From 91f93184af2a9d5d7b287217ca0559c8d057493b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Sun, 9 Nov 2025 13:36:13 -0300 Subject: [PATCH] Update FreeType to 2.14.1. Add SheenBidi dependency (still not in use). Update tests with the new FreeType version. --- .ecode/project_build.json | 2 +- .../assets/fontrendering/eepp-fonts.webp | Bin 75050 -> 75022 bytes .../eepp-text-edit-tab-stop-test.webp | Bin 7358 -> 7278 bytes .../eepp-text-edit-tabs-test.webp | Bin 7264 -> 7180 bytes .../fontrendering/eepp-text-style-bold.webp | Bin 7990 -> 7936 bytes .../fontrendering/eepp-text-style-italic.webp | Bin 9404 -> 9432 bytes .../eepp-text-style-outline.webp | Bin 10242 -> 10122 bytes .../eepp-text-style-regular-center.webp | Bin 7792 -> 7744 bytes .../eepp-text-style-regular-right.webp | Bin 7818 -> 7720 bytes .../eepp-text-style-regular.webp | Bin 7870 -> 7796 bytes .../fontrendering/eepp-text-style-shadow.webp | Bin 8994 -> 8954 bytes .../eepp-text-style-strikethrough-center.webp | Bin 7358 -> 7320 bytes .../eepp-text-style-strikethrough-right.webp | Bin 7446 -> 7368 bytes .../eepp-text-style-strikethrough.webp | Bin 7438 -> 7372 bytes .../eepp-text-style-underline-center.webp | Bin 7834 -> 7760 bytes .../eepp-text-style-underline-right.webp | Bin 7836 -> 7730 bytes .../eepp-text-style-underline.webp | Bin 7888 -> 7754 bytes .../fontrendering/eepp-textedit-bengali.webp | Bin 16776 -> 16802 bytes .../assets/fontrendering/eepp-textedit.webp | Bin 23244 -> 23020 bytes .../assets/fontrendering/eepp-textview.webp | Bin 24540 -> 24420 bytes include/eepp/core/retainsymbol.hpp | 59 + include/eepp/graphics/textshaperun.hpp | 3 + premake4.lua | 16 +- premake5.lua | 50 +- src/eepp/graphics/fonttruetype.cpp | 3 + src/eepp/graphics/textshaperun.cpp | 6 + .../SheenBidi/Headers/SheenBidi/SBAlgorithm.h | 123 + .../SheenBidi/Headers/SheenBidi/SBAllocator.h | 185 + .../SheenBidi/Headers/SheenBidi/SBBase.h | 156 + .../SheenBidi/Headers/SheenBidi/SBBidiType.h | 85 + .../SheenBidi/Headers/SheenBidi/SBCodepoint.h | 184 + .../Headers/SheenBidi/SBCodepointSequence.h | 70 + .../SheenBidi/Headers/SheenBidi/SBConfig.h | 54 + .../Headers/SheenBidi/SBGeneralCategory.h | 110 + .../SheenBidi/Headers/SheenBidi/SBLine.h | 88 + .../Headers/SheenBidi/SBMirrorLocator.h | 108 + .../SheenBidi/Headers/SheenBidi/SBParagraph.h | 105 + .../SheenBidi/Headers/SheenBidi/SBRun.h | 36 + .../SheenBidi/Headers/SheenBidi/SBScript.h | 295 ++ .../Headers/SheenBidi/SBScriptLocator.h | 106 + .../SheenBidi/Headers/SheenBidi/SBVersion.h | 41 + .../SheenBidi/Headers/SheenBidi/SheenBidi.h | 35 + src/thirdparty/SheenBidi/LICENSE | 202 + src/thirdparty/SheenBidi/README.md | 174 + src/thirdparty/SheenBidi/Source/AtomicFlag.h | 94 + .../SheenBidi/Source/AtomicPointer.h | 126 + src/thirdparty/SheenBidi/Source/AtomicUInt.h | 149 + src/thirdparty/SheenBidi/Source/BidiChain.c | 118 + src/thirdparty/SheenBidi/Source/BidiChain.h | 69 + .../SheenBidi/Source/BidiTypeLookup.c | 1088 +++++ .../SheenBidi/Source/BidiTypeLookup.h | 16 + .../SheenBidi/Source/BracketQueue.c | 347 ++ .../SheenBidi/Source/BracketQueue.h | 83 + src/thirdparty/SheenBidi/Source/BracketType.h | 32 + .../SheenBidi/Source/GeneralCategoryLookup.c | 2087 +++++++++ .../SheenBidi/Source/GeneralCategoryLookup.h | 16 + .../SheenBidi/Source/IsolatingRun.c | 524 +++ .../SheenBidi/Source/IsolatingRun.h | 46 + src/thirdparty/SheenBidi/Source/LevelRun.c | 69 + src/thirdparty/SheenBidi/Source/LevelRun.h | 42 + src/thirdparty/SheenBidi/Source/Memory.c | 150 + src/thirdparty/SheenBidi/Source/Memory.h | 107 + src/thirdparty/SheenBidi/Source/Object.c | 71 + src/thirdparty/SheenBidi/Source/Object.h | 119 + src/thirdparty/SheenBidi/Source/Once.c | 38 + src/thirdparty/SheenBidi/Source/Once.h | 39 + .../SheenBidi/Source/PairingLookup.c | 267 ++ .../SheenBidi/Source/PairingLookup.h | 18 + src/thirdparty/SheenBidi/Source/RunExtrema.h | 50 + src/thirdparty/SheenBidi/Source/RunKind.h | 81 + src/thirdparty/SheenBidi/Source/RunQueue.c | 256 ++ src/thirdparty/SheenBidi/Source/RunQueue.h | 58 + src/thirdparty/SheenBidi/Source/SBAlgorithm.c | 141 + src/thirdparty/SheenBidi/Source/SBAlgorithm.h | 36 + src/thirdparty/SheenBidi/Source/SBAllocator.c | 306 ++ src/thirdparty/SheenBidi/Source/SBAllocator.h | 48 + src/thirdparty/SheenBidi/Source/SBAssert.h | 24 + src/thirdparty/SheenBidi/Source/SBBase.c | 834 ++++ src/thirdparty/SheenBidi/Source/SBBase.h | 150 + src/thirdparty/SheenBidi/Source/SBCodepoint.c | 250 ++ src/thirdparty/SheenBidi/Source/SBCodepoint.h | 26 + .../SheenBidi/Source/SBCodepointSequence.c | 174 + .../SheenBidi/Source/SBCodepointSequence.h | 37 + src/thirdparty/SheenBidi/Source/SBLine.c | 321 ++ src/thirdparty/SheenBidi/Source/SBLine.h | 41 + src/thirdparty/SheenBidi/Source/SBLog.c | 305 ++ src/thirdparty/SheenBidi/Source/SBLog.h | 152 + .../SheenBidi/Source/SBMirrorLocator.c | 128 + .../SheenBidi/Source/SBMirrorLocator.h | 34 + src/thirdparty/SheenBidi/Source/SBParagraph.c | 740 ++++ src/thirdparty/SheenBidi/Source/SBParagraph.h | 45 + .../SheenBidi/Source/SBScriptLocator.c | 174 + .../SheenBidi/Source/SBScriptLocator.h | 33 + .../SheenBidi/Source/ScriptLookup.c | 2374 ++++++++++ .../SheenBidi/Source/ScriptLookup.h | 16 + src/thirdparty/SheenBidi/Source/ScriptStack.c | 84 + src/thirdparty/SheenBidi/Source/ScriptStack.h | 50 + src/thirdparty/SheenBidi/Source/SheenBidi.c | 47 + src/thirdparty/SheenBidi/Source/StatusStack.c | 149 + src/thirdparty/SheenBidi/Source/StatusStack.h | 62 + src/thirdparty/SheenBidi/Source/ThreadFence.h | 50 + .../SheenBidi/Source/ThreadLocalStorage.h | 109 + src/thirdparty/freetype2/FTL.TXT | 169 - src/thirdparty/freetype2/LICENSE.TXT | 58 +- src/thirdparty/freetype2/include/dlg/dlg.h | 290 ++ src/thirdparty/freetype2/include/dlg/output.h | 172 + .../include/freetype/config/ftconfig.h | 532 +-- .../include/freetype/config/ftheader.h | 76 +- .../include/freetype/config/ftmodule.h | 9 +- .../include/freetype/config/ftoption.h | 241 +- .../include/freetype/config/ftstdlib.h | 28 +- .../include/freetype/config/integer-types.h | 277 ++ .../include/freetype/config/mac-support.h | 49 + .../include/freetype/config/public-macros.h | 138 + .../freetype2/include/freetype/freetype.h | 1586 ++++--- .../freetype2/include/freetype/ftadvanc.h | 6 +- .../freetype2/include/freetype/ftbbox.h | 5 +- .../freetype2/include/freetype/ftbdf.h | 5 +- .../freetype2/include/freetype/ftbitmap.h | 7 +- .../freetype2/include/freetype/ftbzip2.h | 24 +- .../freetype2/include/freetype/ftcache.h | 81 +- .../freetype2/include/freetype/ftchapters.h | 27 +- .../freetype2/include/freetype/ftcid.h | 5 +- .../freetype2/include/freetype/ftcolor.h | 1383 +++++- .../freetype2/include/freetype/ftdriver.h | 244 +- .../freetype2/include/freetype/fterrdef.h | 6 +- .../freetype2/include/freetype/fterrors.h | 27 +- .../freetype2/include/freetype/ftfntfmt.h | 5 +- .../freetype2/include/freetype/ftgasp.h | 5 +- .../freetype2/include/freetype/ftglyph.h | 129 +- .../freetype2/include/freetype/ftgxval.h | 5 +- .../freetype2/include/freetype/ftgzip.h | 24 +- .../freetype2/include/freetype/ftimage.h | 197 +- .../freetype2/include/freetype/ftincrem.h | 22 +- .../freetype2/include/freetype/ftlcdfil.h | 59 +- .../freetype2/include/freetype/ftlist.h | 5 +- .../freetype2/include/freetype/ftlogging.h | 184 + .../freetype2/include/freetype/ftlzw.h | 24 +- .../freetype2/include/freetype/ftmac.h | 3 +- .../freetype2/include/freetype/ftmm.h | 317 +- .../freetype2/include/freetype/ftmodapi.h | 40 +- .../freetype2/include/freetype/ftmoderr.h | 5 +- .../freetype2/include/freetype/ftotval.h | 5 +- .../freetype2/include/freetype/ftoutln.h | 35 +- .../freetype2/include/freetype/ftparams.h | 20 +- .../freetype2/include/freetype/ftpfr.h | 7 +- .../freetype2/include/freetype/ftrender.h | 9 +- .../freetype2/include/freetype/ftsizes.h | 5 +- .../freetype2/include/freetype/ftsnames.h | 7 +- .../freetype2/include/freetype/ftstroke.h | 43 +- .../freetype2/include/freetype/ftsynth.h | 28 +- .../freetype2/include/freetype/ftsystem.h | 13 +- .../freetype2/include/freetype/fttrigon.h | 4 +- .../freetype2/include/freetype/fttypes.h | 28 +- .../freetype2/include/freetype/ftwinfnt.h | 10 +- .../include/freetype/internal/autohint.h | 8 +- .../include/freetype/internal/cffotypes.h | 13 +- .../include/freetype/internal/cfftypes.h | 25 +- .../freetype/internal/compiler-macros.h | 343 ++ .../include/freetype/internal/ftcalc.h | 346 +- .../include/freetype/internal/ftdebug.h | 179 +- .../include/freetype/internal/ftdrv.h | 7 +- .../include/freetype/internal/ftgloadr.h | 8 +- .../include/freetype/internal/fthash.h | 26 +- .../include/freetype/internal/ftmemory.h | 53 +- .../include/freetype/internal/ftmmtypes.h | 91 + .../include/freetype/internal/ftobjs.h | 72 +- .../include/freetype/internal/ftpsprop.h | 5 +- .../include/freetype/internal/ftrfork.h | 5 +- .../include/freetype/internal/ftserv.h | 30 +- .../include/freetype/internal/ftstream.h | 140 +- .../include/freetype/internal/fttrace.h | 31 +- .../include/freetype/internal/ftvalid.h | 5 +- .../include/freetype/internal/internal.h | 67 - .../include/freetype/internal/psaux.h | 40 +- .../include/freetype/internal/pshints.h | 11 +- .../freetype/internal/services/svbdf.h | 6 +- .../freetype/internal/services/svcfftl.h | 6 +- .../freetype/internal/services/svcid.h | 4 +- .../freetype/internal/services/svfntfmt.h | 4 +- .../freetype/internal/services/svgldict.h | 4 +- .../freetype/internal/services/svgxval.h | 6 +- .../freetype/internal/services/svkern.h | 6 +- .../freetype/internal/services/svmetric.h | 14 +- .../include/freetype/internal/services/svmm.h | 160 +- .../freetype/internal/services/svotval.h | 6 +- .../freetype/internal/services/svpfr.h | 7 +- .../freetype/internal/services/svpostnm.h | 4 +- .../freetype/internal/services/svprop.h | 2 +- .../freetype/internal/services/svpscmap.h | 6 +- .../freetype/internal/services/svpsinfo.h | 6 +- .../freetype/internal/services/svsfnt.h | 6 +- .../freetype/internal/services/svttcmap.h | 6 +- .../freetype/internal/services/svtteng.h | 6 +- .../freetype/internal/services/svttglyf.h | 6 +- .../freetype/internal/services/svwinfnt.h | 6 +- .../include/freetype/internal/sfnt.h | 311 +- .../include/freetype/internal/svginterface.h | 46 + .../include/freetype/internal/t1types.h | 91 +- .../include/freetype/internal/tttypes.h | 203 +- .../include/freetype/internal/wofftypes.h | 210 +- .../freetype2/include/freetype/otsvg.h | 336 ++ .../freetype2/include/freetype/t1tables.h | 237 +- .../freetype2/include/freetype/ttnameid.h | 261 +- .../freetype2/include/freetype/tttables.h | 25 +- .../freetype2/include/freetype/tttags.h | 7 +- src/thirdparty/freetype2/include/ft2build.h | 10 +- .../freetype2/src/autofit/afadjust.c | 1612 +++++++ .../freetype2/src/autofit/afadjust.h | 130 + .../freetype2/src/autofit/afangles.c | 285 -- .../freetype2/src/autofit/afangles.h | 7 - src/thirdparty/freetype2/src/autofit/afblue.c | 227 +- .../freetype2/src/autofit/afblue.cin | 2 +- .../freetype2/src/autofit/afblue.dat | 243 +- src/thirdparty/freetype2/src/autofit/afblue.h | 173 +- .../freetype2/src/autofit/afblue.hin | 11 +- src/thirdparty/freetype2/src/autofit/afcjk.c | 222 +- src/thirdparty/freetype2/src/autofit/afcjk.h | 24 +- .../freetype2/src/autofit/afcover.h | 2 +- .../freetype2/src/autofit/afdummy.c | 2 +- .../freetype2/src/autofit/afdummy.h | 2 +- .../freetype2/src/autofit/aferrors.h | 6 +- .../freetype2/src/autofit/afglobal.c | 112 +- .../freetype2/src/autofit/afglobal.h | 21 +- src/thirdparty/freetype2/src/autofit/afgsub.c | 693 +++ src/thirdparty/freetype2/src/autofit/afgsub.h | 38 + .../freetype2/src/autofit/afhints.c | 295 +- .../freetype2/src/autofit/afhints.h | 53 +- .../freetype2/src/autofit/afindic.c | 42 +- .../freetype2/src/autofit/afindic.h | 2 +- .../freetype2/src/autofit/aflatin.c | 1870 +++++++- .../freetype2/src/autofit/aflatin.h | 31 +- .../freetype2/src/autofit/afloader.c | 50 +- .../freetype2/src/autofit/afloader.h | 4 +- .../freetype2/src/autofit/afmodule.c | 155 +- .../freetype2/src/autofit/afmodule.h | 19 +- .../freetype2/src/autofit/afranges.c | 87 +- .../freetype2/src/autofit/afranges.h | 2 +- .../freetype2/src/autofit/afscript.h | 14 +- .../freetype2/src/autofit/afshaper.c | 390 +- .../freetype2/src/autofit/afshaper.h | 26 +- .../freetype2/src/autofit/afstyles.h | 81 +- .../freetype2/src/autofit/aftypes.h | 100 +- src/thirdparty/freetype2/src/autofit/afwarp.c | 373 -- src/thirdparty/freetype2/src/autofit/afwarp.h | 66 - .../freetype2/src/autofit/afwrtsys.h | 52 - .../freetype2/src/autofit/afws-decl.h | 33 + .../freetype2/src/autofit/afws-iter.h | 31 + .../freetype2/src/autofit/ft-hb-decls.h | 203 + .../freetype2/src/autofit/ft-hb-ft.c | 117 + .../freetype2/src/autofit/ft-hb-ft.h | 46 + .../freetype2/src/autofit/ft-hb-types.h | 129 + src/thirdparty/freetype2/src/autofit/ft-hb.c | 197 + src/thirdparty/freetype2/src/autofit/ft-hb.h | 82 + .../freetype2/src/autofit/hb-script-list.h | 484 ++ src/thirdparty/freetype2/src/base/ftadvanc.c | 15 +- src/thirdparty/freetype2/src/base/ftbase.h | 12 +- src/thirdparty/freetype2/src/base/ftbbox.c | 67 +- src/thirdparty/freetype2/src/base/ftbdf.c | 9 +- src/thirdparty/freetype2/src/base/ftbitmap.c | 127 +- src/thirdparty/freetype2/src/base/ftcalc.c | 345 +- src/thirdparty/freetype2/src/base/ftcid.c | 9 +- src/thirdparty/freetype2/src/base/ftcolor.c | 30 +- src/thirdparty/freetype2/src/base/ftdbgmem.c | 163 +- src/thirdparty/freetype2/src/base/ftdebug.c | 341 +- src/thirdparty/freetype2/src/base/fterrors.c | 9 +- src/thirdparty/freetype2/src/base/ftfntfmt.c | 9 +- src/thirdparty/freetype2/src/base/ftfstype.c | 11 +- src/thirdparty/freetype2/src/base/ftgasp.c | 7 +- src/thirdparty/freetype2/src/base/ftgloadr.c | 95 +- src/thirdparty/freetype2/src/base/ftglyph.c | 287 +- src/thirdparty/freetype2/src/base/ftgxval.c | 9 +- src/thirdparty/freetype2/src/base/fthash.c | 111 +- src/thirdparty/freetype2/src/base/ftinit.c | 16 +- src/thirdparty/freetype2/src/base/ftlcdfil.c | 19 +- src/thirdparty/freetype2/src/base/ftmac.c | 43 +- src/thirdparty/freetype2/src/base/ftmm.c | 174 +- src/thirdparty/freetype2/src/base/ftobjs.c | 849 ++-- src/thirdparty/freetype2/src/base/ftotval.c | 11 +- src/thirdparty/freetype2/src/base/ftoutln.c | 132 +- src/thirdparty/freetype2/src/base/ftpatent.c | 15 +- src/thirdparty/freetype2/src/base/ftpfr.c | 9 +- src/thirdparty/freetype2/src/base/ftpsprop.c | 21 +- src/thirdparty/freetype2/src/base/ftrfork.c | 75 +- src/thirdparty/freetype2/src/base/ftsnames.c | 15 +- src/thirdparty/freetype2/src/base/ftstream.c | 146 +- src/thirdparty/freetype2/src/base/ftstroke.c | 326 +- src/thirdparty/freetype2/src/base/ftsynth.c | 57 +- src/thirdparty/freetype2/src/base/ftsystem.c | 23 +- src/thirdparty/freetype2/src/base/fttrigon.c | 15 +- src/thirdparty/freetype2/src/base/fttype1.c | 11 +- src/thirdparty/freetype2/src/base/ftutil.c | 11 +- src/thirdparty/freetype2/src/base/ftver.rc | 12 +- src/thirdparty/freetype2/src/base/ftwinfnt.c | 11 +- src/thirdparty/freetype2/src/bdf/README | 6 +- src/thirdparty/freetype2/src/bdf/bdf.h | 56 +- src/thirdparty/freetype2/src/bdf/bdfdrivr.c | 263 +- src/thirdparty/freetype2/src/bdf/bdfdrivr.h | 3 +- src/thirdparty/freetype2/src/bdf/bdferror.h | 4 +- src/thirdparty/freetype2/src/bdf/bdflib.c | 1833 +++----- src/thirdparty/freetype2/src/bzip2/ftbzip2.c | 88 +- src/thirdparty/freetype2/src/cache/ftcbasic.c | 154 +- src/thirdparty/freetype2/src/cache/ftccache.c | 187 +- src/thirdparty/freetype2/src/cache/ftccache.h | 29 +- src/thirdparty/freetype2/src/cache/ftccback.h | 17 +- src/thirdparty/freetype2/src/cache/ftccmap.c | 40 +- src/thirdparty/freetype2/src/cache/ftcerror.h | 6 +- src/thirdparty/freetype2/src/cache/ftcglyph.c | 59 +- src/thirdparty/freetype2/src/cache/ftcglyph.h | 25 +- src/thirdparty/freetype2/src/cache/ftcimage.c | 24 +- src/thirdparty/freetype2/src/cache/ftcimage.h | 11 +- src/thirdparty/freetype2/src/cache/ftcmanag.c | 133 +- src/thirdparty/freetype2/src/cache/ftcmanag.h | 5 +- src/thirdparty/freetype2/src/cache/ftcmru.c | 106 +- src/thirdparty/freetype2/src/cache/ftcmru.h | 12 +- src/thirdparty/freetype2/src/cache/ftcsbits.c | 72 +- src/thirdparty/freetype2/src/cache/ftcsbits.h | 18 +- src/thirdparty/freetype2/src/cff/cffcmap.c | 112 +- src/thirdparty/freetype2/src/cff/cffcmap.h | 8 +- src/thirdparty/freetype2/src/cff/cffdrivr.c | 662 +-- src/thirdparty/freetype2/src/cff/cffdrivr.h | 5 +- src/thirdparty/freetype2/src/cff/cfferrs.h | 6 +- src/thirdparty/freetype2/src/cff/cffgload.c | 193 +- src/thirdparty/freetype2/src/cff/cffgload.h | 7 +- src/thirdparty/freetype2/src/cff/cffload.c | 287 +- src/thirdparty/freetype2/src/cff/cffload.h | 11 +- src/thirdparty/freetype2/src/cff/cffobjs.c | 269 +- src/thirdparty/freetype2/src/cff/cffobjs.h | 3 +- src/thirdparty/freetype2/src/cff/cffparse.c | 388 +- src/thirdparty/freetype2/src/cff/cffparse.h | 21 +- src/thirdparty/freetype2/src/cff/cfftoken.h | 74 +- src/thirdparty/freetype2/src/cid/ciderrs.h | 6 +- src/thirdparty/freetype2/src/cid/cidgload.c | 208 +- src/thirdparty/freetype2/src/cid/cidgload.h | 11 +- src/thirdparty/freetype2/src/cid/cidload.c | 226 +- src/thirdparty/freetype2/src/cid/cidload.h | 7 +- src/thirdparty/freetype2/src/cid/cidobjs.c | 49 +- src/thirdparty/freetype2/src/cid/cidobjs.h | 6 +- src/thirdparty/freetype2/src/cid/cidparse.c | 100 +- src/thirdparty/freetype2/src/cid/cidparse.h | 11 +- src/thirdparty/freetype2/src/cid/cidriver.c | 114 +- src/thirdparty/freetype2/src/cid/cidriver.h | 5 +- src/thirdparty/freetype2/src/cid/cidtoken.h | 2 +- src/thirdparty/freetype2/src/dlg/dlg.c | 803 ++++ src/thirdparty/freetype2/src/gxvalid/README | 2 +- .../freetype2/src/gxvalid/gxvalid.h | 11 +- .../freetype2/src/gxvalid/gxvbsln.c | 2 +- .../freetype2/src/gxvalid/gxvcommn.c | 63 +- .../freetype2/src/gxvalid/gxvcommn.h | 45 +- .../freetype2/src/gxvalid/gxverror.h | 6 +- .../freetype2/src/gxvalid/gxvfeat.c | 6 +- .../freetype2/src/gxvalid/gxvfeat.h | 2 +- .../freetype2/src/gxvalid/gxvjust.c | 30 +- .../freetype2/src/gxvalid/gxvkern.c | 18 +- .../freetype2/src/gxvalid/gxvlcar.c | 2 +- src/thirdparty/freetype2/src/gxvalid/gxvmod.c | 59 +- src/thirdparty/freetype2/src/gxvalid/gxvmod.h | 5 +- .../freetype2/src/gxvalid/gxvmort.c | 6 +- .../freetype2/src/gxvalid/gxvmort.h | 9 +- .../freetype2/src/gxvalid/gxvmort0.c | 2 +- .../freetype2/src/gxvalid/gxvmort1.c | 2 +- .../freetype2/src/gxvalid/gxvmort2.c | 14 +- .../freetype2/src/gxvalid/gxvmort4.c | 2 +- .../freetype2/src/gxvalid/gxvmort5.c | 4 +- .../freetype2/src/gxvalid/gxvmorx.c | 8 +- .../freetype2/src/gxvalid/gxvmorx.h | 9 +- .../freetype2/src/gxvalid/gxvmorx0.c | 2 +- .../freetype2/src/gxvalid/gxvmorx1.c | 2 +- .../freetype2/src/gxvalid/gxvmorx2.c | 30 +- .../freetype2/src/gxvalid/gxvmorx4.c | 2 +- .../freetype2/src/gxvalid/gxvmorx5.c | 2 +- .../freetype2/src/gxvalid/gxvopbd.c | 4 +- .../freetype2/src/gxvalid/gxvprop.c | 6 +- .../freetype2/src/gxvalid/gxvtrak.c | 8 +- src/thirdparty/freetype2/src/gzip/ftgzip.c | 115 +- src/thirdparty/freetype2/src/lzw/ftlzw.c | 21 +- .../src/lzw/{ftzopen.c => ftzopen.ctpl} | 19 +- src/thirdparty/freetype2/src/lzw/ftzopen.h | 8 +- .../freetype2/src/otvalid/otvalid.h | 11 +- .../freetype2/src/otvalid/otvbase.c | 14 +- .../freetype2/src/otvalid/otvcommn.c | 69 +- .../freetype2/src/otvalid/otvcommn.h | 43 +- .../freetype2/src/otvalid/otverror.h | 6 +- .../freetype2/src/otvalid/otvgdef.c | 8 +- .../freetype2/src/otvalid/otvgpos.c | 38 +- .../freetype2/src/otvalid/otvgpos.h | 2 +- .../freetype2/src/otvalid/otvgsub.c | 48 +- .../freetype2/src/otvalid/otvjstf.c | 6 +- .../freetype2/src/otvalid/otvmath.c | 4 +- src/thirdparty/freetype2/src/otvalid/otvmod.c | 17 +- src/thirdparty/freetype2/src/otvalid/otvmod.h | 5 +- src/thirdparty/freetype2/src/pcf/pcf.h | 5 +- src/thirdparty/freetype2/src/pcf/pcfdrivr.c | 234 +- src/thirdparty/freetype2/src/pcf/pcfdrivr.h | 3 +- src/thirdparty/freetype2/src/pcf/pcferror.h | 4 +- src/thirdparty/freetype2/src/pcf/pcfread.c | 151 +- src/thirdparty/freetype2/src/pcf/pcfread.h | 1 - src/thirdparty/freetype2/src/pcf/pcfutil.c | 53 +- src/thirdparty/freetype2/src/pcf/pcfutil.h | 2 +- src/thirdparty/freetype2/src/pfr/pfrcmap.c | 71 +- src/thirdparty/freetype2/src/pfr/pfrcmap.h | 5 +- src/thirdparty/freetype2/src/pfr/pfrdrivr.c | 37 +- src/thirdparty/freetype2/src/pfr/pfrdrivr.h | 5 +- src/thirdparty/freetype2/src/pfr/pfrerror.h | 6 +- src/thirdparty/freetype2/src/pfr/pfrgload.c | 38 +- src/thirdparty/freetype2/src/pfr/pfrgload.h | 2 +- src/thirdparty/freetype2/src/pfr/pfrload.c | 103 +- src/thirdparty/freetype2/src/pfr/pfrload.h | 4 +- src/thirdparty/freetype2/src/pfr/pfrobjs.c | 63 +- src/thirdparty/freetype2/src/pfr/pfrobjs.h | 2 +- src/thirdparty/freetype2/src/pfr/pfrsbit.c | 35 +- src/thirdparty/freetype2/src/pfr/pfrsbit.h | 2 +- src/thirdparty/freetype2/src/pfr/pfrtypes.h | 7 +- src/thirdparty/freetype2/src/psaux/afmparse.c | 143 +- src/thirdparty/freetype2/src/psaux/afmparse.h | 5 +- .../freetype2/src/psaux/cffdecode.c | 67 +- .../freetype2/src/psaux/cffdecode.h | 5 +- src/thirdparty/freetype2/src/psaux/psarrst.c | 9 +- src/thirdparty/freetype2/src/psaux/psarrst.h | 1 - src/thirdparty/freetype2/src/psaux/psauxerr.h | 6 +- src/thirdparty/freetype2/src/psaux/psauxmod.c | 11 +- src/thirdparty/freetype2/src/psaux/psauxmod.h | 20 +- src/thirdparty/freetype2/src/psaux/psblues.c | 53 +- src/thirdparty/freetype2/src/psaux/psconv.c | 15 +- src/thirdparty/freetype2/src/psaux/psconv.h | 5 +- src/thirdparty/freetype2/src/psaux/pserror.h | 5 +- src/thirdparty/freetype2/src/psaux/psfixed.h | 6 +- src/thirdparty/freetype2/src/psaux/psfont.c | 3 +- src/thirdparty/freetype2/src/psaux/psfont.h | 2 +- src/thirdparty/freetype2/src/psaux/psft.c | 42 +- src/thirdparty/freetype2/src/psaux/psft.h | 14 +- src/thirdparty/freetype2/src/psaux/psglue.h | 2 +- src/thirdparty/freetype2/src/psaux/pshints.c | 72 +- src/thirdparty/freetype2/src/psaux/psintrp.c | 124 +- src/thirdparty/freetype2/src/psaux/psintrp.h | 2 +- src/thirdparty/freetype2/src/psaux/psobjs.c | 172 +- src/thirdparty/freetype2/src/psaux/psobjs.h | 7 +- src/thirdparty/freetype2/src/psaux/psread.c | 2 +- src/thirdparty/freetype2/src/psaux/psstack.c | 18 +- src/thirdparty/freetype2/src/psaux/psstack.h | 5 +- src/thirdparty/freetype2/src/psaux/pstypes.h | 3 +- src/thirdparty/freetype2/src/psaux/t1cmap.c | 145 +- src/thirdparty/freetype2/src/psaux/t1cmap.h | 7 +- src/thirdparty/freetype2/src/psaux/t1decode.c | 248 +- src/thirdparty/freetype2/src/psaux/t1decode.h | 7 +- .../freetype2/src/pshinter/pshalgo.c | 158 +- .../freetype2/src/pshinter/pshalgo.h | 32 +- .../freetype2/src/pshinter/pshglob.c | 11 +- .../freetype2/src/pshinter/pshglob.h | 6 +- .../freetype2/src/pshinter/pshmod.c | 15 +- .../freetype2/src/pshinter/pshmod.h | 5 +- .../freetype2/src/pshinter/pshnterr.h | 6 +- .../freetype2/src/pshinter/pshrec.c | 212 +- .../freetype2/src/pshinter/pshrec.h | 5 +- .../freetype2/src/psnames/psmodule.c | 122 +- .../freetype2/src/psnames/psmodule.h | 5 +- .../freetype2/src/psnames/psnamerr.h | 6 +- .../freetype2/src/psnames/pstables.h | 2 +- src/thirdparty/freetype2/src/raster/ftmisc.h | 30 +- .../freetype2/src/raster/ftraster.c | 2222 ++++------ .../freetype2/src/raster/ftraster.h | 5 +- src/thirdparty/freetype2/src/raster/ftrend1.c | 30 +- src/thirdparty/freetype2/src/raster/ftrend1.h | 5 +- .../freetype2/src/raster/rasterrs.h | 6 +- src/thirdparty/freetype2/src/sdf/ftbsdf.c | 1362 ++++++ src/thirdparty/freetype2/src/sdf/ftsdf.c | 3932 +++++++++++++++++ src/thirdparty/freetype2/src/sdf/ftsdf.h | 97 + .../freetype2/src/sdf/ftsdfcommon.c | 104 + .../freetype2/src/sdf/ftsdfcommon.h | 140 + src/thirdparty/freetype2/src/sdf/ftsdferrs.h | 37 + src/thirdparty/freetype2/src/sdf/ftsdfrend.c | 603 +++ src/thirdparty/freetype2/src/sdf/ftsdfrend.h | 118 + src/thirdparty/freetype2/src/sfnt/pngshim.c | 54 +- src/thirdparty/freetype2/src/sfnt/pngshim.h | 3 +- src/thirdparty/freetype2/src/sfnt/sfdriver.c | 289 +- src/thirdparty/freetype2/src/sfnt/sfdriver.h | 5 +- src/thirdparty/freetype2/src/sfnt/sferrors.h | 6 +- src/thirdparty/freetype2/src/sfnt/sfobjs.c | 237 +- src/thirdparty/freetype2/src/sfnt/sfobjs.h | 7 +- src/thirdparty/freetype2/src/sfnt/sfwoff.c | 78 +- src/thirdparty/freetype2/src/sfnt/sfwoff.h | 10 +- src/thirdparty/freetype2/src/sfnt/sfwoff2.c | 2380 ++++++++++ src/thirdparty/freetype2/src/sfnt/sfwoff2.h | 78 + src/thirdparty/freetype2/src/sfnt/ttbdf.c | 22 +- src/thirdparty/freetype2/src/sfnt/ttbdf.h | 7 +- src/thirdparty/freetype2/src/sfnt/ttcmap.c | 620 +-- src/thirdparty/freetype2/src/sfnt/ttcmap.h | 14 +- src/thirdparty/freetype2/src/sfnt/ttcmapc.h | 2 +- src/thirdparty/freetype2/src/sfnt/ttcolr.c | 1530 ++++++- src/thirdparty/freetype2/src/sfnt/ttcolr.h | 29 +- src/thirdparty/freetype2/src/sfnt/ttcpal.c | 25 +- src/thirdparty/freetype2/src/sfnt/ttcpal.h | 3 +- src/thirdparty/freetype2/src/sfnt/ttgpos.c | 982 ++++ src/thirdparty/freetype2/src/sfnt/ttgpos.h | 52 + src/thirdparty/freetype2/src/sfnt/ttkern.c | 31 +- src/thirdparty/freetype2/src/sfnt/ttkern.h | 13 +- src/thirdparty/freetype2/src/sfnt/ttload.c | 180 +- src/thirdparty/freetype2/src/sfnt/ttload.h | 7 +- src/thirdparty/freetype2/src/sfnt/ttmtx.c | 15 +- src/thirdparty/freetype2/src/sfnt/ttmtx.h | 7 +- src/thirdparty/freetype2/src/sfnt/ttpost.c | 350 +- src/thirdparty/freetype2/src/sfnt/ttpost.h | 4 +- src/thirdparty/freetype2/src/sfnt/ttsbit.c | 152 +- src/thirdparty/freetype2/src/sfnt/ttsbit.h | 3 +- src/thirdparty/freetype2/src/sfnt/ttsvg.c | 423 ++ src/thirdparty/freetype2/src/sfnt/ttsvg.h | 43 + src/thirdparty/freetype2/src/sfnt/woff2tags.c | 119 + src/thirdparty/freetype2/src/sfnt/woff2tags.h | 41 + src/thirdparty/freetype2/src/smooth/ftgrays.c | 989 +++-- src/thirdparty/freetype2/src/smooth/ftgrays.h | 15 +- .../freetype2/src/smooth/ftsmerrs.h | 6 +- .../freetype2/src/smooth/ftsmooth.c | 722 +-- .../freetype2/src/smooth/ftsmooth.h | 9 +- src/thirdparty/freetype2/src/svg/ftsvg.c | 355 ++ src/thirdparty/freetype2/src/svg/ftsvg.h | 35 + src/thirdparty/freetype2/src/svg/svgtypes.h | 42 + .../freetype2/src/truetype/ttdriver.c | 194 +- .../freetype2/src/truetype/ttdriver.h | 5 +- .../freetype2/src/truetype/tterrors.h | 6 +- .../freetype2/src/truetype/ttgload.c | 1458 +++--- .../freetype2/src/truetype/ttgload.h | 3 +- .../freetype2/src/truetype/ttgxvar.c | 2324 ++++++---- .../freetype2/src/truetype/ttgxvar.h | 136 +- .../freetype2/src/truetype/ttinterp.c | 2768 ++++-------- .../freetype2/src/truetype/ttinterp.h | 296 +- .../freetype2/src/truetype/ttobjs.c | 640 ++- .../freetype2/src/truetype/ttobjs.h | 142 +- .../freetype2/src/truetype/ttpload.c | 179 +- .../freetype2/src/truetype/ttpload.h | 11 +- .../freetype2/src/truetype/ttsubpix.c | 1014 ----- .../freetype2/src/truetype/ttsubpix.h | 111 - src/thirdparty/freetype2/src/type1/t1afm.c | 36 +- src/thirdparty/freetype2/src/type1/t1afm.h | 5 +- src/thirdparty/freetype2/src/type1/t1driver.c | 117 +- src/thirdparty/freetype2/src/type1/t1driver.h | 5 +- src/thirdparty/freetype2/src/type1/t1errors.h | 6 +- src/thirdparty/freetype2/src/type1/t1gload.c | 63 +- src/thirdparty/freetype2/src/type1/t1gload.h | 3 +- src/thirdparty/freetype2/src/type1/t1load.c | 454 +- src/thirdparty/freetype2/src/type1/t1load.h | 31 +- src/thirdparty/freetype2/src/type1/t1objs.c | 47 +- src/thirdparty/freetype2/src/type1/t1objs.h | 6 +- src/thirdparty/freetype2/src/type1/t1parse.c | 72 +- src/thirdparty/freetype2/src/type1/t1parse.h | 7 +- src/thirdparty/freetype2/src/type1/t1tokens.h | 2 +- .../freetype2/src/type42/t42drivr.c | 68 +- .../freetype2/src/type42/t42drivr.h | 5 +- .../freetype2/src/type42/t42error.h | 6 +- src/thirdparty/freetype2/src/type42/t42objs.c | 44 +- src/thirdparty/freetype2/src/type42/t42objs.h | 17 +- .../freetype2/src/type42/t42parse.c | 188 +- .../freetype2/src/type42/t42parse.h | 4 +- .../freetype2/src/type42/t42types.h | 11 +- .../freetype2/src/winfonts/fnterrs.h | 6 +- .../freetype2/src/winfonts/winfnt.c | 109 +- .../freetype2/src/winfonts/winfnt.h | 7 +- src/thirdparty/harfbuzz/config.h | 1 + 557 files changed, 56711 insertions(+), 20852 deletions(-) create mode 100644 include/eepp/core/retainsymbol.hpp create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBAlgorithm.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBAllocator.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBBase.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBBidiType.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepoint.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepointSequence.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBConfig.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBGeneralCategory.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBLine.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBMirrorLocator.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBParagraph.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBRun.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBScript.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBScriptLocator.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SBVersion.h create mode 100644 src/thirdparty/SheenBidi/Headers/SheenBidi/SheenBidi.h create mode 100755 src/thirdparty/SheenBidi/LICENSE create mode 100644 src/thirdparty/SheenBidi/README.md create mode 100644 src/thirdparty/SheenBidi/Source/AtomicFlag.h create mode 100644 src/thirdparty/SheenBidi/Source/AtomicPointer.h create mode 100644 src/thirdparty/SheenBidi/Source/AtomicUInt.h create mode 100644 src/thirdparty/SheenBidi/Source/BidiChain.c create mode 100644 src/thirdparty/SheenBidi/Source/BidiChain.h create mode 100644 src/thirdparty/SheenBidi/Source/BidiTypeLookup.c create mode 100644 src/thirdparty/SheenBidi/Source/BidiTypeLookup.h create mode 100644 src/thirdparty/SheenBidi/Source/BracketQueue.c create mode 100644 src/thirdparty/SheenBidi/Source/BracketQueue.h create mode 100644 src/thirdparty/SheenBidi/Source/BracketType.h create mode 100644 src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.c create mode 100644 src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.h create mode 100644 src/thirdparty/SheenBidi/Source/IsolatingRun.c create mode 100644 src/thirdparty/SheenBidi/Source/IsolatingRun.h create mode 100644 src/thirdparty/SheenBidi/Source/LevelRun.c create mode 100644 src/thirdparty/SheenBidi/Source/LevelRun.h create mode 100644 src/thirdparty/SheenBidi/Source/Memory.c create mode 100644 src/thirdparty/SheenBidi/Source/Memory.h create mode 100644 src/thirdparty/SheenBidi/Source/Object.c create mode 100644 src/thirdparty/SheenBidi/Source/Object.h create mode 100644 src/thirdparty/SheenBidi/Source/Once.c create mode 100644 src/thirdparty/SheenBidi/Source/Once.h create mode 100644 src/thirdparty/SheenBidi/Source/PairingLookup.c create mode 100644 src/thirdparty/SheenBidi/Source/PairingLookup.h create mode 100644 src/thirdparty/SheenBidi/Source/RunExtrema.h create mode 100644 src/thirdparty/SheenBidi/Source/RunKind.h create mode 100644 src/thirdparty/SheenBidi/Source/RunQueue.c create mode 100644 src/thirdparty/SheenBidi/Source/RunQueue.h create mode 100644 src/thirdparty/SheenBidi/Source/SBAlgorithm.c create mode 100644 src/thirdparty/SheenBidi/Source/SBAlgorithm.h create mode 100644 src/thirdparty/SheenBidi/Source/SBAllocator.c create mode 100644 src/thirdparty/SheenBidi/Source/SBAllocator.h create mode 100644 src/thirdparty/SheenBidi/Source/SBAssert.h create mode 100644 src/thirdparty/SheenBidi/Source/SBBase.c create mode 100644 src/thirdparty/SheenBidi/Source/SBBase.h create mode 100644 src/thirdparty/SheenBidi/Source/SBCodepoint.c create mode 100644 src/thirdparty/SheenBidi/Source/SBCodepoint.h create mode 100644 src/thirdparty/SheenBidi/Source/SBCodepointSequence.c create mode 100644 src/thirdparty/SheenBidi/Source/SBCodepointSequence.h create mode 100644 src/thirdparty/SheenBidi/Source/SBLine.c create mode 100644 src/thirdparty/SheenBidi/Source/SBLine.h create mode 100644 src/thirdparty/SheenBidi/Source/SBLog.c create mode 100644 src/thirdparty/SheenBidi/Source/SBLog.h create mode 100644 src/thirdparty/SheenBidi/Source/SBMirrorLocator.c create mode 100644 src/thirdparty/SheenBidi/Source/SBMirrorLocator.h create mode 100644 src/thirdparty/SheenBidi/Source/SBParagraph.c create mode 100644 src/thirdparty/SheenBidi/Source/SBParagraph.h create mode 100644 src/thirdparty/SheenBidi/Source/SBScriptLocator.c create mode 100644 src/thirdparty/SheenBidi/Source/SBScriptLocator.h create mode 100644 src/thirdparty/SheenBidi/Source/ScriptLookup.c create mode 100644 src/thirdparty/SheenBidi/Source/ScriptLookup.h create mode 100644 src/thirdparty/SheenBidi/Source/ScriptStack.c create mode 100644 src/thirdparty/SheenBidi/Source/ScriptStack.h create mode 100644 src/thirdparty/SheenBidi/Source/SheenBidi.c create mode 100644 src/thirdparty/SheenBidi/Source/StatusStack.c create mode 100644 src/thirdparty/SheenBidi/Source/StatusStack.h create mode 100644 src/thirdparty/SheenBidi/Source/ThreadFence.h create mode 100644 src/thirdparty/SheenBidi/Source/ThreadLocalStorage.h delete mode 100644 src/thirdparty/freetype2/FTL.TXT create mode 100644 src/thirdparty/freetype2/include/dlg/dlg.h create mode 100644 src/thirdparty/freetype2/include/dlg/output.h create mode 100644 src/thirdparty/freetype2/include/freetype/config/integer-types.h create mode 100644 src/thirdparty/freetype2/include/freetype/config/mac-support.h create mode 100644 src/thirdparty/freetype2/include/freetype/config/public-macros.h create mode 100644 src/thirdparty/freetype2/include/freetype/ftlogging.h create mode 100644 src/thirdparty/freetype2/include/freetype/internal/compiler-macros.h create mode 100644 src/thirdparty/freetype2/include/freetype/internal/ftmmtypes.h delete mode 100644 src/thirdparty/freetype2/include/freetype/internal/internal.h create mode 100644 src/thirdparty/freetype2/include/freetype/internal/svginterface.h create mode 100644 src/thirdparty/freetype2/include/freetype/otsvg.h create mode 100644 src/thirdparty/freetype2/src/autofit/afadjust.c create mode 100644 src/thirdparty/freetype2/src/autofit/afadjust.h delete mode 100644 src/thirdparty/freetype2/src/autofit/afangles.c delete mode 100644 src/thirdparty/freetype2/src/autofit/afangles.h create mode 100644 src/thirdparty/freetype2/src/autofit/afgsub.c create mode 100644 src/thirdparty/freetype2/src/autofit/afgsub.h delete mode 100644 src/thirdparty/freetype2/src/autofit/afwarp.c delete mode 100644 src/thirdparty/freetype2/src/autofit/afwarp.h delete mode 100644 src/thirdparty/freetype2/src/autofit/afwrtsys.h create mode 100644 src/thirdparty/freetype2/src/autofit/afws-decl.h create mode 100644 src/thirdparty/freetype2/src/autofit/afws-iter.h create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb-decls.h create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb-ft.c create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb-ft.h create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb-types.h create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb.c create mode 100644 src/thirdparty/freetype2/src/autofit/ft-hb.h create mode 100644 src/thirdparty/freetype2/src/autofit/hb-script-list.h create mode 100644 src/thirdparty/freetype2/src/dlg/dlg.c rename src/thirdparty/freetype2/src/lzw/{ftzopen.c => ftzopen.ctpl} (95%) create mode 100644 src/thirdparty/freetype2/src/sdf/ftbsdf.c create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdf.c create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdf.h create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdfcommon.c create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdfcommon.h create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdferrs.h create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdfrend.c create mode 100644 src/thirdparty/freetype2/src/sdf/ftsdfrend.h create mode 100644 src/thirdparty/freetype2/src/sfnt/sfwoff2.c create mode 100644 src/thirdparty/freetype2/src/sfnt/sfwoff2.h create mode 100644 src/thirdparty/freetype2/src/sfnt/ttgpos.c create mode 100644 src/thirdparty/freetype2/src/sfnt/ttgpos.h create mode 100644 src/thirdparty/freetype2/src/sfnt/ttsvg.c create mode 100644 src/thirdparty/freetype2/src/sfnt/ttsvg.h create mode 100644 src/thirdparty/freetype2/src/sfnt/woff2tags.c create mode 100644 src/thirdparty/freetype2/src/sfnt/woff2tags.h create mode 100644 src/thirdparty/freetype2/src/svg/ftsvg.c create mode 100644 src/thirdparty/freetype2/src/svg/ftsvg.h create mode 100644 src/thirdparty/freetype2/src/svg/svgtypes.h delete mode 100644 src/thirdparty/freetype2/src/truetype/ttsubpix.c delete mode 100644 src/thirdparty/freetype2/src/truetype/ttsubpix.h diff --git a/.ecode/project_build.json b/.ecode/project_build.json index 8550b92ec..4bd800991 100644 --- a/.ecode/project_build.json +++ b/.ecode/project_build.json @@ -169,7 +169,7 @@ "eepp-linux": { "build": [ { - "args": "--disable-static-build --with-text-shaper --with-debug-symbols --with-mold-linker --address-sanitizer gmake", + "args": "--disable-static-build --with-text-shaper --with-mold-linker --with-debug-symbols --address-sanitizer gmake", "command": "premake4", "working_dir": "${project_root}" }, diff --git a/bin/unit_tests/assets/fontrendering/eepp-fonts.webp b/bin/unit_tests/assets/fontrendering/eepp-fonts.webp index 92d05bf94002c759598a531ffabcc016ec917ff9..8bd603de8ae1b2bda41021d63881440c085b9932 100644 GIT binary patch delta 72740 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 abd;d?-0g0^+VRW%X_o)Y@}IR&1_1y{fviga delta 72719 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

O;=9Pq+EZF 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 PI|X}MmA9O>iqrfLK+WL^ literal 7358 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 b!1#~EG57zM+x*ecqZaz3ar=dnb>sg9<;4co diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-edit-tabs-test.webp b/bin/unit_tests/assets/fontrendering/eepp-text-edit-tabs-test.webp index 8e73a15cf1a3007215031aa30b243e64f12bf56c..279f7f06c808a6b55b8538287b992f4835a68247 100644 GIT binary patch literal 7180 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 Gfd2uPGMfDW literal 7264 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 I798OJ0SIC$tN;K2 literal 7990 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 Me_fu2X<=dh5AD5|(*OVf diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-italic.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-italic.webp index b4035d13ae525214c1880b7a835c77922afc0e28..5fb2cd2a14d19417208cb9caabec7a3466b69186 100644 GIT binary patch literal 9432 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 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-outline.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-outline.webp index 7a34066b2a2d79e83f26d49a2b6d9f415b0a4cd0..f792313f81ba9f735d605cb4cbb3d9413babaa04 100644 GIT binary patch literal 10122 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 literal 10242 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 YZMbbG622Y#b0Ycw4=HcESuoK44;zO5S^xk5 literal 7792 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 literal 7818 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 Y9n1dy`EYwvQSor|U$+Nv1PaRk1IYgJ@Bjb+ diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-regular.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-regular.webp index e83f9611d645690a1388c22b09703e2b7c547102..b421e6aa31caa08ad5d18d3df811cec0d41c8852 100644 GIT binary patch literal 7796 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 V`O)={n=h*!|NXJGi?AQ>e*p7a^9}$2 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-shadow.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-shadow.webp index 03d4c8733aba41619fdc4408811e0afbfd32be0b..a716a4195ebb137c1df195767077f3bb58ad5101 100644 GIT binary patch literal 8954 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 literal 8994 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 literal 7358 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 G_5T2C=>Hu6 literal 7446 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 Qzy90(`vdQ`niTzi0KhIERsaA1 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-strikethrough.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-strikethrough.webp index 4252f58460998404ec41701ec8bda3e315d58887..a4f8393e3975e4d5a11defdcca0dc94e399823a8 100644 GIT binary patch literal 7372 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 literal 7438 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 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-underline-center.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-underline-center.webp index 3827dadd744ca54230f036c89096576ec494f7e9..ce7f717ab52d4e9876796f51f5553416beb63781 100644 GIT binary patch literal 7760 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 Cm)Y3> literal 7834 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 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-underline-right.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-underline-right.webp index b6f13bc995c3d78e05a80b6ddb9bbd42eebd82ec..1b385e3026b9624772728e733acb2d91040bb59a 100644 GIT binary patch literal 7730 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 diff --git a/bin/unit_tests/assets/fontrendering/eepp-text-style-underline.webp b/bin/unit_tests/assets/fontrendering/eepp-text-style-underline.webp index c158b5cd81b0eed80a32f96c6a232d5fda158797..c8f9fa6705d784c1f8213d65c21e69cbd3ebe4b1 100644 GIT binary patch literal 7754 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 QE$^LvH7wVDFJyrK1H%A|EdT%j diff --git a/bin/unit_tests/assets/fontrendering/eepp-textedit.webp b/bin/unit_tests/assets/fontrendering/eepp-textedit.webp index 243146fb40105cdc78a446fdd3946ff4540fcae5..0345926cca207db4d6033584dce683500de42c4d 100644 GIT binary patch literal 23020 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 diff --git a/bin/unit_tests/assets/fontrendering/eepp-textview.webp b/bin/unit_tests/assets/fontrendering/eepp-textview.webp index 52bcc3d061af714ca51c3152939a8633422a7357..21d9a24f783de25d23db123a6cfdc69442a5c2d3 100644 GIT binary patch literal 24420 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 WYvPwI?JeVPX0|T}+H&qv82/dev/null") - if handle then - local arch = handle:read("*l") - handle:close() - if arch then return arch end - end + local handle = io.popen("uname -m 2>/dev/null") + if handle then + local arch = handle:read("*l") + handle:close() + if arch then return arch end + end - local arch = os.getenv("PROCESSOR_ARCHITECTURE") - if arch then - if arch == "AMD64" or arch == "IA64" then - return "x86_64" - end - return string.lower(arch) - end + local arch = os.getenv("PROCESSOR_ARCHITECTURE") + if arch then + if arch == "AMD64" or arch == "IA64" then + return "x86_64" + end + return string.lower(arch) + end - return "x86_64" + return "x86_64" end function build_link_configuration( package_name, use_ee_icon ) @@ -556,11 +556,12 @@ function add_static_links() end if not _OPTIONS["with-dynamic-freetype"] then - links { "freetype-static", "libpng-static" } + links { "freetype-static" } end if _OPTIONS["with-text-shaper"] then - links { "harfbuzz-static" } + links { "harfbuzz-static", "SheenBidi-static" } + includedirs { "src/thirdparty/SheenBidi/Headers" } defines { "EE_TEXT_SHAPER_ENABLED" } end @@ -575,6 +576,7 @@ function add_static_links() "pcre2-8-static", "oniguruma-static", "libwebp-static", + "libpng-static", } if not _OPTIONS["without-mojoal"] then @@ -771,6 +773,8 @@ function build_eepp( build_name ) "src/thirdparty/pcre2/src", "src/thirdparty/oniguruma", "src/thirdparty/libwebp/src", + "src/thirdparty/SheenBidi/Headers", + "src/thirdparty/SheenBidi/Headers/SheenBidi", } add_static_links() @@ -1127,6 +1131,14 @@ workspace "eepp" target_dir_thirdparty() filter "action:vs*" buildoptions{ "/bigobj" } + + project "SheenBidi-static" + kind "StaticLib" + language "C" + files { "src/thirdparty/SheenBidi/Source/**.c" } + incdirs { "src/thirdparty/SheenBidi/Headers" } + target_dir_thirdparty() + build_base_configuration( "sheenbidi" ) end project "chipmunk-static" diff --git a/src/eepp/graphics/fonttruetype.cpp b/src/eepp/graphics/fonttruetype.cpp index ee5dda144..05c29b900 100644 --- a/src/eepp/graphics/fonttruetype.cpp +++ b/src/eepp/graphics/fonttruetype.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -29,6 +30,8 @@ using namespace EE::Window; namespace { +RETAIN_SYMBOL( FT_Palette_Select ); + // FreeType callbacks that operate on a IOStream unsigned long read( FT_Stream rec, unsigned long offset, unsigned char* buffer, unsigned long count ) { diff --git a/src/eepp/graphics/textshaperun.cpp b/src/eepp/graphics/textshaperun.cpp index 3875efb04..bec303ea6 100644 --- a/src/eepp/graphics/textshaperun.cpp +++ b/src/eepp/graphics/textshaperun.cpp @@ -68,6 +68,7 @@ void TextShapeRun::findNextEnd() { mCurFont = font; if ( curScript == HB_SCRIPT_COMMON || curScript == HB_SCRIPT_INHERITED ) curScript = HB_SCRIPT_LATIN; + mIsRTL = hb_script_get_horizontal_direction( curScript ) == HB_DIRECTION_RTL; } // Break run if: @@ -81,6 +82,7 @@ void TextShapeRun::findNextEnd() { if ( mIsNewLine || ( lFont != nullptr && font != lFont ) || effectiveScript != curScript ) { mLen = mIsNewLine ? pos + 1 : pos; mCurFont = lFont; + mIsRTL = hb_script_get_horizontal_direction( effectiveScript ) == HB_DIRECTION_RTL; return; } @@ -114,4 +116,8 @@ void TextShapeRun::findNextEnd() { #endif } +bool TextShapeRun::isRTL() const { + return mIsRTL; +} + } // namespace EE::Graphics diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAlgorithm.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAlgorithm.h new file mode 100644 index 000000000..07ff531d7 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAlgorithm.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_ALGORITHM_H +#define _SB_PUBLIC_ALGORITHM_H + +#include +#include +#include +#include + +SB_EXTERN_C_BEGIN + +typedef const struct _SBAlgorithm *SBAlgorithmRef; + +/** + * Creates an algorithm object for the specified code point sequence. The source string inside the + * code point sequence should not be freed until the algorithm object is in use. + * + * @param codepointSequence + * The code point sequence to apply bidirectional algorithm on. + * @return + * A reference to an algorithm object if the call was successful, NULL otherwise. + */ +SB_PUBLIC SBAlgorithmRef SBAlgorithmCreate(const SBCodepointSequence *codepointSequence); + +/** + * Returns a direct pointer to the bidirectional types of code units, stored in the algorithm + * object. + * + * @param algorithm + * The algorithm object from which to access the bidirectional types of code units. + * @return + * A valid pointer to an array of SBBidiType structures, whose length will be equal to that of + * string buffer. + */ +SB_PUBLIC const SBBidiType *SBAlgorithmGetBidiTypesPtr(SBAlgorithmRef algorithm); + +/** + * Determines the boundary of first paragraph within the specified range. + * + * The boundary of the paragraph occurs after a code point whose bidirectional type is Paragraph + * Separator (B), or at the suggestedLength if no such code point exists before it. The exception to + * this rule is when a Carriage Return (CR) is followed by a Line Feed (LF). Both CR and LF are + * paragraph separators, but in that case, the boundary of the paragraph is considered after LF code + * point. + * + * @param algorithm + * The algorithm object to use for determining paragraph boundary. + * @param paragraphOffset + * The index to the first code unit of the paragraph in source string. + * @param suggestedLength + * The number of code units covering the suggested length of the paragraph. + * @param acutalLength + * The actual length of the first paragraph, including the paragraph separator, within the + * given range. + * @param separatorLength + * On output, the length of paragraph separator. This parameter can be set to NULL if not + * needed. + */ +SB_PUBLIC void SBAlgorithmGetParagraphBoundary(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *acutalLength, SBUInteger *separatorLength); + +/** + * Creates a paragraph object processed with Unicode Bidirectional Algorithm. + * + * This function processes only first paragraph starting at paragraphOffset with length less than or + * equal to suggestedLength, in accordance with Rule P1 of Unicode Bidirectional Algorithm. + * + * The paragraph level is determined by applying Rules P2-P3 and embedding levels are resolved by + * applying Rules X1-I2. + * + * @param algorithm + * The algorithm object to use for creating the desired paragraph. + * @param paragraphOffset + * The index to the first code unit of the paragraph in source string. + * @param suggestedLength + * The number of code units covering the suggested length of the paragraph. + * @param baseLevel + * The desired base level of the paragraph. Rules P2-P3 would be ignored if it is neither + * SBLevelDefaultLTR nor SBLevelDefaultRTL. + * @return + * A reference to a paragraph object if the call was successful, NULL otherwise. + */ +SB_PUBLIC SBParagraphRef SBAlgorithmCreateParagraph(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel); + +/** + * Increments the reference count of an algorithm object. + * + * @param algorithm + * The algorithm object whose reference count will be incremented. + * @return + * The same algorithm object passed in as the parameter. + */ +SB_PUBLIC SBAlgorithmRef SBAlgorithmRetain(SBAlgorithmRef algorithm); + +/** + * Decrements the reference count of an algorithm object. The object will be deallocated when its + * reference count reaches zero. + * + * @param algorithm + * The algorithm object whose reference count will be decremented. + */ +SB_PUBLIC void SBAlgorithmRelease(SBAlgorithmRef algorithm); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAllocator.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAllocator.h new file mode 100644 index 000000000..fca74689f --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBAllocator.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_ALLOCATOR_H +#define _SB_PUBLIC_ALLOCATOR_H + +#include + +SB_EXTERN_C_BEGIN + +typedef const struct _SBAllocator *SBAllocatorRef; + +/** + * Function type for allocating a single memory block. + * + * @param size + * Size of the memory block to allocate, in bytes. + * @param info + * User-defined context pointer provided during allocator creation. + * @return + * Pointer to the allocated memory block, or `NULL` on failure. + */ +typedef void *(*SBAllocatorAllocateBlockFunc)(SBUInteger size, void *info); + +/** + * Function type for resizing a previously allocated memory block. + * + * @param pointer + * Pointer to the memory block to be resized. + * @param newSize + * The new size in bytes for the memory block. + * @param info + * User-defined context pointer provided during allocator creation. + * @return + * Pointer to the resized memory block, or `NULL` if the operation failed. + */ +typedef void *(*SBAllocatorReallocateBlockFunc)(void *pointer, SBUInteger newSize, void *info); + +/** + * Function type for deallocating a previously allocated memory block. + * + * @param pointer + * Pointer to the memory block to deallocate. + * @param info + * User-defined context pointer provided during allocator creation. + */ +typedef void (*SBAllocatorDeallocateBlockFunc)(void *pointer, void *info); + +/** + * Function type for allocating short-lived scratch memory. + * + * Scratch allocations are intended for temporary use within the scope of a public function call. + * All memory returned by this function is automatically invalidated after a corresponding call to + * `resetScratch`, which is typically called at the end of the same public function. + * + * The implementation is responsible for managing thread safety (e.g. using thread-local buffers, + * locking, or fallback mechanisms). + * + * @param size + * The requested size of scratch memory, in bytes. + * @param info + * User-defined context pointer provided during allocator creation. + * @return + * Pointer to the allocated memory block, or `NULL` on failure. + */ +typedef void *(*SBAllocatorAllocateScratchFunc)(SBUInteger size, void *info); + +/** + * Function type for resetting the scratch memory space. + * + * This invalidates all previous scratch allocations for the current execution context (e.g., + * thread). It is typically called once per public function to reuse memory without freeing + * individual chunks. + * + * @param info + * User-defined context pointer provided during allocator creation. + */ +typedef void (*SBAllocatorResetScratchFunc)(void *info); + +/** + * Function signature for finalizing an allocator object. + * This is called once the reference count reaches zero. + * + * @param info + * User-defined context pointer provided during allocator creation. + */ +typedef void (*SBAllocatorFinalizeFunc)(void *info); + +/** + * Set of function pointers defining a memory allocator protocol. + * + * All functions are optional except `allocateBlock` and `deallocateBlock`. Optional functions will + * fall back to standard mechanisms if not provided. + */ +typedef struct _SBAllocatorProtocol { + /** + * Allocates a memory block of the given size. + */ + SBAllocatorAllocateBlockFunc allocateBlock; + /** + * Reallocates a previously allocated block to a new size. + */ + SBAllocatorReallocateBlockFunc reallocateBlock; + /** + * Deallocates a memory block. + */ + SBAllocatorDeallocateBlockFunc deallocateBlock; + /** + * Allocates short-lived scratch memory. + * If `NULL`, the allocator will return `NULL` prompting the caller to use `allocateBlock` + * instead. + */ + SBAllocatorAllocateScratchFunc allocateScratch; + /** + * Resets the scratch memory space, invalidating previous allocations. + * If `NULL`, the allocator will do nothing. + */ + SBAllocatorResetScratchFunc resetScratch; + /** + * Optional function to finalize the allocator when its reference count drops to zero. + */ + SBAllocatorFinalizeFunc finalize; +} SBAllocatorProtocol; + +/** + * Returns the global default allocator object. + */ +SB_PUBLIC SBAllocatorRef SBAllocatorGetDefault(void); + +/** + * Sets the global default allocator object. + * + * @param allocator + * The allocator object to set as the default. If `NULL`, the default allocator will be reset + * to a standard implementation. + */ +SB_PUBLIC void SBAllocatorSetDefault(SBAllocatorRef allocator); + +/** + * Creates a custom allocator using the provided allocation protocol and optional context. + * + * @param protocol + * The set of function pointers defining custom allocation behavior. + * @param info + * An optional pointer to context data passed to each allocator function. + * @return + * A reference to the allocator instance, or `NULL` on failure. + */ +SB_PUBLIC SBAllocatorRef SBAllocatorCreate(const SBAllocatorProtocol *protocol, void *info); + +/** + * Increments the reference count of an allocator object. + * + * @param allocator + * The allocator object whose reference count will be incremented. + * @return + * The same allocator object passed in as the parameter. + */ +SB_PUBLIC SBAllocatorRef SBAllocatorRetain(SBAllocatorRef allocator); + +/** + * Decrements the reference count of an allocator object. The object will be deallocated when its + * reference count reaches zero. + * + * @param allocator + * The allocator object whose reference count will be decremented. + */ +SB_PUBLIC void SBAllocatorRelease(SBAllocatorRef allocator); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBase.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBase.h new file mode 100644 index 000000000..dfb6d8c8f --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBase.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_BASE_H +#define _SB_PUBLIC_BASE_H + +#include + +#ifdef __cplusplus +#define SB_EXTERN_C_BEGIN extern "C" { +#define SB_EXTERN_C_END } +#else +#define SB_EXTERN_C_BEGIN +#define SB_EXTERN_C_END +#endif + +#ifdef _WIN32 + +#if defined(SB_CONFIG_DLL_EXPORT) +#define SB_PUBLIC __declspec(dllexport) +#elif defined(SB_CONFIG_DLL_IMPORT) +#define SB_PUBLIC __declspec(dllimport) +#endif + +#endif + +#ifndef SB_PUBLIC +#define SB_PUBLIC +#endif + +#if defined(__cplusplus) && __cplusplus >= 201402L +#define SB_DEPRECATED [[deprecated]] +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +#define SB_DEPRECATED [[deprecated]] +#elif defined(__clang__) || defined(__GNUC__) +#define SB_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define SB_DEPRECATED __declspec(deprecated) +#else +#define SB_DEPRECATED +#endif + +SB_EXTERN_C_BEGIN + +/** + * A type to represent an 8-bit signed integer. + */ +typedef int8_t SBInt8; + +/** + * A type to represent a 16-bit signed integer. + */ +typedef int16_t SBInt16; + +/** + * A type to represent a 32-bit signed integer. + */ +typedef int32_t SBInt32; + +/** + * A type to represent an 8-bit unsigned integer. + */ +typedef uint8_t SBUInt8; + +/** + * A type to represent a 16-bit unsigned integer. + */ +typedef uint16_t SBUInt16; + +/** + * A type to represent a 32-bit unsigned integer. + */ +typedef uint32_t SBUInt32; + +/** + * A signed integer type whose width is equal to the width of the machine word. + */ +typedef intptr_t SBInteger; + +/** + * An unsigned integer type whose width is equal to the width of the machine word. + */ +typedef uintptr_t SBUInteger; + +/** + * Constants that specify the states of a boolean. + */ +enum { + SBFalse = 0, /**< A value representing the false state. */ + SBTrue = 1 /**< A value representing the true state. */ +}; +/** + * A type to represent a boolean value. + */ +typedef SBUInt8 SBBoolean; + +#define SBUInt8InRange(v, s, e) \ +( \ + (SBUInt8)((v) - (s)) \ + <= (SBUInt8)((e) - (s)) \ +) + +#define SBUInt16InRange(v, s, e) \ +( \ + (SBUInt16)((v) - (s)) \ + <= (SBUInt16)((e) - (s)) \ +) + +#define SBUInt32InRange(v, s, e) \ +( \ + (SBUInt32)((v) - (s)) \ + <= (SBUInt32)((e) - (s)) \ +) + + +/** + * A type to represent a bidi level. + */ +typedef SBUInt8 SBLevel; + +/** + * A value representing an invalid bidi level. + */ +#define SBLevelInvalid 0xFF + +/** + * A value representing maximum explicit embedding level. + */ +#define SBLevelMax 125 + +/** + * A value specifying to set base level to zero (left-to-right) if there is no strong character. + */ +#define SBLevelDefaultLTR 0xFE + +/** + * A value specifying to set base level to one (right-to-left) if there is no strong character. + */ +#define SBLevelDefaultRTL 0xFD + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBidiType.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBidiType.h new file mode 100644 index 000000000..8f78b1b30 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBBidiType.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_BIDI_TYPE_H +#define _SB_PUBLIC_BIDI_TYPE_H + +#include + +SB_EXTERN_C_BEGIN + +/** + * Constants that specify the bidirectional types of a character. + */ +enum { + SBBidiTypeNil = 0x00, + + SBBidiTypeL = 0x01, /**< Strong: Left-to-Right */ + SBBidiTypeR = 0x02, /**< Strong: Right-to-Left */ + SBBidiTypeAL = 0x03, /**< Strong: Right-to-Left Arabic */ + + SBBidiTypeBN = 0x04, /**< Weak: Boundary Neutral */ + SBBidiTypeNSM = 0x05, /**< Weak: Non-Spacing Mark */ + SBBidiTypeAN = 0x06, /**< Weak: Arabic Number */ + SBBidiTypeEN = 0x07, /**< Weak: European Number */ + SBBidiTypeET = 0x08, /**< Weak: European Number Terminator */ + SBBidiTypeES = 0x09, /**< Weak: European Number Separator */ + SBBidiTypeCS = 0x0A, /**< Weak: Common Number Separator */ + + SBBidiTypeWS = 0x0B, /**< Neutral: White Space */ + SBBidiTypeS = 0x0C, /**< Neutral: Segment Separator */ + SBBidiTypeB = 0x0D, /**< Neutral: Paragraph Separator */ + SBBidiTypeON = 0x0E, /**< Neutral: Other Neutral */ + + SBBidiTypeLRI = 0x0F, /**< Format: Left-to-Right Isolate */ + SBBidiTypeRLI = 0x10, /**< Format: Right-to-Left Isolate */ + SBBidiTypeFSI = 0x11, /**< Format: First Strong Isolate */ + SBBidiTypePDI = 0x12, /**< Format: Pop Directional Isolate */ + SBBidiTypeLRE = 0x13, /**< Format: Left-to-Right Embedding */ + SBBidiTypeRLE = 0x14, /**< Format: Right-to-Left Embedding */ + SBBidiTypeLRO = 0x15, /**< Format: Left-to-Right Override */ + SBBidiTypeRLO = 0x16, /**< Format: Right-to-Left Override */ + SBBidiTypePDF = 0x17 /**< Format: Pop Directional Formatting */ +}; + +/** + * A type to represent the bidirectional type of a character. + */ +typedef SBUInt8 SBBidiType; + +/** + * Checks whether specified bidirectional type is strong. + */ +#define SBBidiTypeIsStrong(t) SBUInt8InRange(t, SBBidiTypeL, SBBidiTypeAL) + +/** + * Checks whether specified bidirectional type is weak. + */ +#define SBBidiTypeIsWeak(t) SBUInt8InRange(t, SBBidiTypeBN, SBBidiTypeCS) + +/** + * Checks whether specified bidirectional type is neutral. + */ +#define SBBidiTypeIsNeutral(t) SBUInt8InRange(t, SBBidiTypeWS, SBBidiTypeON) + +/** + * Checks whether specified bidirectional type is format. + */ +#define SBBidiTypeIsFormat(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypePDF) + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepoint.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepoint.h new file mode 100644 index 000000000..6f470c4ad --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepoint.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_CODEPOINT_H +#define _SB_PUBLIC_CODEPOINT_H + +#include +#include +#include +#include + +SB_EXTERN_C_BEGIN + +/** + * A type to represent a Unicode code point. + */ +typedef SBUInt32 SBCodepoint; + +/** + * A value representing an invalid Unicode code point. + */ +#define SBCodepointInvalid UINT32_MAX + +/** + * A value representing a faulty Unicode code point. + * + * This value is used as a replacement for unrecognized code points during decoding. + */ +#define SBCodepointFaulty 0xFFFD + +/** + * The maximum valid Unicode code point value. + * + * Unicode code points are valid in the range [0x0000, 0x10FFFF]. + */ +#define SBCodepointMax 0x10FFFF + +/** + * Checks if a code point is a UTF-16 surrogate. + * + * Surrogate code points lie within the range [0xD800, 0xDFFF] and are not valid Unicode scalar + * values. + * + * @param c + * The code point to check. + * @return + * `true` if the code point is a surrogate, `false` otherwise. + */ +#define SBCodepointIsSurrogate(c) SBUInt32InRange(c, 0xD800, 0xDFFF) + +/** + * Checks if a code point is a valid Unicode scalar value. + * + * A code point is considered valid if: + * - It is not a surrogate (i.e., not in the range 0xD800 to 0xDFFF) + * - It is less than or equal to SBCodepointMax (0x10FFFF). + * + * @param c + * The code point to check. + * @return + * `true` if the code point is valid, `false` otherwise. + */ +#define SBCodepointIsValid(c) (!SBCodepointIsSurrogate(c) && (c) <= SBCodepointMax) + +/** + * Returns the bidirectional type of a Unicode code point. + * + * @param codepoint + * The code point whose bidirectional type is returned. + * @return + * The bidirectional type of the specified code point. + */ +SB_PUBLIC SBBidiType SBCodepointGetBidiType(SBCodepoint codepoint); + +/** + * Returns the general category of a Unicode code point. + * + * @param codepoint + * The code point whose general category is returned. + * @return + * The general category of the specified code point. + */ +SB_PUBLIC SBGeneralCategory SBCodepointGetGeneralCategory(SBCodepoint codepoint); + +/** + * Returns the mirrored code point for a given Unicode code point. + * + * @param codepoint + * The code point whose mirrored counterpart is returned. + * @return + * The mirrored code point if available, or 0 if no mirror exists. + */ +SB_PUBLIC SBCodepoint SBCodepointGetMirror(SBCodepoint codepoint); + +/** + * Returns the script associated with a Unicode code point. + * + * @param codepoint + * The code point whose script is returned. + * @return + * The script of the specified code point. + */ +SB_PUBLIC SBScript SBCodepointGetScript(SBCodepoint codepoint); + +/** + * Decodes the next Unicode code point from a UTF-8 encoded buffer. + * + * @param buffer + * The buffer containing UTF-8 encoded code units. + * @param length + * The length of the buffer. + * @param index + * The index at which decoding starts. On output, it is updated to the start of the next code + * point. + * @return + * The decoded code point, or `SBCodepointInvalid` if `index` is out of bounds. + */ +SB_PUBLIC SBCodepoint SBCodepointDecodeNextFromUTF8(const SBUInt8 *buffer, SBUInteger length, + SBUInteger *index); + +/** + * Decodes the previous Unicode code point from a UTF-8 encoded buffer. + * + * @param buffer + * The buffer containing UTF-8 encoded code units. + * @param length + * The length of the buffer. + * @param index + * The index before which decoding occurs. On output, it is updated to the start of the + * decoded code point. + * @return + * The decoded code point, or `SBCodepointInvalid` if `index` is zero or out of bounds. + */ +SB_PUBLIC SBCodepoint SBCodepointDecodePreviousFromUTF8(const SBUInt8 *buffer, SBUInteger length, + SBUInteger *index); + +/** + * Decodes the next Unicode code point from a UTF-16 encoded buffer. + * + * @param buffer + * The buffer containing UTF-16 encoded code units. + * @param length + * The length of the buffer. + * @param index + * The index at which decoding starts. On output, it is updated to the start of the next code + * point. + * @return + * The decoded code point, or `SBCodepointInvalid` if `index` is out of bounds. + */ +SB_PUBLIC SBCodepoint SBCodepointDecodeNextFromUTF16(const SBUInt16 *buffer, SBUInteger length, + SBUInteger *index); + +/** + * Decodes the previous Unicode code point from a UTF-16 encoded buffer. + * + * @param buffer + * The buffer containing UTF-16 encoded code units. + * @param length + * The length of the buffer. + * @param index + * The index before which decoding occurs. On output, it is updated to the start of the + * decoded code point. + * @return + * The decoded code point, or `SBCodepointInvalid` if `index` is zero or out of bounds. + */ +SB_PUBLIC SBCodepoint SBCodepointDecodePreviousFromUTF16(const SBUInt16 *buffer, SBUInteger length, + SBUInteger *index); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepointSequence.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepointSequence.h new file mode 100644 index 000000000..b5f58647a --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBCodepointSequence.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_CODEPOINT_SEQUENCE_H +#define _SB_PUBLIC_CODEPOINT_SEQUENCE_H + +#include +#include + +SB_EXTERN_C_BEGIN + +enum { + SBStringEncodingUTF8 = 0, /**< An 8-bit representation of Unicode code points. */ + SBStringEncodingUTF16 = 1, /**< 16-bit UTF encoding in native endianness. */ + SBStringEncodingUTF32 = 2 /**< 32-bit UTF encoding in native endianness. */ +}; +typedef SBUInt32 SBStringEncoding; + +typedef struct _SBCodepointSequence { + SBStringEncoding stringEncoding; /**< The encoding of the string. */ + const void *stringBuffer; /**< The source string containing the code units. */ + SBUInteger stringLength; /**< The length of the string in terms of code units. */ +} SBCodepointSequence; + +/** + * Returns the code point before the given string index. + * + * @param codepointSequence + * The object holding the information of the string. + * @param stringIndex + * The index of code unit before which to get the code point. On output, it is set to point to + * the first code unit of returned code point. + * @return + * The code point before the given string index, or SBCodepointInvalid if stringIndex is equal + * to zero or larger than actual length of source string. + */ +SB_PUBLIC SBCodepoint SBCodepointSequenceGetCodepointBefore( + const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); + +/** + * Returns the code point at the given string index. + * + * @param codepointSequence + * The object holding the information of the string. + * @param stringIndex + * The index of code unit at which to get the code point. On output, it is set to point to the + * first code unit of next code point. + * @return + * The code point at the given string index, or SBCodepointInvalid if stringIndex is larger + * than or equal to actual length of source string. + */ +SB_PUBLIC SBCodepoint SBCodepointSequenceGetCodepointAt( + const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBConfig.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBConfig.h new file mode 100644 index 000000000..69acad4ac --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBConfig.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_CONFIG_H +#define _SB_PUBLIC_CONFIG_H + +/* #define SB_CONFIG_DLL_EXPORT */ +/* #define SB_CONFIG_DLL_IMPORT */ +/* #define SB_CONFIG_LOG */ +/* #define SB_CONFIG_UNITY */ +/* #define SB_CONFIG_ALLOW_NON_ATOMIC_FALLBACK */ + +/** + * Disable scratch memory functionality of default allocator. + * When defined, all scratch memory operations will return NULL/do nothing. + */ +/* #define SB_CONFIG_DISABLE_SCRATCH_MEMORY */ + +/** + * Define the size of each scratch buffer in bytes. + * Default is 8192 bytes (8KB) if not specified. + */ +#ifndef SB_CONFIG_SCRATCH_BUFFER_SIZE +#define SB_CONFIG_SCRATCH_BUFFER_SIZE 8192 +#endif + +/** + * Define the number of scratch buffers in the pool. + * Default is 3 buffers if not specified. + */ +#ifndef SB_CONFIG_SCRATCH_POOL_SIZE +#define SB_CONFIG_SCRATCH_POOL_SIZE 3 +#endif + +#ifdef SB_CONFIG_UNITY +#define SB_INTERNAL static +#else +#define SB_INTERNAL +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBGeneralCategory.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBGeneralCategory.h new file mode 100644 index 000000000..f32545312 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBGeneralCategory.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_GENERAL_CATEGORY_H +#define _SB_PUBLIC_GENERAL_CATEGORY_H + +#include + +SB_EXTERN_C_BEGIN + +/** + * Constants that specify the general category of a character. + */ +enum { + SBGeneralCategoryNil = 0x00, + + SBGeneralCategoryLU = 0x01, /**< Letter: Uppercase Letter */ + SBGeneralCategoryLL = 0x02, /**< Letter: Lowercase Letter */ + SBGeneralCategoryLT = 0x03, /**< Letter: Titlecase Letter */ + SBGeneralCategoryLM = 0x04, /**< Letter: Modifier Letter */ + SBGeneralCategoryLO = 0x05, /**< Letter: Other Letter */ + + SBGeneralCategoryMN = 0x06, /**< Mark: Nonspacing Mark */ + SBGeneralCategoryMC = 0x07, /**< Mark: Spacing Mark */ + SBGeneralCategoryME = 0x08, /**< Mark: Enclosing Mark */ + + SBGeneralCategoryND = 0x09, /**< Number: Decimal Number */ + SBGeneralCategoryNL = 0x0A, /**< Number: Letter Number */ + SBGeneralCategoryNO = 0x0B, /**< Number: Other Number */ + + SBGeneralCategoryPC = 0x0C, /**< Punctuation: Connector Punctuation */ + SBGeneralCategoryPD = 0x0D, /**< Punctuation: Dash Punctuation */ + SBGeneralCategoryPS = 0x0E, /**< Punctuation: Open Punctuation */ + SBGeneralCategoryPE = 0x0F, /**< Punctuation: Close Punctuation */ + SBGeneralCategoryPI = 0x10, /**< Punctuation: Initial Punctuation */ + SBGeneralCategoryPF = 0x11, /**< Punctuation: Final Punctuation */ + SBGeneralCategoryPO = 0x12, /**< Punctuation: Other Punctuation */ + + SBGeneralCategorySM = 0x13, /**< Symbol: Math Symbol */ + SBGeneralCategorySC = 0x14, /**< Symbol: Currency Symbol */ + SBGeneralCategorySK = 0x15, /**< Symbol: Modifier Symbol */ + SBGeneralCategorySO = 0x16, /**< Symbol: Other Symbol */ + + SBGeneralCategoryZS = 0x17, /**< Separator: Space Separator */ + SBGeneralCategoryZL = 0x18, /**< Separator: Line Separator */ + SBGeneralCategoryZP = 0x19, /**< Separator: Paragraph Separator */ + + SBGeneralCategoryCC = 0x1A, /**< Other: Control */ + SBGeneralCategoryCF = 0x1B, /**< Other: Format */ + SBGeneralCategoryCS = 0x1C, /**< Other: Surrogate */ + SBGeneralCategoryCO = 0x1D, /**< Other: Private_Use */ + SBGeneralCategoryCN = 0x1E /**< Other: Unassigned */ +}; + +/** + * A type to represent the general category of a character. + */ +typedef SBUInt8 SBGeneralCategory; + +/** + * Checks whether specified general category is letter. + */ +#define SBGeneralCategoryIsLetter(gc) SBUInt8InRange(gc, SBGeneralCategoryLU, SBGeneralCategoryLO) + +/** + * Checks whether specified general category is mark. + */ +#define SBGeneralCategoryIsMark(gc) SBUInt8InRange(gc, SBGeneralCategoryMN, SBGeneralCategoryME) + +/** + * Checks whether specified general category is number. + */ +#define SBGeneralCategoryIsNumber(gc) SBUInt8InRange(gc, SBGeneralCategoryND, SBGeneralCategoryNO) + +/** + * Checks whether specified general category is punctuation. + */ +#define SBGeneralCategoryIsPunctuation(gc) SBUInt8InRange(gc, SBGeneralCategoryPC, SBGeneralCategoryPO) + +/** + * Checks whether specified general category is symbol. + */ +#define SBGeneralCategoryIsSymbol(gc) SBUInt8InRange(gc, SBGeneralCategorySM, SBGeneralCategorySO) + +/** + * Checks whether specified general category is separator. + */ +#define SBGeneralCategoryIsSeparator(gc) SBUInt8InRange(gc, SBGeneralCategoryZS, SBGeneralCategoryZP) + +/** + * Checks whether specified general category is other. + */ +#define SBGeneralCategoryIsOther(gc) SBUInt8InRange(gc, SBGeneralCategoryCC, SBGeneralCategoryCN) + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBLine.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBLine.h new file mode 100644 index 000000000..062f5b847 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBLine.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_LINE_H +#define _SB_PUBLIC_LINE_H + +#include +#include + +SB_EXTERN_C_BEGIN + +typedef const struct _SBLine *SBLineRef; + +/** + * Returns the index to the first code unit of the line in source string. + * + * @param line + * The line whose offset is returned. + * @return + * The offset of the line passed in. + */ +SB_PUBLIC SBUInteger SBLineGetOffset(SBLineRef line); + +/** + * Returns the number of code units coverting the length of the line. + * + * @param line + * The line whose length is returned. + * @return + * The length of the line passed in. + */ +SB_PUBLIC SBUInteger SBLineGetLength(SBLineRef line); + +/** + * Returns the number of runs in the line. + * + * @param line + * The line whose run count is returned. + * @return + * The number of runs in the line passed in. + */ +SB_PUBLIC SBUInteger SBLineGetRunCount(SBLineRef line); + +/** + * Returns a direct pointer to the run array, stored in the line. + * + * @param line + * The line from which to access the runs. + * @return + * A valid pointer to an array of SBRun structures. + */ +SB_PUBLIC const SBRun *SBLineGetRunsPtr(SBLineRef line); + +/** + * Increments the reference count of a line object. + * + * @param line + * The line object whose reference count will be incremented. + * @return + * The same line object passed in as the parameter. + */ +SB_PUBLIC SBLineRef SBLineRetain(SBLineRef line); + +/** + * Decrements the reference count of a line object. The object will be deallocated when its + * reference count reaches zero. + * + * @param line + * The line object whose reference count will be decremented. + */ +SB_PUBLIC void SBLineRelease(SBLineRef line); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBMirrorLocator.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBMirrorLocator.h new file mode 100644 index 000000000..b1a61086f --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBMirrorLocator.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_MIRROR_LOCATOR_H +#define _SB_PUBLIC_MIRROR_LOCATOR_H + +#include +#include +#include + +SB_EXTERN_C_BEGIN + +typedef struct _SBMirrorLocator *SBMirrorLocatorRef; + +/** + * A structure containing the information about a code point having Bidi_Mirrored property. + */ +typedef struct _SBMirrorAgent { + SBUInteger index; /**< The absolute index of the code point. */ + SBCodepoint mirror; /**< The mirrored code point. */ + SBCodepoint codepoint; /**< The actual code point. */ +} SBMirrorAgent; + +/** + * Creates a mirror locator object which can be used to find mirrors in a line. + * + * @return + * A reference to a mirror locator object. + */ +SB_PUBLIC SBMirrorLocatorRef SBMirrorLocatorCreate(void); + +/** + * Loads a line in the locator so that its mirror can be located. + * + * @param locator + * The locator in which the line will be loaded. + * @param line + * The line which will be loaded in the locator. + * @param stringBuffer + * The string buffer from which the line's algorithm was created. + */ +SB_PUBLIC void SBMirrorLocatorLoadLine(SBMirrorLocatorRef locator, SBLineRef line, + const void *stringBuffer); + +/** + * Returns the agent containing the information of current located mirror. + * + * @param locator + * The locator whose agent is returned. + */ +SB_PUBLIC const SBMirrorAgent *SBMirrorLocatorGetAgent(SBMirrorLocatorRef locator); + +/** + * Instructs the locator to find next mirror in the loaded line. + * + * @param locator + * The locator whom you want to instruct. + * @return + * SBTrue if another mirror is available, SBFalse otherwise. + * @note + * The locator will be reset after locating last mirror. + */ +SB_PUBLIC SBBoolean SBMirrorLocatorMoveNext(SBMirrorLocatorRef locator); + +/** + * Instructs the locator to reset itself so that mirrors of the loaded line can be obatained from + * the beginning. + * + * @param locator + * The locator whom you want to reset. + */ +SB_PUBLIC void SBMirrorLocatorReset(SBMirrorLocatorRef locator); + +/** + * Increments the reference count of a mirror locator object. + * + * @param locator + * The mirror locator object whose reference count will be incremented. + * @return + * The same mirror locator object passed in as the parameter. + */ +SB_PUBLIC SBMirrorLocatorRef SBMirrorLocatorRetain(SBMirrorLocatorRef locator); + +/** + * Decrements the reference count of a mirror locator object. The object will be deallocated when + * its reference count reaches zero. + * + * @param locator + * The mirror locator object whose reference count will be decremented. + */ +SB_PUBLIC void SBMirrorLocatorRelease(SBMirrorLocatorRef locator); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBParagraph.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBParagraph.h new file mode 100644 index 000000000..16637bf58 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBParagraph.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_PARAGRAPH_H +#define _SB_PUBLIC_PARAGRAPH_H + +#include +#include + +SB_EXTERN_C_BEGIN + +typedef const struct _SBParagraph *SBParagraphRef; + +/** + * Returns the index to the first code unit of the paragraph in source string. + * + * @param paragraph + * The paragraph whose offset is returned. + * @return + * The offset of the paragraph passed in. + */ +SB_PUBLIC SBUInteger SBParagraphGetOffset(SBParagraphRef paragraph); + +/** + * Returns the number of code units covering the length of the paragraph. + * + * @param paragraph + * The paragraph whose length is returned. + * @return + * The length of the paragraph passed in. + */ +SB_PUBLIC SBUInteger SBParagraphGetLength(SBParagraphRef paragraph); + +/** + * Returns the base level of the paragraph. + * + * @param paragraph + * The paragraph whose base level is returned. + * @return + * The base level of the paragraph passed in. + */ +SB_PUBLIC SBLevel SBParagraphGetBaseLevel(SBParagraphRef paragraph); + +/** + * Returns a direct pointer to the embedding levels, stored in the paragraph. + * + * @param paragraph + * The paragraph from which to access the embedding levels. + * @return + * A valid pointer to an array of SBLevel structures. + */ +SB_PUBLIC const SBLevel *SBParagraphGetLevelsPtr(SBParagraphRef paragraph); + +/** + * Creates a line object of specified range by applying rules L1-L2 of Unicode Bidirectional + * Algorithm. + * + * @param paragraph + * The paragraph that creates the line. + * @param lineOffset + * The index to the first code unit of the line in source string. It should occur within the + * range of paragraph. + * @param lineLength + * The number of code units covering the length of the line. + * @return + * A reference to a line object if the call was successful, NULL otherwise. + */ +SB_PUBLIC SBLineRef SBParagraphCreateLine(SBParagraphRef paragraph, SBUInteger lineOffset, + SBUInteger lineLength); + +/** + * Increments the reference count of a paragraph object. + * + * @param paragraph + * The paragraph object whose reference count will be incremented. + * @return + * The same paragraph object passed in as the parameter. + */ +SB_PUBLIC SBParagraphRef SBParagraphRetain(SBParagraphRef paragraph); + +/** + * Decrements the reference count of a paragraph object. The object will be deallocated when its + * reference count reaches zero. + * + * @param paragraph + * The paragraph object whose reference count will be decremented. + */ +SB_PUBLIC void SBParagraphRelease(SBParagraphRef paragraph); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBRun.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBRun.h new file mode 100644 index 000000000..442a0ea17 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBRun.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_RUN_H +#define _SB_PUBLIC_RUN_H + +#include + +SB_EXTERN_C_BEGIN + +/** + * A structure containing the information of a sequence of characters having the same embedding + * level. + */ +typedef struct _SBRun { + SBUInteger offset; /**< The index to the first code unit of the run in source string. */ + SBUInteger length; /**< The number of code units covering the length of the run. */ + SBLevel level; /**< The embedding level of the run. */ +} SBRun; + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScript.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScript.h new file mode 100644 index 000000000..509a8d4af --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScript.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_SCRIPT_H +#define _SB_PUBLIC_SCRIPT_H + +#include + +SB_EXTERN_C_BEGIN + +/** + * Constants that specify the script of a character. + */ +enum { + SBScriptNil = 0x00, + + SBScriptZINH = 0x01, /**< Inherited */ + SBScriptZYYY = 0x02, /**< Common */ + SBScriptZZZZ = 0x03, /**< Unknown */ + + /* Unicode 1.1 */ + SBScriptARAB = 0x04, /**< Arabic */ + SBScriptARMN = 0x05, /**< Armenian */ + SBScriptBENG = 0x06, /**< Bengali */ + SBScriptBOPO = 0x07, /**< Bopomofo */ + SBScriptCYRL = 0x08, /**< Cyrillic */ + SBScriptDEVA = 0x09, /**< Devanagari */ + SBScriptGEOR = 0x0A, /**< Georgian */ + SBScriptGREK = 0x0B, /**< Greek */ + SBScriptGUJR = 0x0C, /**< Gujarati */ + SBScriptGURU = 0x0D, /**< Gurmukhi */ + SBScriptHANG = 0x0E, /**< Hangul */ + SBScriptHANI = 0x0F, /**< Han */ + SBScriptHEBR = 0x10, /**< Hebrew */ + SBScriptHIRA = 0x11, /**< Hiragana */ + SBScriptKANA = 0x12, /**< Katakana */ + SBScriptKNDA = 0x13, /**< Kannada */ + SBScriptLAOO = 0x14, /**< Lao */ + SBScriptLATN = 0x15, /**< Latin */ + SBScriptMLYM = 0x16, /**< Malayalam */ + SBScriptORYA = 0x17, /**< Oriya */ + SBScriptTAML = 0x18, /**< Tamil */ + SBScriptTELU = 0x19, /**< Telugu */ + SBScriptTHAI = 0x1A, /**< Thai */ + + /* Unicode 2.0 */ + SBScriptTIBT = 0x1B, /**< Tibetan */ + + /* Unicode 3.0 */ + SBScriptBRAI = 0x1C, /**< Braille */ + SBScriptCANS = 0x1D, /**< Canadian_Aboriginal */ + SBScriptCHER = 0x1E, /**< Cherokee */ + SBScriptETHI = 0x1F, /**< Ethiopic */ + SBScriptKHMR = 0x20, /**< Khmer */ + SBScriptMONG = 0x21, /**< Mongolian */ + SBScriptMYMR = 0x22, /**< Myanmar */ + SBScriptOGAM = 0x23, /**< Ogham */ + SBScriptRUNR = 0x24, /**< Runic */ + SBScriptSINH = 0x25, /**< Sinhala */ + SBScriptSYRC = 0x26, /**< Syriac */ + SBScriptTHAA = 0x27, /**< Thaana */ + SBScriptYIII = 0x28, /**< Yi */ + + /* Unicode 3.1 */ + SBScriptDSRT = 0x29, /**< Deseret */ + SBScriptGOTH = 0x2A, /**< Gothic */ + SBScriptITAL = 0x2B, /**< Old_Italic */ + + /* Unicode 3.2 */ + SBScriptBUHD = 0x2C, /**< Buhid */ + SBScriptHANO = 0x2D, /**< Hanunoo */ + SBScriptTAGB = 0x2E, /**< Tagbanwa */ + SBScriptTGLG = 0x2F, /**< Tagalog */ + + /* Unicode 4.0 */ + SBScriptCPRT = 0x30, /**< Cypriot */ + SBScriptLIMB = 0x31, /**< Limbu */ + SBScriptLINB = 0x32, /**< Linear_B */ + SBScriptOSMA = 0x33, /**< Osmanya */ + SBScriptSHAW = 0x34, /**< Shavian */ + SBScriptTALE = 0x35, /**< Tai_Le */ + SBScriptUGAR = 0x36, /**< Ugaritic */ + + /* Unicode 4.1 */ + SBScriptBUGI = 0x37, /**< Buginese */ + SBScriptCOPT = 0x38, /**< Coptic */ + SBScriptGLAG = 0x39, /**< Glagolitic */ + SBScriptKHAR = 0x3A, /**< Kharoshthi */ + SBScriptSYLO = 0x3B, /**< Syloti_Nagri */ + SBScriptTALU = 0x3C, /**< New_Tai_Lue */ + SBScriptTFNG = 0x3D, /**< Tifinagh */ + SBScriptXPEO = 0x3E, /**< Old_Persian */ + + /* Unicode 5.0 */ + SBScriptBALI = 0x3F, /**< Balinese */ + SBScriptNKOO = 0x40, /**< Nko */ + SBScriptPHAG = 0x41, /**< Phags_Pa */ + SBScriptPHNX = 0x42, /**< Phoenician */ + SBScriptXSUX = 0x43, /**< Cuneiform */ + + /* Unicode 5.1 */ + SBScriptCARI = 0x44, /**< Carian */ + SBScriptCHAM = 0x45, /**< Cham */ + SBScriptKALI = 0x46, /**< Kayah_Li */ + SBScriptLEPC = 0x47, /**< Lepcha */ + SBScriptLYCI = 0x48, /**< Lycian */ + SBScriptLYDI = 0x49, /**< Lydian */ + SBScriptOLCK = 0x4A, /**< Ol_Chiki */ + SBScriptRJNG = 0x4B, /**< Rejang */ + SBScriptSAUR = 0x4C, /**< Saurashtra */ + SBScriptSUND = 0x4D, /**< Sundanese */ + SBScriptVAII = 0x4E, /**< Vai */ + + /* Unicode 5.2 */ + SBScriptARMI = 0x4F, /**< Imperial_Aramaic */ + SBScriptAVST = 0x50, /**< Avestan */ + SBScriptBAMU = 0x51, /**< Bamum */ + SBScriptEGYP = 0x52, /**< Egyptian_Hieroglyphs */ + SBScriptJAVA = 0x53, /**< Javanese */ + SBScriptKTHI = 0x54, /**< Kaithi */ + SBScriptLANA = 0x55, /**< Tai_Tham */ + SBScriptLISU = 0x56, /**< Lisu */ + SBScriptMTEI = 0x57, /**< Meetei_Mayek */ + SBScriptORKH = 0x58, /**< Old_Turkic */ + SBScriptPHLI = 0x59, /**< Inscriptional_Pahlavi */ + SBScriptPRTI = 0x5A, /**< Inscriptional_Parthian */ + SBScriptSAMR = 0x5B, /**< Samaritan */ + SBScriptSARB = 0x5C, /**< Old_South_Arabian */ + SBScriptTAVT = 0x5D, /**< Tai_Viet */ + + /* Unicode 6.0 */ + SBScriptBATK = 0x5E, /**< Batak */ + SBScriptBRAH = 0x5F, /**< Brahmi */ + SBScriptMAND = 0x60, /**< Mandaic */ + + /* Unicode 6.1 */ + SBScriptCAKM = 0x61, /**< Chakma */ + SBScriptMERC = 0x62, /**< Meroitic_Cursive */ + SBScriptMERO = 0x63, /**< Meroitic_Hieroglyphs */ + SBScriptPLRD = 0x64, /**< Miao */ + SBScriptSHRD = 0x65, /**< Sharada */ + SBScriptSORA = 0x66, /**< Sora_Sompeng */ + SBScriptTAKR = 0x67, /**< Takri */ + + /* Unicode 7.0 */ + SBScriptAGHB = 0x68, /**< Caucasian_Albanian */ + SBScriptBASS = 0x69, /**< Bassa_Vah */ + SBScriptDUPL = 0x6A, /**< Duployan */ + SBScriptELBA = 0x6B, /**< Elbasan */ + SBScriptGRAN = 0x6C, /**< Grantha */ + SBScriptHMNG = 0x6D, /**< Pahawh_Hmong */ + SBScriptKHOJ = 0x6E, /**< Khojki */ + SBScriptLINA = 0x6F, /**< Linear_A */ + SBScriptMAHJ = 0x70, /**< Mahajani */ + SBScriptMANI = 0x71, /**< Manichaean */ + SBScriptMEND = 0x72, /**< Mende_Kikakui */ + SBScriptMODI = 0x73, /**< Modi */ + SBScriptMROO = 0x74, /**< Mro */ + SBScriptNARB = 0x75, /**< Old_North_Arabian */ + SBScriptNBAT = 0x76, /**< Nabataean */ + SBScriptPALM = 0x77, /**< Palmyrene */ + SBScriptPAUC = 0x78, /**< Pau_Cin_Hau */ + SBScriptPERM = 0x79, /**< Old_Permic */ + SBScriptPHLP = 0x7A, /**< Psalter_Pahlavi */ + SBScriptSIDD = 0x7B, /**< Siddham */ + SBScriptSIND = 0x7C, /**< Khudawadi */ + SBScriptTIRH = 0x7D, /**< Tirhuta */ + SBScriptWARA = 0x7E, /**< Warang_Citi */ + + /* Unicode 8.0 */ + SBScriptAHOM = 0x7F, /**< Ahom */ + SBScriptHATR = 0x80, /**< Hatran */ + SBScriptHLUW = 0x81, /**< Anatolian_Hieroglyphs */ + SBScriptHUNG = 0x82, /**< Old_Hungarian */ + SBScriptMULT = 0x83, /**< Multani */ + SBScriptSGNW = 0x84, /**< SignWriting */ + + /* Unicode 9.0 */ + SBScriptADLM = 0x85, /**< Adlam */ + SBScriptBHKS = 0x86, /**< Bhaiksuki */ + SBScriptMARC = 0x87, /**< Marchen */ + SBScriptNEWA = 0x88, /**< Newa */ + SBScriptOSGE = 0x89, /**< Osage */ + SBScriptTANG = 0x8A, /**< Tangut */ + + /* Unicode 10.0 */ + SBScriptGONM = 0x8B, /**< Masaram_Gondi */ + SBScriptNSHU = 0x8C, /**< Nushu */ + SBScriptSOYO = 0x8D, /**< Soyombo */ + SBScriptZANB = 0x8E, /**< Zanabazar_Square */ + + /* Unicode 11.0 */ + SBScriptDOGR = 0x8F, /**< Dogra */ + SBScriptGONG = 0x90, /**< Gunjala_Gondi */ + SBScriptMAKA = 0x91, /**< Makasar */ + SBScriptMEDF = 0x92, /**< Medefaidrin */ + SBScriptROHG = 0x93, /**< Hanifi_Rohingya */ + SBScriptSOGD = 0x94, /**< Sogdian */ + SBScriptSOGO = 0x95, /**< Old_Sogdian */ + + /* Unicode 12.0 */ + SBScriptELYM = 0x96, /**< Elymaic */ + SBScriptHMNP = 0x97, /**< Nyiakeng_Puachue_Hmong */ + SBScriptNAND = 0x98, /**< Nandinagari */ + SBScriptWCHO = 0x99, /**< Wancho */ + + /* Unicode 13.0 */ + SBScriptCHRS = 0x9A, /**< Chorasmian */ + SBScriptDIAK = 0x9B, /**< Dives_Akuru */ + SBScriptKITS = 0x9C, /**< Khitan_Small_Script */ + SBScriptYEZI = 0x9D, /**< Yezidi */ + + /* Unicode 14.0 */ + SBScriptCPMN = 0x9E, /**< Cypro_Minoan */ + SBScriptOUGR = 0x9F, /**< Old_Uyghur */ + SBScriptTNSA = 0xA0, /**< Tangsa */ + SBScriptTOTO = 0xA1, /**< Toto */ + SBScriptVITH = 0xA2, /**< Vithkuqi */ + + /* Unicode 15.1 */ + SBScriptKAWI = 0xA3, /**< Kawi */ + SBScriptNAGM = 0xA4, /**< Nag_Mundari */ + + /* Unicode 16.0 */ + SBScriptGARA = 0xA5, /**< Garay */ + SBScriptGUKH = 0xA6, /**< Gurung_Khema */ + SBScriptKRAI = 0xA7, /**< Kirat_Rai */ + SBScriptONAO = 0xA8, /**< Ol_Onal */ + SBScriptSUNU = 0xA9, /**< Sunuwar */ + SBScriptTODR = 0xAA, /**< Todhri */ + SBScriptTUTG = 0xAB, /**< Tulu_Tigalari */ + + /* Unicode 17.0 */ + SBScriptBERF = 0xAC, /**< Beria_Erfe */ + SBScriptSIDT = 0xAD, /**< Sidetic */ + SBScriptTAYO = 0xAE, /**< Tai_Yo */ + SBScriptTOLS = 0xAF /**< Tolong_Siki */ +}; + +/** + * A type to represent the script of a character. + */ +typedef SBUInt8 SBScript; + +/** + * Returns the OpenType tag of a script as UInt32 in big endian byte order. The association between + * Unicode Script property and OpenType script tags is taken from the specification: + * https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags. + * + * If more than one tag is associated with a script, then the latest one is retured. For example, + * Devanagari script has two tags, `deva` and `dev2`. So in this case, `dev2` will be returned. + * + * If no tag is associated with a script, then `DFLT` is returned. + * + * @param script + * The script whose OpenType tag is returned. + * @return + * The OpenType tag of specified script as UInt32 in big endian byte order. + */ +SB_DEPRECATED +SB_PUBLIC SBUInt32 SBScriptGetOpenTypeTag(SBScript script); + +/** + * Returns the 4-letter Unicode Script abbreviation tag for a given SBScript value. + * + * The tag is returned as a UInt32 value in big-endian byte order (e.g., 'Arab' is 0x41726162), + * suitable for use in shaping engines and script tagging. + * + * The tag is based on the Unicode Script property aliases as defined in PropertyValueAliases.txt, + * section: "sc" (Script). + * + * @param script + * The SBScript enum value. + * @return + * A big-endian UInt32 representing the 4-letter script tag, or 0 if the script has no + * associated tag. + */ +SB_PUBLIC SBUInt32 SBScriptGetUnicodeTag(SBScript script); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScriptLocator.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScriptLocator.h new file mode 100644 index 000000000..f3231b2a9 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBScriptLocator.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_SCRIPT_LOCATOR_H +#define _SB_PUBLIC_SCRIPT_LOCATOR_H + +#include +#include +#include + +SB_EXTERN_C_BEGIN + +typedef struct _SBScriptLocator *SBScriptLocatorRef; + +/** + * A structure containing the information about a run of code points having same script. + */ +typedef struct _SBScriptAgent { + SBUInteger offset; /**< The index to the first code unit of the run in source string. */ + SBUInteger length; /**< The number of code units covering the length of the run. */ + SBScript script; /**< The script of the run. */ +} SBScriptAgent; + +/** + * Creates a script locator object which can be used to find script runs in a string. + * + * @return + * A reference to a script locator object. + */ +SB_PUBLIC SBScriptLocatorRef SBScriptLocatorCreate(void); + +/** + * Loads a code point sequence in the locator so that its script runs can be located. + * + * @param locator + * The locator in which the code point sequence will be loaded. + * @param codepointSequence + * The code point sequence which will be loaded in the locator. + */ +SB_PUBLIC void SBScriptLocatorLoadCodepoints(SBScriptLocatorRef locator, + const SBCodepointSequence *codepointSequence); + +/** + * Returns the agent containing the information of current located script run. + * + * @param locator + * The locator whose agent is returned. + */ +SB_PUBLIC const SBScriptAgent *SBScriptLocatorGetAgent(SBScriptLocatorRef locator); + +/** + * Instructs the locator to find next script run in the loaded code point sequence. + * + * @param locator + * The locator whom you want to instruct. + * @return + * SBTrue if another script run is available, SBFalse otherwise. + * @note + * The locator will be reset after locating last script run. + */ +SB_PUBLIC SBBoolean SBScriptLocatorMoveNext(SBScriptLocatorRef locator); + +/** + * Instructs the locator to reset itself so that script runs of the loaded line can be obatained + * from the beginning. + * + * @param locator + * The locator whom you want to reset. + */ +SB_PUBLIC void SBScriptLocatorReset(SBScriptLocatorRef locator); + +/** + * Increments the reference count of a script locator object. + * + * @param locator + * The script locator object whose reference count will be incremented. + * @return + * The same script locator object passed in as the parameter. + */ +SB_PUBLIC SBScriptLocatorRef SBScriptLocatorRetain(SBScriptLocatorRef locator); + +/** + * Decrements the reference count of a script locator object. The object will be deallocated when + * its reference count reaches zero. + * + * @param locator + * The script locator object whose reference count will be decremented. + */ +SB_PUBLIC void SBScriptLocatorRelease(SBScriptLocatorRef locator); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SBVersion.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBVersion.h new file mode 100644 index 000000000..f2b81bf7e --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SBVersion.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_PUBLIC_VERSION_H +#define _SB_PUBLIC_VERSION_H + +#include + +SB_EXTERN_C_BEGIN + +#define SHEENBIDI_VERSION_MAJOR 2 +#define SHEENBIDI_VERSION_MINOR 9 +#define SHEENBIDI_VERSION_PATCH 0 +#define SHEENBIDI_VERSION_STRING "2.9.0" + +/** + * Returns the version string of the SheenBidi library. + * + * This function returns a constant null-terminated string representing the version of the linked + * SheenBidi library, in the format "MAJOR.MINOR.PATCH". + * + * @return A string representing the version (e.g. "2.9.0"). + */ +SB_PUBLIC const char *SBVersionGetString(void); + +SB_EXTERN_C_END + +#endif diff --git a/src/thirdparty/SheenBidi/Headers/SheenBidi/SheenBidi.h b/src/thirdparty/SheenBidi/Headers/SheenBidi/SheenBidi.h new file mode 100644 index 000000000..2b8e37734 --- /dev/null +++ b/src/thirdparty/SheenBidi/Headers/SheenBidi/SheenBidi.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SHEENBIDI_H +#define _SHEENBIDI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/src/thirdparty/SheenBidi/LICENSE b/src/thirdparty/SheenBidi/LICENSE new file mode 100755 index 000000000..d64569567 --- /dev/null +++ b/src/thirdparty/SheenBidi/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/thirdparty/SheenBidi/README.md b/src/thirdparty/SheenBidi/README.md new file mode 100644 index 000000000..1e8a3dd55 --- /dev/null +++ b/src/thirdparty/SheenBidi/README.md @@ -0,0 +1,174 @@ +# SheenBidi + +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Linux CI](https://github.com/Tehreer/SheenBidi/actions/workflows/linux.yml/badge.svg)](https://github.com/Tehreer/SheenBidi/actions/workflows/linux.yml) +[![macOS CI](https://github.com/Tehreer/SheenBidi/actions/workflows/macos.yml/badge.svg)](https://github.com/Tehreer/SheenBidi/actions/workflows/macos.yml) +[![Windows CI](https://github.com/Tehreer/SheenBidi/actions/workflows/windows.yml/badge.svg)](https://github.com/Tehreer/SheenBidi/actions/workflows/windows.yml) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/k2vvegcdqsb9ld5a?svg=true)](https://ci.appveyor.com/project/mta452/sheenbidi) +[![Coverage Status](https://coveralls.io/repos/github/Tehreer/SheenBidi/badge.svg?branch=master)](https://coveralls.io/github/Tehreer/SheenBidi) + +SheenBidi is a lightweight, fast and stable implementation of the [Unicode Bidirectional Algorithm (UBA)](https://unicode.org/reports/tr9/). + +It is being used by multiple open source and commercial projects in different domains such as: +- **Games:** [SuperTuxKart](https://github.com/supertuxkart/stk-code), [VVVVVV](https://github.com/TerryCavanagh/VVVVVV), [DevilutionX](https://github.com/diasurgical/DevilutionX), [Watch Dogs: Legion](https://www.mobygames.com/game/152206/watch-dogs-legion/), [Monaco 2](https://www.mobygames.com/game/240348/monaco-2/) +- **Audio:** [JUCE](https://github.com/juce-framework/JUCE), [Tracktion Engine](https://github.com/Tracktion/tracktion_engine), [d&b En-Space](https://www.dbaudio.com/global/en/solutions/enabling-technologies/sound-design/en-space/) +- **Mapping:** [VTS Browser](https://github.com/melowntech/vts-browser-cpp) +- **Animation:** [Rive Runtime](https://github.com/rive-app/rive-runtime) +- **Text Processing:** [Raqm](https://github.com/HOST-Oman/libraqm), [Rich Text](https://github.com/forenoonwatch/rich-text), [Tehreer Android](https://github.com/Tehreer/Tehreer-Android), [Tehreer Cocoa](https://github.com/Tehreer/Tehreer-Cocoa) +- **Web:** [Dropflow](https://github.com/chearon/dropflow), [Itemizer](https://github.com/chearon/itemizer) + +*If you use SheenBidi in your project, I’d love to hear about it!* + +## Features +- **Object Based Design:** Facilitates modular and maintainable code. +- **Core Level Optimization:** Ensures high performance. +- **Thread Safe Architecture:** Suitable for multithreaded applications. +- **Lightweight API:** Simplifies integration. +- **Encoding Support:** UTF-8, UTF-16, and UTF-32. + +## API Overview + + +The above diagram provides a visual representation of the API applied to sample text. + +### SBCodepointSequence +Decodes a string buffer in a specified encoding into code points. + +### SBAlgorithm +Determines the bidirectional type of each code unit in the source string. It identifies paragraph boundaries as per rule [P1](https://www.unicode.org/reports/tr9/#P1) and allows creation of paragraph objects with explicit base levels or derived from rules [P2](https://www.unicode.org/reports/tr9/#P2)-[P3](https://www.unicode.org/reports/tr9/#P3). + +### SBParagraph +Represents a single paragraph processed with rules [X1](https://www.unicode.org/reports/tr9/#X1)-[I2](https://www.unicode.org/reports/tr9/#I2), providing resolved embedding levels for all code units. + +### SBLine +Represents a line of text processed with rules [L1](https://www.unicode.org/reports/tr9/#L1)-[L2](https://www.unicode.org/reports/tr9/#L2), offering reordered level runs instead of individual characters. + +### SBRun +Denotes a sequence of characters sharing the same embedding level. A run's direction is right-to-left if its embedding level is odd. + +### SBMirrorLocator +Identifies mirrored characters in a line as determined by rule [L4](https://www.unicode.org/reports/tr9/#L4). + +### SBScriptLocator +Assists in text shaping by locating script runs as specified in [UAX #24](https://www.unicode.org/reports/tr24/). + +## Dependency +SheenBidi relies solely on standard C library headers: `stddef.h`, `stdint.h`, and `stdlib.h`. + +## Configuration +Configuration options are available in `Headers/SBConfig.h`: + +- `SB_CONFIG_LOG`: Logs activities performed during the bidirectional algorithm application. +- `SB_CONFIG_UNITY`: Builds the library as a single module, allowing the compiler to inline functions. + +## Compiling +SheenBidi can be compiled with any C compiler. The recommended approach is to add all files to an IDE and build. If `SB_CONFIG_UNITY` is enabled, only `Source/SheenBidi.c` should be compiled. + +### CMake +To build and install SheenBidi using CMake: + +```bash +cmake -S. -Bbuild-release -DCMAKE_BUILD_TYPE=Release +cmake --build build-release +sudo cmake --install build-release +``` + +For development and testing: + +```bash +cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DSB_CONFIG_UNITY=OFF +cmake --build build +ctest --test-dir build --output-on-failure +``` + +In other CMake projects, SheenBidi can be found via `find_package(SheenBidi)`, providing the target `SheenBidi::SheenBidi`. SheenBidi can also be used via `FetchContent`. + +### Meson +To build and install SheenBidi using Meson: + +```bash +meson setup builddir --buildtype=release +meson compile -C builddir +sudo meson install -C builddir +``` + +For testing: + +```bash +meson setup builddir -Dunity_mode=disabled +meson test -C builddir --print-errorlogs +``` + +## Example +A simple example in C11. + +```c +#include +#include +#include + +#include + +int main(int argc, const char * argv[]) { + /* Create code point sequence for a sample bidirectional text. */ + const char *bidiText = "یہ ایک )car( ہے۔"; + SBCodepointSequence codepointSequence = { SBStringEncodingUTF8, (void *)bidiText, strlen(bidiText) }; + + /* Extract the first bidirectional paragraph. */ + SBAlgorithmRef bidiAlgorithm = SBAlgorithmCreate(&codepointSequence); + SBParagraphRef firstParagraph = SBAlgorithmCreateParagraph(bidiAlgorithm, 0, INT32_MAX, SBLevelDefaultLTR); + SBUInteger paragraphLength = SBParagraphGetLength(firstParagraph); + + /* Create a line consisting of the whole paragraph and get its runs. */ + SBLineRef paragraphLine = SBParagraphCreateLine(firstParagraph, 0, paragraphLength); + SBUInteger runCount = SBLineGetRunCount(paragraphLine); + const SBRun *runArray = SBLineGetRunsPtr(paragraphLine); + + /* Log the details of each run in the line. */ + for (SBUInteger i = 0; i < runCount; i++) { + printf("Run Offset: %ld\n", (long)runArray[i].offset); + printf("Run Length: %ld\n", (long)runArray[i].length); + printf("Run Level: %ld\n\n", (long)runArray[i].level); + } + + /* Create a mirror locator and load the line in it. */ + SBMirrorLocatorRef mirrorLocator = SBMirrorLocatorCreate(); + SBMirrorLocatorLoadLine(mirrorLocator, paragraphLine, (void *)bidiText); + const SBMirrorAgent *mirrorAgent = SBMirrorLocatorGetAgent(mirrorLocator); + + /* Log the details of each mirror in the line. */ + while (SBMirrorLocatorMoveNext(mirrorLocator)) { + printf("Mirror Index: %ld\n", (long)mirrorAgent->index); + printf("Actual Code Point: %ld\n", (long)mirrorAgent->codepoint); + printf("Mirrored Code Point: %ld\n\n", (long)mirrorAgent->mirror); + } + + /* Release all objects. */ + SBMirrorLocatorRelease(mirrorLocator); + SBLineRelease(paragraphLine); + SBParagraphRelease(firstParagraph); + SBAlgorithmRelease(bidiAlgorithm); + + return 0; +} +``` + +## Support +If SheenBidi plays a role in your project, you’re welcome to [star the repository](https://github.com/Tehreer/SheenBidi/stargazers) or [contribute improvements](https://github.com/Tehreer/SheenBidi/pulls). Engagement from the community helps inform future development and ensures continued relevance. + +## License +``` +Copyright (C) 2014-2025 Muhammad Tayyab Akram + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/src/thirdparty/SheenBidi/Source/AtomicFlag.h b/src/thirdparty/SheenBidi/Source/AtomicFlag.h new file mode 100644 index 000000000..11d9b3c2a --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/AtomicFlag.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ATOMIC_FLAG_H +#define _SB_INTERNAL_ATOMIC_FLAG_H + +#include "SBBase.h" + +/* Define data type for atomic flag. */ +#ifdef USE_C11_ATOMICS + +#include +#define HAS_ATOMIC_FLAG_SUPPORT +typedef atomic_flag AtomicFlag; + +#elif defined(USE_ATOMIC_BUILTINS) || defined(USE_SYNC_BUILTINS) + +#define HAS_ATOMIC_FLAG_SUPPORT +typedef SBBoolean AtomicFlag; + +#elif defined(USE_WIN_INTRINSICS) + +#include +#define HAS_ATOMIC_FLAG_SUPPORT +#pragma intrinsic(_InterlockedExchange8) +typedef volatile char AtomicFlag; + +#elif defined(USE_WIN_INTERLOCKED) + +#include +#define HAS_ATOMIC_FLAG_SUPPORT +typedef volatile LONG AtomicFlag; + +#else + +typedef SBBoolean AtomicFlag; + +#endif + +typedef AtomicFlag *AtomicFlagRef; + +/* Define functions for atomic flag. */ +#if defined(USE_C11_ATOMICS) + +#define AtomicFlagMake() ATOMIC_FLAG_INIT +#define AtomicFlagTestAndSet(flag) ((SBBoolean)atomic_flag_test_and_set(flag)) +#define AtomicFlagClear(flag) atomic_flag_clear(flag) + +#elif defined(USE_ATOMIC_BUILTINS) + +#define AtomicFlagMake() SBFalse +#define AtomicFlagTestAndSet(flag) __atomic_test_and_set(flag, __ATOMIC_SEQ_CST) +#define AtomicFlagClear(flag) __atomic_clear(flag, __ATOMIC_SEQ_CST) + +#elif defined(USE_SYNC_BUILTINS) + +#define AtomicFlagMake() SBFalse +#define AtomicFlagTestAndSet(flag) __sync_lock_test_and_set(flag, SBTrue) +#define AtomicFlagClear(flag) __sync_lock_release(flag) + +#elif defined(USE_WIN_INTRINSICS) + +#define AtomicFlagMake() 0 +#define AtomicFlagTestAndSet(flag) (_InterlockedExchange8(flag, 1) == 1) +#define AtomicFlagClear(flag) _InterlockedExchange8(flag, 0) + +#elif defined(USE_WIN_INTERLOCKED) + +#define AtomicFlagMake() 0 +#define AtomicFlagTestAndSet(flag) (InterlockedExchange(flag, 1) == 1) +#define AtomicFlagClear(flag) InterlockedExchange(flag, 0) + +#else /* Non-atomic fallback */ + +#define AtomicFlagMake() SBFalse +#define AtomicFlagTestAndSet(flag) (*(flag) ? SBTrue : (*(flag) = SBTrue, SBFalse)) +#define AtomicFlagClear(flag) (*(flag) = SBFalse) + +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Source/AtomicPointer.h b/src/thirdparty/SheenBidi/Source/AtomicPointer.h new file mode 100644 index 000000000..ff2c9f0f2 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/AtomicPointer.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ATOMIC_POINTER_H +#define _SB_INTERNAL_ATOMIC_POINTER_H + +#include "SBBase.h" + +/* Define data type for atomic pointer. */ +#ifdef USE_C11_ATOMICS + +#include +#define HAS_ATOMIC_POINTER_SUPPORT +typedef _Atomic(void *) AtomicPointer; +#define AtomicPointerType(type) _Atomic(type *) + +#elif defined(USE_ATOMIC_BUILTINS) || defined(USE_SYNC_BUILTINS) + +#define HAS_ATOMIC_POINTER_SUPPORT +typedef void *AtomicPointer; +#define AtomicPointerType(type) type * + +#elif defined(USE_WIN_INTRINSICS) + +#include +#define HAS_ATOMIC_POINTER_SUPPORT +#pragma intrinsic(_InterlockedExchangePointer, _InterlockedCompareExchangePointer) +typedef void * volatile AtomicPointer; +#define AtomicPointerType(type) type * volatile + +#elif defined(USE_WIN_INTERLOCKED) + +#include +#define HAS_ATOMIC_POINTER_SUPPORT +typedef void * volatile AtomicPointer; +#define AtomicPointerType(type) type * volatile + +#else + +typedef void *AtomicPointer; +#define AtomicPointerType(type) type * + +#endif + +typedef AtomicPointer *AtomicPointerRef; + +/* Define functions for atomic pointer. */ +#if defined(USE_C11_ATOMICS) + +#define AtomicPointerLoad(pointer) \ + atomic_load(pointer) +#define AtomicPointerStore(pointer, value) \ + atomic_store(pointer, value) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + atomic_compare_exchange_strong(pointer, expected, desired) + +#elif defined(USE_ATOMIC_BUILTINS) + +#define AtomicPointerLoad(pointer) \ + __atomic_load_n(pointer, __ATOMIC_SEQ_CST) +#define AtomicPointerStore(pointer, value) \ + __atomic_store_n(pointer, value, __ATOMIC_SEQ_CST) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + __atomic_compare_exchange_n(pointer, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) + +#elif defined(USE_SYNC_BUILTINS) + +#define AtomicPointerLoad(pointer) \ + __sync_fetch_and_add(pointer, 0) +#define AtomicPointerStore(pointer, value) \ + __sync_lock_test_and_set(pointer, value) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + __sync_bool_compare_and_swap(pointer, *(expected), desired) + +#elif defined(USE_WIN_INTRINSICS) + +#define AtomicPointerLoad(pointer) \ + _InterlockedCompareExchangePointer((AtomicPointerRef)(pointer), NULL, NULL) +#define AtomicPointerStore(pointer, value) \ + _InterlockedExchangePointer((AtomicPointerRef)(pointer), (void *)(value)) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + (_InterlockedCompareExchangePointer((AtomicPointerRef)(pointer), (void *)(desired), (void *)(*(expected))) == *(expected)) + +#elif defined(USE_WIN_INTERLOCKED) + +#ifdef _WIN64 +#define AtomicPointerLoad(pointer) \ + ((void *)InterlockedCompareExchange64((LONG64 volatile *)(pointer), 0, 0)) +#define AtomicPointerStore(pointer, value) \ + InterlockedExchange64((LONG64 volatile *)(pointer), (LONG64)(value)) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + (((void *)InterlockedCompareExchange64((LONG64 volatile *)(pointer), (LONG64)(desired), (LONG64)(*(expected)))) == *(expected)) +#else +#define AtomicPointerLoad(pointer) \ + ((void *)InterlockedCompareExchange((LONG volatile *)(pointer), 0, 0)) +#define AtomicPointerStore(pointer, value) \ + InterlockedExchange((LONG volatile *)(pointer), (LONG)(value)) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + (((void *)InterlockedCompareExchange((LONG volatile *)(pointer), (LONG)(desired), (LONG)(*(expected)))) == *(expected)) +#endif + +#else /* Non-atomic fallback */ + +#define AtomicPointerLoad(pointer) \ + (*(pointer)) +#define AtomicPointerStore(pointer, value) \ + (*(pointer) = (value)) +#define AtomicPointerCompareAndSet(pointer, expected, desired) \ + ((*(pointer) == *(expected)) ? ((*(pointer) = (desired)), SBTrue) : SBFalse) + +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Source/AtomicUInt.h b/src/thirdparty/SheenBidi/Source/AtomicUInt.h new file mode 100644 index 000000000..b892aba45 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/AtomicUInt.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ATOMIC_UINT_H +#define _SB_INTERNAL_ATOMIC_UINT_H + +#include "SBBase.h" + +/* Define data type for atomic uint. */ +#ifdef USE_C11_ATOMICS + +#include +#define HAS_ATOMIC_UINT_SUPPORT +typedef _Atomic(SBUInteger) AtomicUInt; + +#elif defined(USE_ATOMIC_BUILTINS) || defined(USE_SYNC_BUILTINS) + +#define HAS_ATOMIC_UINT_SUPPORT +typedef SBUInteger AtomicUInt; + +#elif defined(USE_WIN_INTRINSICS) + +#include +#define HAS_ATOMIC_UINT_SUPPORT +#ifdef _WIN64 +#pragma intrinsic(_InterlockedExchange64, _InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedIncrement64, _InterlockedDecrement64) +typedef volatile __int64 AtomicUInt; +#else +#pragma intrinsic(_InterlockedExchange, _InterlockedCompareExchange) +#pragma intrinsic(_InterlockedIncrement, _InterlockedDecrement) +typedef volatile long AtomicUInt; +#endif + +#elif defined(USE_WIN_INTERLOCKED) + +#include +#define HAS_ATOMIC_UINT_SUPPORT +#ifdef _WIN64 +typedef volatile LONG64 AtomicUInt; +#else +typedef volatile LONG AtomicUInt; +#endif + +#else + +typedef SBUInteger AtomicUInt; + +#endif + +typedef AtomicUInt *AtomicUIntRef; + +/* Define functions for atomic uint. */ +#if defined(USE_C11_ATOMICS) + +#define AtomicUIntInitialize(aui, value) atomic_init(aui, value) +#define AtomicUIntLoad(aui) atomic_load(aui) +#define AtomicUIntStore(aui, value) atomic_store(aui, value) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + atomic_compare_exchange_strong(aui, expected, desired) +#define AtomicUIntIncrement(aui) ((SBUInteger)(atomic_fetch_add(aui, 1) + 1)) +#define AtomicUIntDecrement(aui) ((SBUInteger)(atomic_fetch_sub(aui, 1) - 1)) + +#elif defined(USE_ATOMIC_BUILTINS) + +#define AtomicUIntInitialize(aui, value) (*(aui) = (value)) +#define AtomicUIntLoad(aui) __atomic_load_n(aui, __ATOMIC_SEQ_CST) +#define AtomicUIntStore(aui, value) __atomic_store_n(aui, value, __ATOMIC_SEQ_CST) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + __atomic_compare_exchange_n(aui, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define AtomicUIntIncrement(aui) __atomic_add_fetch(aui, 1, __ATOMIC_SEQ_CST) +#define AtomicUIntDecrement(aui) __atomic_sub_fetch(aui, 1, __ATOMIC_SEQ_CST) + +#elif defined(USE_SYNC_BUILTINS) + +#define AtomicUIntInitialize(aui, value) (*(aui) = (value)) +#define AtomicUIntLoad(aui) __sync_fetch_and_add(aui, 0) +#define AtomicUIntStore(aui, value) __sync_lock_test_and_set(aui, value) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + __sync_bool_compare_and_swap(aui, *(expected), desired) +#define AtomicUIntIncrement(aui) __sync_add_and_fetch(aui, 1) +#define AtomicUIntDecrement(aui) __sync_sub_and_fetch(aui, 1) + +#elif defined(USE_WIN_INTRINSICS) + +#ifdef _WIN64 +#define AtomicUIntInitialize(aui, value) (*(aui) = (__int64)(value)) +#define AtomicUIntLoad(aui) ((SBUInteger)_InterlockedCompareExchange64(aui, 0, 0)) +#define AtomicUIntStore(aui, value) _InterlockedExchange64(aui, (__int64)(value)) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + (((SBUInteger)_InterlockedCompareExchange64(aui, (__int64)(desired), (__int64)(*(expected)))) == *(expected)) +#define AtomicUIntIncrement(aui) ((SBUInteger)_InterlockedIncrement64(aui)) +#define AtomicUIntDecrement(aui) ((SBUInteger)_InterlockedDecrement64(aui)) +#else +#define AtomicUIntInitialize(aui, value) (*(aui) = (long)(value)) +#define AtomicUIntLoad(aui) ((SBUInteger)_InterlockedCompareExchange(aui, 0, 0)) +#define AtomicUIntStore(aui, value) _InterlockedExchange(aui, (long)(value)) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + (((SBUInteger)_InterlockedCompareExchange(aui, (long)(desired), (long)(*(expected)))) == *(expected)) +#define AtomicUIntIncrement(aui) ((SBUInteger)_InterlockedIncrement(aui)) +#define AtomicUIntDecrement(aui) ((SBUInteger)_InterlockedDecrement(aui)) +#endif + +#elif defined(USE_WIN_INTERLOCKED) + +#ifdef _WIN64 +#define AtomicUIntInitialize(aui, value) (*(aui) = (LONG64)(value)) +#define AtomicUIntLoad(aui) ((SBUInteger)InterlockedCompareExchange64(aui, 0, 0)) +#define AtomicUIntStore(aui, value) InterlockedExchange64(aui, (LONG64)(value)) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + (((SBUInteger)InterlockedCompareExchange64(aui, (LONG64)(desired), (LONG64)(*(expected)))) == *(expected)) +#define AtomicUIntIncrement(aui) ((SBUInteger)InterlockedIncrement64(aui)) +#define AtomicUIntDecrement(aui) ((SBUInteger)InterlockedDecrement64(aui)) +#else +#define AtomicUIntInitialize(aui, value) (*(aui) = (LONG)(value)) +#define AtomicUIntLoad(aui) ((SBUInteger)InterlockedCompareExchange(aui, 0, 0)) +#define AtomicUIntStore(aui, value) InterlockedExchange(aui, (LONG)(value)) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + (((SBUInteger)InterlockedCompareExchange(aui, (LONG)(desired), (LONG)(*(expected)))) == *(expected)) +#define AtomicUIntIncrement(aui) ((SBUInteger)InterlockedIncrement(aui)) +#define AtomicUIntDecrement(aui) ((SBUInteger)InterlockedDecrement(aui)) +#endif + +#else /* Non-atomic fallback */ + +#define AtomicUIntInitialize(aui, value) (*(aui) = (value)) +#define AtomicUIntLoad(aui) (*(aui)) +#define AtomicUIntCompareAndSet(aui, expected, desired) \ + ((*(aui) == *(expected)) ? ((*(aui) = (desired)), SBTrue) : SBFalse) +#define AtomicUIntStore(aui, value) (*(aui) = (value)) +#define AtomicUIntIncrement(aui) (++(*(aui))) +#define AtomicUIntDecrement(aui) (--(*(aui))) + +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Source/BidiChain.c b/src/thirdparty/SheenBidi/Source/BidiChain.c new file mode 100644 index 000000000..694cf14c5 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BidiChain.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "SBBase.h" +#include "BidiChain.h" + +SB_INTERNAL void BidiChainInitialize(BidiChainRef chain, + SBBidiType *types, SBLevel *levels, BidiFlag *flags, BidiLink *links) +{ + chain->types = types; + chain->levels = levels; + chain->flags = flags; + chain->links = links; + chain->roller = 0; + chain->last = 0; + + /* Make first link empty. */ + chain->types[0] = SBBidiTypeNil; + chain->levels[0] = SBLevelInvalid; + chain->flags[0] = BidiFlagNone; + chain->links[0] = BidiLinkNone; +} + +SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger lastLinkLength) +{ + BidiLink last = chain->last; + BidiLink current = last + (SBUInt32)lastLinkLength; + + chain->types[current] = type; + chain->flags[current] = BidiFlagNone; + chain->links[current] = chain->roller; + + if (lastLinkLength == 1) { + chain->flags[last] |= BidiFlagSingle; + } + + chain->links[last] = current; + chain->last = current; +} + +SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link) +{ + return chain->flags[link] & BidiFlagSingle; +} + +SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link) +{ + return chain->types[link]; +} + +SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type) +{ + chain->types[link] = type; +} + +SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link) +{ + return chain->levels[link]; +} + +SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level) +{ + chain->levels[link] = level; +} + +SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link) +{ + return chain->links[link]; +} + +SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next) +{ + chain->links[link] = next; +} + +SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link) +{ + BidiLink next = chain->links[link]; + BidiLink limit = chain->links[next]; + + chain->links[link] = limit; +} + +SB_INTERNAL void BidiChainAbsorbNext(BidiChainRef chain, BidiLink link) +{ + BidiLink next = chain->links[link]; + + chain->links[link] = chain->links[next]; + chain->flags[link] &= ~BidiFlagSingle; +} + +SB_INTERNAL SBBoolean BidiChainMergeNext(BidiChainRef chain, BidiLink link) +{ + BidiLink next = chain->links[link]; + + if (chain->types[link] == chain->types[next] + && chain->levels[link] == chain->levels[next]) { + BidiChainAbsorbNext(chain, link); + return SBTrue; + } + + return SBFalse; +} diff --git a/src/thirdparty/SheenBidi/Source/BidiChain.h b/src/thirdparty/SheenBidi/Source/BidiChain.h new file mode 100644 index 000000000..a55055917 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BidiChain.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_BIDI_CHAIN_H +#define _SB_INTERNAL_BIDI_CHAIN_H + +#include + +#include "SBBase.h" + +typedef SBUInt32 BidiLink; + +#define BidiLinkNone (SBUInt32)(-1) + +enum { + BidiFlagNone = 0x00, + BidiFlagSingle = 0x01 +}; +typedef SBUInt8 BidiFlag; + +typedef struct _BidiChain { + SBBidiType *types; + SBLevel *levels; + BidiFlag *flags; + BidiLink *links; + BidiLink roller; + BidiLink last; +} BidiChain, *BidiChainRef; + +SB_INTERNAL void BidiChainInitialize(BidiChainRef chain, + SBBidiType *types, SBLevel *levels, BidiFlag *flags, BidiLink *links); +SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger lastLinkLength); + +#define BidiChainGetOffset(chain, link) \ +( \ + (link) - 1 \ +) + +SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link); + +SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type); + +SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level); + +SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next); +SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link); +SB_INTERNAL void BidiChainAbsorbNext(BidiChainRef chain, BidiLink link); +SB_INTERNAL SBBoolean BidiChainMergeNext(BidiChainRef chain, BidiLink link); + +#define BidiChainForEach(chain, roller, link) \ + for (link = chain->links[roller]; link != roller; link = chain->links[link]) + +#endif diff --git a/src/thirdparty/SheenBidi/Source/BidiTypeLookup.c b/src/thirdparty/SheenBidi/Source/BidiTypeLookup.c new file mode 100644 index 000000000..9b058f634 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BidiTypeLookup.c @@ -0,0 +1,1088 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 4816+(2880*2)+(1088*2) = 12752 Bytes + */ + +#include "BidiTypeLookup.h" + +#define AL SBBidiTypeAL +#define AN SBBidiTypeAN +#define B SBBidiTypeB +#define BN SBBidiTypeBN +#define CS SBBidiTypeCS +#define EN SBBidiTypeEN +#define ES SBBidiTypeES +#define ET SBBidiTypeET +#define FSI SBBidiTypeFSI +#define L SBBidiTypeL +#define LRE SBBidiTypeLRE +#define LRI SBBidiTypeLRI +#define LRO SBBidiTypeLRO +#define NSM SBBidiTypeNSM +#define ON SBBidiTypeON +#define PDF SBBidiTypePDF +#define PDI SBBidiTypePDI +#define R SBBidiTypeR +#define RLE SBBidiTypeRLE +#define RLI SBBidiTypeRLI +#define RLO SBBidiTypeRLO +#define S SBBidiTypeS +#define WS SBBidiTypeWS + +static const SBUInt8 PrimaryBidiTypeData[4816] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, S, B, S, WS, B, BN, BN, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, B, B, B, S, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + WS, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, CS, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, BN, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + BN, BN, BN, BN, BN, B, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + CS, ON, ET, ET, ET, ET, ON, ON, ON, ON, L, ON, ON, BN, ON, ON, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + ET, ET, EN, EN, ON, L, ON, ON, ON, EN, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + L, L, L, L, ON, ON, L, L, L, L, L, L, L, L, ON, L, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + L, L, L, L, ON, ON, L, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + L, L, L, L, L, L, ON, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + L, L, L, L, L, L, L, L, L, L, ON, L, L, ON, ON, ET, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + R, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, NSM, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + R, NSM, NSM, R, NSM, NSM, R, NSM, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + AN, AN, AN, AN, AN, AN, ON, ON, AL, ET, ET, AL, CS, AL, ON, ON, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, ET, AN, AN, AL, AL, AL, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, AN, ON, NSM, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + NSM, NSM, NSM, NSM, NSM, AL, AL, NSM, NSM, ON, NSM, NSM, NSM, NSM, AL, AL, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + AL, NSM, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + R, R, R, R, R, R, R, R, R, R, R, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + NSM, NSM, NSM, NSM, R, R, ON, ON, ON, ON, R, R, R, NSM, R, R, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + R, R, R, R, R, R, NSM, NSM, NSM, NSM, R, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + NSM, NSM, NSM, NSM, R, NSM, NSM, NSM, R, NSM, NSM, NSM, NSM, NSM, R, R, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + R, R, R, R, R, R, R, R, R, NSM, NSM, NSM, R, R, R, R, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + AN, AN, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + NSM, NSM, AN, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + L, L, ET, ET, L, L, L, L, L, L, L, ET, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + L, NSM, NSM, L, L, L, L, NSM, NSM, L, L, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + NSM, NSM, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + L, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + L, ET, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + L, L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + NSM, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + L, L, L, ON, ON, ON, ON, ON, ON, ET, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + NSM, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + NSM, L, L, L, L, L, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + L, L, L, L, L, L, L, L, L, L, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + L, L, NSM, NSM, NSM, L, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, ET, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + L, L, L, L, L, NSM, L, NSM, L, NSM, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + L, L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + L, L, L, L, L, L, L, L, NSM, NSM, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + L, L, NSM, L, L, NSM, NSM, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + WS, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + L, L, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + L, L, L, L, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + L, L, L, L, L, L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, ET, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, NSM, NSM, NSM, BN, NSM, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + L, L, L, L, L, L, L, L, L, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + NSM, NSM, NSM, L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + L, L, NSM, L, L, L, L, L, L, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + ON, L, L, L, ON, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + L, L, L, L, L, L, L, NSM, NSM, L, L, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + L, L, L, L, L, L, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + NSM, L, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + L, L, L, L, NSM, L, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + L, L, L, L, L, L, NSM, L, NSM, NSM, L, L, L, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + L, L, L, L, NSM, L, L, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, L, ON, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + ON, ON, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, L, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + WS, WS, WS, WS, WS, WS, WS, WS, WS, WS, WS, BN, BN, BN, L, R, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, WS, B, LRE, RLE, PDF, LRO, RLO, CS, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + ET, ET, ET, ET, ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + ON, ON, ON, ON, CS, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, WS, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + BN, BN, BN, BN, BN, BN, LRI, RLI, FSI, PDI, BN, BN, BN, BN, BN, BN, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + EN, L, L, L, EN, EN, EN, EN, EN, EN, ES, ES, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ES, ES, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, ET, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + ON, ON, L, ON, ON, ON, ON, L, ON, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + L, L, L, L, ON, L, ON, ON, ON, L, L, L, L, L, ON, ON, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + ON, ON, ON, ON, L, ON, L, ON, L, ON, L, L, L, L, ET, L, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + L, L, L, L, L, L, L, L, L, L, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + ON, ON, ON, ON, ON, L, L, L, L, L, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + L, L, L, L, L, L, L, L, L, ON, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + ON, ON, ES, ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + ON, ON, ON, ON, ON, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, L, L, L, L, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + ON, ON, ON, ON, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + NSM, NSM, L, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + WS, ON, ON, ON, ON, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + ON, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + ON, L, L, L, L, L, ON, ON, L, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + L, L, L, L, L, L, L, L, L, L, L, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, ON, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + L, L, L, L, L, L, L, ON, ON, ON, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, ON, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + NSM, NSM, NSM, ON, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, ON, ON, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + ON, ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + L, L, L, L, L, L, L, L, ON, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + L, L, NSM, L, L, L, NSM, L, L, L, L, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + L, L, L, L, L, NSM, NSM, L, ON, ON, ON, ON, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + L, L, L, L, L, L, L, L, ET, ET, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + L, L, L, L, ON, ON, ON, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + L, L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + L, L, L, NSM, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + L, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + L, L, L, NSM, L, L, L, L, L, L, L, L, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + NSM, L, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + L, L, L, L, L, NSM, L, L, NSM, L, L, L, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, R, NSM, R, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + R, R, R, R, R, R, R, R, R, ES, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + AL, AL, AL, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + ON, ON, ON, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, ON, ON, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + ON, ON, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + AL, AL, AL, AL, AL, AL, AL, AL, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, ON, ON, ON, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + CS, ON, CS, L, ON, CS, ON, ON, ON, ON, ON, ON, ON, ON, ON, ET, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + ON, ON, ES, ES, ON, ON, ON, L, ON, ET, ET, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, BN, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + L, ON, ON, ET, ET, ET, ON, ON, ON, ON, ON, ES, CS, ES, CS, CS, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + ET, ET, ON, ON, ON, ET, ET, L, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + BN, BN, BN, BN, BN, BN, BN, BN, BN, ON, ON, ON, ON, ON, BN, BN, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + L, ON, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + NSM, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + R, R, R, R, R, R, R, R, R, R, R, R, R, R, R, ON, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + R, NSM, NSM, NSM, R, NSM, NSM, R, R, R, R, R, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + R, R, R, R, R, R, R, R, NSM, NSM, NSM, R, R, R, R, NSM, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + R, R, R, R, R, NSM, NSM, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + R, R, R, R, R, R, R, R, R, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + AL, AL, AL, AL, NSM, NSM, NSM, NSM, AL, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + R, R, R, R, R, R, R, R, R, NSM, NSM, NSM, NSM, NSM, ON, R, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, AN, R, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + R, R, R, R, R, R, R, R, R, R, R, NSM, NSM, R, R, R, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, AL, AL, AL, AL, AL, AL, AL, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + R, R, NSM, NSM, NSM, NSM, R, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + NSM, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + NSM, NSM, L, L, NSM, L, NSM, NSM, L, L, L, L, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + NSM, L, NSM, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, L, NSM, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + NSM, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + L, L, NSM, NSM, NSM, NSM, L, L, L, L, L, L, NSM, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, L, L, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, L, NSM, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + L, L, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, NSM, L, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + L, L, L, L, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, L, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + L, L, L, L, L, L, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + NSM, L, NSM, NSM, NSM, L, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + NSM, L, NSM, NSM, L, NSM, NSM, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, NSM, L, NSM, NSM, L, NSM, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + NSM, NSM, L, L, L, NSM, L, NSM, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + L, L, L, NSM, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + L, L, L, L, L, ON, ON, ON, ON, ON, ON, ON, ON, ET, ET, ET, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + ET, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + NSM, L, L, L, L, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + L, L, ON, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, NSM, NSM, L, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + BN, BN, BN, BN, L, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ON, ON, ON, L, L, L, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + ON, ON, ON, ON, L, L, L, L, L, L, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + L, L, L, L, L, L, L, NSM, NSM, NSM, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + L, L, L, BN, BN, BN, BN, BN, BN, BN, BN, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + L, L, L, L, L, L, L, L, L, L, NSM, NSM, NSM, NSM, L, L, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + ON, ON, NSM, NSM, NSM, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + L, L, L, L, L, ON, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + L, L, L, L, L, L, L, L, L, ON, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + L, L, L, ON, L, L, L, L, L, L, L, L, L, L, EN, EN, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + L, L, L, L, NSM, L, L, L, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, NSM, L, L, NSM, NSM, NSM, NSM, NSM, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + NSM, NSM, L, NSM, NSM, L, NSM, NSM, NSM, NSM, NSM, L, L, L, L, L, +/* DATA_BLOCK: -- 0x11B0..0x11BF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, ET, +/* DATA_BLOCK: -- 0x11C0..0x11CF -- */ + L, L, L, NSM, L, L, NSM, L, L, L, L, L, L, L, NSM, NSM, +/* DATA_BLOCK: -- 0x11D0..0x11DF -- */ + NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, R, R, R, R, R, R, R, R, +/* DATA_BLOCK: -- 0x11E0..0x11EF -- */ + R, R, R, R, NSM, NSM, NSM, NSM, NSM, NSM, NSM, R, R, R, R, R, +/* DATA_BLOCK: -- 0x11F0..0x11FF -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, +/* DATA_BLOCK: -- 0x1200..0x120F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, +/* DATA_BLOCK: -- 0x1210..0x121F -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x1220..0x122F -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, ON, L, L, +/* DATA_BLOCK: -- 0x1230..0x123F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x1240..0x124F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1250..0x125F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, L, L, L, +/* DATA_BLOCK: -- 0x1260..0x126F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, ON, ON, +/* DATA_BLOCK: -- 0x1270..0x127F -- */ + ON, ON, ON, ON, ON, ON, ON, L, ON, L, L, L, L, ON, ON, ON, +/* DATA_BLOCK: -- 0x1280..0x128F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, ON, +/* DATA_BLOCK: -- 0x1290..0x129F -- */ + ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, L, L, L, L, ON, +/* DATA_BLOCK: -- 0x12A0..0x12AF -- */ + ON, ON, ON, L, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, ON, +/* DATA_BLOCK: -- 0x12B0..0x12BF -- */ + EN, EN, EN, EN, EN, EN, EN, EN, EN, EN, ON, L, L, L, L, L, +/* DATA_BLOCK: -- 0x12C0..0x12CF -- */ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, BN, BN +}; + +static const SBUInt16 MainBidiTypeIndexes[2880] = { +/* INDEX_BLOCK: -- 0x0000..0x003F -- */ + 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0040, 0x0060, 0x0070, 0x0080, 0x0090, 0x00A0, + 0x00B0, 0x00C0, 0x00B0, 0x00C0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00E0, 0x00E0, 0x00F0, 0x0100, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0120, 0x0130, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x0140, +/* INDEX_BLOCK: -- 0x0040..0x007F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0150, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0160, 0x0170, 0x0110, 0x0180, 0x0190, 0x01A0, 0x01A0, 0x01A0, 0x01B0, 0x01C0, 0x01D0, 0x01D0, + 0x01E0, 0x0110, 0x01F0, 0x0200, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0210, 0x0220, 0x0230, + 0x01D0, 0x0240, 0x01D0, 0x0110, 0x01C0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0250, 0x0200, + 0x01A0, 0x01A0, 0x0260, 0x0270, +/* INDEX_BLOCK: -- 0x0080..0x00BF -- */ + 0x01A0, 0x0280, 0x0290, 0x01A0, 0x01A0, 0x02A0, 0x01D0, 0x01D0, 0x01D0, 0x02B0, 0x01D0, 0x01D0, + 0x02C0, 0x0110, 0x02D0, 0x0110, 0x02E0, 0x00B0, 0x00B0, 0x02F0, 0x0300, 0x0310, 0x0320, 0x00B0, + 0x0330, 0x00B0, 0x00B0, 0x0340, 0x0350, 0x00B0, 0x0320, 0x0360, 0x0370, 0x00B0, 0x00B0, 0x0340, + 0x0380, 0x0330, 0x00B0, 0x0390, 0x0370, 0x00B0, 0x00B0, 0x0340, 0x03A0, 0x00B0, 0x0320, 0x03B0, + 0x0330, 0x00B0, 0x00B0, 0x03C0, 0x0350, 0x03D0, 0x0320, 0x00B0, 0x03E0, 0x00B0, 0x00B0, 0x00B0, + 0x03F0, 0x00B0, 0x00B0, 0x0400, +/* INDEX_BLOCK: -- 0x00C0..0x00FF -- */ + 0x0410, 0x00B0, 0x00B0, 0x0420, 0x0430, 0x03D0, 0x0320, 0x0440, 0x0330, 0x00B0, 0x00B0, 0x0340, + 0x0450, 0x00B0, 0x0320, 0x00B0, 0x0460, 0x00B0, 0x00B0, 0x0470, 0x0350, 0x00B0, 0x0320, 0x00B0, + 0x0330, 0x00B0, 0x00B0, 0x00B0, 0x0480, 0x0490, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x04A0, + 0x04B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x04C0, 0x04D0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x04E0, 0x00B0, 0x04F0, 0x00B0, 0x00B0, 0x00B0, 0x0500, 0x0510, 0x0520, 0x0110, 0x0530, + 0x0540, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0100..0x013F -- */ + 0x00B0, 0x00B0, 0x0550, 0x0560, 0x00B0, 0x0570, 0x0580, 0x0590, 0x05A0, 0x05B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0550, 0x00B0, 0x00B0, 0x00B0, 0x05C0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0140..0x017F -- */ + 0x0040, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x05D0, 0x05E0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x05F0, 0x00B0, 0x0320, 0x00B0, 0x0320, 0x00B0, 0x0320, 0x00B0, 0x00B0, 0x00B0, 0x0600, + 0x0610, 0x0620, 0x00B0, 0x05C0, +/* INDEX_BLOCK: -- 0x0180..0x01BF -- */ + 0x0630, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x03D0, 0x00B0, 0x0640, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0650, 0x0660, 0x0670, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0680, 0x0100, 0x0100, 0x00B0, 0x0690, 0x00B0, 0x00B0, + 0x00B0, 0x06A0, 0x06B0, 0x06C0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x06D0, 0x06E0, 0x00B0, + 0x06F0, 0x00B0, 0x00B0, 0x0700, 0x03E0, 0x00B0, 0x0710, 0x06F0, 0x0460, 0x00B0, 0x0720, 0x00B0, + 0x00B0, 0x00B0, 0x0730, 0x0460, +/* INDEX_BLOCK: -- 0x01C0..0x01FF -- */ + 0x00B0, 0x00B0, 0x0740, 0x0750, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0760, 0x0770, 0x0780, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0110, 0x0110, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0790, + 0x07A0, 0x07B0, 0x07B0, 0x07C0, +/* INDEX_BLOCK: -- 0x0200..0x023F -- */ + 0x07D0, 0x0100, 0x07E0, 0x07F0, 0x0800, 0x0810, 0x0820, 0x0830, 0x0840, 0x00B0, 0x0850, 0x0850, + 0x0850, 0x0110, 0x0110, 0x0580, 0x0860, 0x0870, 0x0880, 0x0890, 0x08A0, 0x0100, 0x00B0, 0x00B0, + 0x08B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x08C0, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x08D0, 0x00B0, 0x00B0, 0x00B0, 0x0050, 0x0100, 0x08E0, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0240..0x027F -- */ + 0x0100, 0x0100, 0x05C0, 0x00B0, 0x08F0, 0x00B0, 0x0100, 0x0100, 0x0900, 0x0910, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0920, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0930, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0280..0x02BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0940, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x02C0..0x02FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0950, 0x0960, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0970, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0980, 0x00B0, 0x00B0, 0x0100, 0x0990, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x09A0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x08D0, 0x00B0, 0x0100, +/* INDEX_BLOCK: -- 0x0300..0x033F -- */ + 0x09B0, 0x0100, 0x09C0, 0x09D0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x09E0, 0x0040, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x09F0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0A00, 0x00B0, 0x00B0, 0x07C0, 0x00B0, 0x00B0, + 0x00B0, 0x0100, 0x00B0, 0x0A10, 0x00B0, 0x00B0, 0x00B0, 0x0A20, 0x0A30, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A40, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0680, 0x00B0, 0x0A50, +/* INDEX_BLOCK: -- 0x0340..0x037F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0380..0x03BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x03C0..0x03FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, + 0x0A60, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x07B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0970, 0x0A70, 0x00B0, 0x0A80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0460, + 0x0100, 0x0100, 0x0A90, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0AA0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0400..0x043F -- */ + 0x0AB0, 0x00B0, 0x0AC0, 0x0AD0, 0x00B0, 0x00B0, 0x00B0, 0x0AE0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0AF0, 0x00B0, 0x0110, 0x0B00, 0x00B0, 0x00B0, 0x0B10, 0x00B0, 0x0B20, 0x0460, 0x00B0, 0x00B0, + 0x02E0, 0x00B0, 0x00B0, 0x0B30, 0x00B0, 0x00B0, 0x0B40, 0x00B0, 0x00B0, 0x00B0, 0x0B50, 0x0B60, + 0x0B70, 0x00B0, 0x00B0, 0x0340, 0x00B0, 0x00B0, 0x00B0, 0x0B80, 0x0330, 0x00B0, 0x0450, 0x0540, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0890, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0B90, 0x00B0, +/* INDEX_BLOCK: -- 0x0440..0x047F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0BA0, 0x0BB0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x0BC0, 0x0BD0, 0x01D0, 0x01D0, +/* INDEX_BLOCK: -- 0x0480..0x04BF -- */ + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0BE0, 0x0100, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x0BF0, 0x01D0, 0x01D0, 0x0C00, 0x0080, 0x0080, 0x0C10, 0x0110, 0x05C0, 0x0110, 0x0100, + 0x0100, 0x0C20, 0x0C30, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0C40, + 0x0C50, 0x0030, 0x0040, 0x0050, 0x0040, 0x0050, 0x08D0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0C60, 0x0C70, +/* INDEX_BLOCK: -- 0x04C0..0x04FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0C80, 0x00B0, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0C90, 0x0C90, 0x0040, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x05B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0CA0, 0x0910, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0CB0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0500..0x053F -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0CC0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0CD0, 0x01A0, 0x01A0, 0x0CE0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x0CF0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x0D00, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0540..0x057F -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x0D10, 0x0D20, 0x0D30, 0x01A0, 0x0D40, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x0D50, 0x0D60, 0x01A0, 0x01A0, 0x0D70, 0x01A0, 0x01D0, 0x0D80, 0x01D0, 0x02C0, + 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x0250, 0x0200, 0x01D0, 0x01A0, 0x0D90, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0580..0x05BF -- */ + 0x0330, 0x00B0, 0x00B0, 0x0DA0, 0x0DB0, 0x00E0, 0x08D0, 0x0DC0, 0x0460, 0x00B0, 0x00B0, 0x0DD0, + 0x03E0, 0x00B0, 0x00B0, 0x00B0, 0x02E0, 0x00B0, 0x0DE0, 0x0DF0, 0x00B0, 0x00B0, 0x00B0, 0x0E00, + 0x0460, 0x00B0, 0x00B0, 0x0E10, 0x0E20, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0970, 0x0E30, + 0x0330, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0970, 0x0E40, 0x00B0, + 0x0460, 0x00B0, 0x00B0, 0x0470, 0x0580, 0x00B0, 0x0E50, 0x0DF0, 0x00B0, 0x00B0, 0x00B0, 0x0710, + 0x0E60, 0x0E70, 0x0370, 0x00B0, +/* INDEX_BLOCK: -- 0x05C0..0x05FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x0DA0, 0x0490, 0x0E80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E90, + 0x0EA0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x0EB0, 0x0580, 0x0450, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0EC0, + 0x0580, 0x00B0, 0x0C90, 0x00B0, 0x00B0, 0x00B0, 0x0ED0, 0x0EE0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x0EF0, 0x0F00, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0600..0x063F -- */ + 0x00B0, 0x00B0, 0x0970, 0x0F10, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0F20, 0x0E00, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0F30, 0x0580, 0x00B0, 0x0F40, 0x00B0, 0x00B0, 0x0F50, + 0x0F60, 0x0F70, 0x00B0, 0x00B0, 0x0F80, 0x0F90, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0FA0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0640..0x067F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x0FB0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0FC0, 0x0FD0, 0x0FE0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0FF0, 0x0EE0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x1000, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x1010, + 0x0460, 0x00B0, 0x00B0, 0x0CB0, 0x0E70, 0x0480, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x1020, 0x1030, 0x0A90, +/* INDEX_BLOCK: -- 0x0680..0x06BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x1040, 0x1050, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x06C0..0x06FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A80, 0x1060, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0700..0x073F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0DF0, + 0x00B0, 0x00B0, 0x00B0, 0x0DB0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0740..0x077F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0970, 0x00B0, 0x00B0, 0x00B0, 0x0970, 0x02E0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x1070, 0x00B0, +/* INDEX_BLOCK: -- 0x0780..0x07BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x1080, 0x1090, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x07C0..0x07FF -- */ + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x08D0, 0x00B0, 0x10A0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x10B0, 0x0100, 0x0040, 0x0100, 0x0040, + 0x0110, 0x0110, 0x06D0, 0x0110, 0x0DB0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0800..0x083F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x10C0, 0x10D0, + 0x10E0, 0x00B0, 0x10F0, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, + 0x1100, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0A60, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0840..0x087F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0C80, 0x09F0, 0x00B0, 0x09F0, + 0x00B0, 0x1110, 0x00B0, 0x1110, 0x0A50, 0x00B0, 0x0A50, 0x00B0, 0x1120, 0x00B0, 0x1120, 0x00B0, + 0x1130, 0x1140, 0x1140, 0x1140, +/* INDEX_BLOCK: -- 0x0880..0x08BF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0110, 0x0110, 0x0110, 0x1150, + 0x0110, 0x0110, 0x0530, 0x0B40, 0x1160, 0x0710, 0x1170, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x08C0..0x08FF -- */ + 0x1180, 0x1190, 0x11A0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0970, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0DB0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0E80, 0x00B0, 0x00B0, 0x00B0, 0x0740, 0x11B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0900..0x093F -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x0740, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x0A80, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x11C0, 0x0B40, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, +/* INDEX_BLOCK: -- 0x0940..0x097F -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x11D0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x11E0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x0980..0x09BF -- */ + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, + 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x01D0, 0x0BF0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, 0x01A0, + 0x01A0, 0x01A0, 0x01A0, 0x01A0, +/* INDEX_BLOCK: -- 0x09C0..0x09FF -- */ + 0x0100, 0x0100, 0x11F0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x09A0, 0x1200, 0x0A20, + 0x0A20, 0x0A20, 0x0100, 0x08D0, 0x1210, 0x00B0, 0x0A50, 0x00B0, 0x00B0, 0x00B0, 0x0920, 0x00B0, + 0x00B0, 0x00B0, 0x1220, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x08D0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, +/* INDEX_BLOCK: -- 0x0A00..0x0A3F -- */ + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x1230, 0x0C90, 0x0C90, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x05C0, 0x11F0, 0x0040, +/* INDEX_BLOCK: -- 0x0A40..0x0A7F -- */ + 0x11F0, 0x0100, 0x0100, 0x0100, 0x1240, 0x05C0, 0x0100, 0x0100, 0x1240, 0x0100, 0x0980, 0x11F0, + 0x0A90, 0x1250, 0x00B0, 0x00B0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x1240, 0x0980, 0x0C90, 0x1260, 0x0100, 0x0100, 0x0100, 0x1270, 0x1280, 0x1290, 0x1250, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x12A0, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x12B0, +/* INDEX_BLOCK: -- 0x0A80..0x0ABF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x00B0, 0x00B0, 0x00B0, 0x12C0, +/* INDEX_BLOCK: -- 0x0AC0..0x0AFF -- */ + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, + 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0110, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, +/* INDEX_BLOCK: -- 0x0B00..0x0B3F -- */ + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080 +}; + +static const SBUInt16 BranchBidiTypeIndexes[1088] = { + 0x0000, 0x0040, 0x0080, 0x00C0, 0x0100, 0x0140, 0x0180, 0x01C0, 0x0200, 0x0240, 0x0280, 0x02C0, + 0x0300, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0380, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x03C0, 0x0400, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0440, 0x0480, 0x04C0, 0x0340, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0680, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x06C0, 0x0340, 0x0700, 0x0740, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0780, 0x0340, 0x0340, 0x0340, 0x07C0, 0x0800, 0x0840, 0x0880, 0x0340, + 0x08C0, 0x0900, 0x0940, 0x0980, 0x09C0, 0x0A00, 0x0A40, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, 0x0AC0, 0x0B00, 0x0B00, 0x0B00, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0A80 +}; + +SB_INTERNAL SBBidiType LookupBidiType(SBCodepoint codepoint) +{ + if (codepoint <= 0x10FFFF) { + return PrimaryBidiTypeData[ + MainBidiTypeIndexes[ + BranchBidiTypeIndexes[ + codepoint / 0x0400 + ] + (codepoint % 0x0400) / 0x0010 + ] + codepoint % 0x0010 + ]; + } + + return ON; +} + +#undef AL +#undef AN +#undef B +#undef BN +#undef CS +#undef EN +#undef ES +#undef ET +#undef FSI +#undef L +#undef LRE +#undef LRI +#undef LRO +#undef NSM +#undef ON +#undef PDF +#undef PDI +#undef R +#undef RLE +#undef RLI +#undef RLO +#undef S +#undef WS diff --git a/src/thirdparty/SheenBidi/Source/BidiTypeLookup.h b/src/thirdparty/SheenBidi/Source/BidiTypeLookup.h new file mode 100644 index 000000000..2ce0e00fd --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BidiTypeLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_BIDI_TYPE_LOOKUP_H +#define _SB_INTERNAL_BIDI_TYPE_LOOKUP_H + +#include +#include +#include +#include + +SB_INTERNAL SBBidiType LookupBidiType(SBCodepoint codepoint); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/BracketQueue.c b/src/thirdparty/SheenBidi/Source/BracketQueue.c new file mode 100644 index 000000000..8178dbec3 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BracketQueue.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "BidiChain.h" +#include "Memory.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "BracketQueue.h" + +#define MakeBracketQueuePosition() \ + { NULL, SBInvalidIndex } +#define SetBracketQueuePosition(bqp, _list, _index) \ + ((bqp).list = (_list), (bqp).index = (_index)) +#define IsInvalidBracketQueuePosition(bqp) \ + ((bqp).list == NULL) + +static const BracketQueuePosition InvalidBracketQueuePosition = MakeBracketQueuePosition(); + +#define LIST 0 +#define ELEMENTS 1 +#define COUNT 2 + +static BracketQueueElement *InsertBracketQueueElement(BracketQueueRef queue) +{ + BracketQueueListRef rearList = queue->_rearList; + BracketQueueElement *element = NULL; + + if ((queue->_rearTop + 1) < rearList->capacity) { + queue->_rearTop += 1; + queue->_actualCount += 1; + + element = &rearList->elements[queue->_rearTop]; + } else { + BracketQueueListRef previousList = rearList; + + rearList = previousList->next; + + if (!rearList) { + const SBUInteger capacity = queue->_actualCount; + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT]; + + sizes[LIST] = sizeof(BracketQueueList); + sizes[ELEMENTS] = sizeof(BracketQueueElement) * capacity; + + if (MemoryAllocateChunks(queue->_memory, MemoryTypeScratch, sizes, COUNT, pointers)) { + rearList = pointers[LIST]; + rearList->elements = pointers[ELEMENTS]; + rearList->capacity = capacity; + rearList->previous = previousList; + rearList->next = NULL; + + previousList->next = rearList; + } + } + + if (rearList) { + queue->_rearList = rearList; + queue->_rearTop = 0; + queue->_actualCount += 1; + + element = &rearList->elements[0]; + } + } + + return element; +} + +static void InvalidateOpenPairs(BracketQueueRef queue, BracketQueuePosition from) +{ + BracketQueueListRef rearList = queue->_rearList; + BracketQueueListRef breakList = rearList->next; + SBUInteger invalidCount = 0; + BracketQueuePosition current; + + current = from; + + do { + SBUInteger end = (current.list == rearList ? queue->_rearTop + 1 : current.list->capacity); + + while (current.index < end) { + BracketQueueElement *element = ¤t.list->elements[current.index]; + + if (element->openingLink != BidiLinkNone && element->closingLink == BidiLinkNone) { + element->openingLink = BidiLinkNone; + invalidCount += 1; + } + + current.index += 1; + } + + current.list = current.list->next; + current.index = 0; + } while (current.list != breakList); + + queue->_actualCount -= invalidCount; +} + +static void SkipToNextBracketPair(BracketQueueRef queue) +{ + BracketQueueListRef rearList = queue->_rearList; + BracketQueueListRef breakList = rearList->next; + SBBoolean hasProcessedFirst = SBFalse; + BracketQueuePosition current; + + current = queue->_front; + + do { + SBUInteger end = (current.list == rearList ? queue->_rearTop + 1 : current.list->capacity); + + while (current.index < end) { + BracketQueueElement *element = ¤t.list->elements[current.index]; + + if (element->openingLink != BidiLinkNone && element->closingLink != BidiLinkNone) { + if (hasProcessedFirst) { + queue->_front = current; + return; + } + + queue->pairCount -= 1; + } + + hasProcessedFirst = SBTrue; + current.index += 1; + } + + current.list = current.list->next; + current.index = 0; + } while (current.list != breakList); + + /* No more pairs. */ + queue->_front = InvalidBracketQueuePosition; +} + +#undef LIST +#undef ELEMENTS +#undef COUNT + +SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue, MemoryRef memory) +{ + queue->_memory = memory; + + queue->_firstList.elements = queue->_elements; + queue->_firstList.capacity = BracketQueueEmbeddedElementCount; + queue->_firstList.previous = NULL; + queue->_firstList.next = NULL; + + BracketQueueReset(queue, SBBidiTypeNil); +} + +SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction) +{ + queue->_rearList = &queue->_firstList; + queue->_rearTop = SBInvalidIndex; + queue->_firstOpenPair = InvalidBracketQueuePosition; + queue->_front = InvalidBracketQueuePosition; + queue->_actualCount = 0; + queue->pairCount = 0; + queue->_direction = direction; + queue->_isPopulated = SBFalse; +} + +SB_INTERNAL void BracketQueueMarkPopulated(BracketQueueRef queue) +{ + SBAssert(!queue->_isPopulated); + + if (queue->pairCount > 0) { + BracketQueueElement *first = &queue->_firstList.elements[0]; + + SetBracketQueuePosition(queue->_front, &queue->_firstList, 0); + + if (first->openingLink == BidiLinkNone + || first->closingLink == BidiLinkNone) { + SkipToNextBracketPair(queue); + } + } + + queue->_actualCount = 0; + queue->_isPopulated = SBTrue; +} + +SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue, + BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket) +{ + SBBoolean isEnqueued = SBFalse; + BracketQueueElement *element; + + /* The queue must NOT be populated yet. */ + SBAssert(!queue->_isPopulated); + /* The queue can ONLY have a maximum of 63 open pairs. */ + SBAssert(BracketQueueGetOpenPairCount(queue) < BracketQueueMaxOpenPairs); + + element = InsertBracketQueueElement(queue); + + if (element) { + element->priorStrongLink = priorStrongLink; + element->openingLink = openingLink; + element->closingLink = BidiLinkNone; + element->bracket = bracket; + element->innerStrongType = SBBidiTypeNil; + + if (IsInvalidBracketQueuePosition(queue->_firstOpenPair)) { + SetBracketQueuePosition(queue->_firstOpenPair, queue->_rearList, queue->_rearTop); + } + + isEnqueued = SBTrue; + } + + return isEnqueued; +} + +SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue) +{ + /* The queue MUST be populated and NOT empty. */ + SBAssert(queue->_isPopulated && queue->pairCount > 0); + + SkipToNextBracketPair(queue); +} + +SB_INTERNAL SBUInteger BracketQueueGetOpenPairCount(BracketQueueRef queue) +{ + return (queue->_actualCount - queue->pairCount); +} + +SB_INTERNAL void BracketQueueAssignInnerStrongType(BracketQueueRef queue, SBBidiType strongType) +{ + BracketQueuePosition first = queue->_firstOpenPair; + + /* The queue must NOT be populated yet. */ + SBAssert(!queue->_isPopulated); + /* Passed-in bidi type MUST be valid. */ + SBAssert(strongType == SBBidiTypeL || strongType == SBBidiTypeR); + + /* Proceed if at least one open pair exists. */ + if (!IsInvalidBracketQueuePosition(first)) { + BracketQueueListRef rearList = queue->_rearList; + BracketQueueListRef breakList = first.list->previous; + BracketQueuePosition current; + + SetBracketQueuePosition(current, queue->_rearList, queue->_rearTop + 1); + + /* Assign the strong type to all open pairs. */ + do { + SBUInteger start = (current.list == first.list ? first.index : 0); + + if (current.list != rearList) { + current.index = current.list->capacity; + } + + while (current.index-- > start) { + BracketQueueElement *element = ¤t.list->elements[current.index]; + + if (element->closingLink == BidiLinkNone + && element->innerStrongType != queue->_direction) { + element->innerStrongType = strongType; + } + } + + current.list = current.list->previous; + } while (current.list != breakList); + } +} + +SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, + BidiLink closingLink, SBCodepoint bracket) +{ + BracketQueuePosition first = queue->_firstOpenPair; + + /* The queue must NOT be populated yet. */ + SBAssert(!queue->_isPopulated); + + /* Proceed if at least one open pair exists. */ + if (!IsInvalidBracketQueuePosition(first)) { + BracketQueueListRef rearList = queue->_rearList; + BracketQueueListRef breakList = first.list->previous; + BracketQueuePosition current; + + SetBracketQueuePosition(current, rearList, queue->_rearTop + 1); + + /* Find out the matching open pair. */ + do { + SBUInteger start = (current.list == first.list ? first.index : 0); + + if (current.list != rearList) { + current.index = current.list->capacity; + } + + while (current.index-- > start) { + BracketQueueElement *element = ¤t.list->elements[current.index]; + + if (element->openingLink != BidiLinkNone && element->closingLink == BidiLinkNone + && SBCodepointIsCanonicalEquivalentBracket(element->bracket, bracket)) { + element->closingLink = closingLink; + queue->pairCount += 1; + InvalidateOpenPairs(queue, current); + + if (queue->_firstOpenPair.list == current.list + && queue->_firstOpenPair.index == current.index) { + /* No open pair exists at this point. */ + queue->_firstOpenPair = InvalidBracketQueuePosition; + } + return; + } + } + + current.list = current.list->previous; + } while (current.list != breakList); + } +} + +SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue) +{ + return queue->_front.list->elements[queue->_front.index].priorStrongLink; +} + +SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue) +{ + return queue->_front.list->elements[queue->_front.index].openingLink; +} + +SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue) +{ + return queue->_front.list->elements[queue->_front.index].closingLink; +} + +SB_INTERNAL SBBidiType BracketQueueGetInnerStrongType(BracketQueueRef queue) +{ + return queue->_front.list->elements[queue->_front.index].innerStrongType; +} diff --git a/src/thirdparty/SheenBidi/Source/BracketQueue.h b/src/thirdparty/SheenBidi/Source/BracketQueue.h new file mode 100644 index 000000000..f07ac0a37 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BracketQueue.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_BRACKET_QUEUE_H +#define _SB_INTERNAL_BRACKET_QUEUE_H + +#include +#include +#include + +#include "BidiChain.h" +#include "Memory.h" + +#define BracketQueueEmbeddedElementCount 8 +#define BracketQueueMaxOpenPairs 63 + +typedef struct _BracketQueueElement { + SBCodepoint bracket; + BidiLink priorStrongLink; + BidiLink openingLink; + BidiLink closingLink; + SBBidiType innerStrongType; +} BracketQueueElement; + +typedef struct _BracketQueueList { + BracketQueueElement *elements; + SBUInteger capacity; + + struct _BracketQueueList *previous; + struct _BracketQueueList *next; +} BracketQueueList, *BracketQueueListRef; + +typedef struct _BracketQueuePosition { + BracketQueueListRef list; + SBUInteger index; +} BracketQueuePosition; + +typedef struct _BracketQueue { + MemoryRef _memory; + BracketQueueElement _elements[BracketQueueEmbeddedElementCount]; + BracketQueueList _firstList; + BracketQueueListRef _rearList; + SBUInteger _rearTop; + BracketQueuePosition _firstOpenPair; + BracketQueuePosition _front; + SBUInteger _actualCount; + SBUInteger pairCount; + SBBidiType _direction; + SBBoolean _isPopulated; +} BracketQueue, *BracketQueueRef; + +SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue, MemoryRef memory); +SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction); +SB_INTERNAL void BracketQueueMarkPopulated(BracketQueueRef queue); + +SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue, + BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket); +SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue); + +SB_INTERNAL SBUInteger BracketQueueGetOpenPairCount(BracketQueueRef queue); +SB_INTERNAL void BracketQueueAssignInnerStrongType(BracketQueueRef queue, SBBidiType strongType); +SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, + BidiLink closingLink, SBCodepoint bracket); + +SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue); +SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue); +SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue); +SB_INTERNAL SBBidiType BracketQueueGetInnerStrongType(BracketQueueRef queue); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/BracketType.h b/src/thirdparty/SheenBidi/Source/BracketType.h new file mode 100644 index 000000000..5f44e3479 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/BracketType.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_BRACKET_TYPE_H +#define _SB_INTERNAL_BRACKET_TYPE_H + +#include "SBBase.h" + +enum { + BracketTypeNone = 0x00, + BracketTypeOpen = 0x40, /**< Opening paired bracket. */ + BracketTypeClose = 0x80, /**< Closing paired bracket. */ + + BracketTypePrimaryMask = BracketTypeOpen | BracketTypeClose, + BracketTypeInverseMask = ~BracketTypePrimaryMask +}; +typedef SBUInt8 BracketType; + +#endif diff --git a/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.c b/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.c new file mode 100644 index 000000000..286cf1305 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.c @@ -0,0 +1,2087 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 11472+(4288*2)+(1088*2) = 22224 Bytes + */ + +#include "GeneralCategoryLookup.h" + +#define Cc SBGeneralCategoryCC +#define Cf SBGeneralCategoryCF +#define Cn SBGeneralCategoryCN +#define Co SBGeneralCategoryCO +#define Cs SBGeneralCategoryCS +#define Ll SBGeneralCategoryLL +#define Lm SBGeneralCategoryLM +#define Lo SBGeneralCategoryLO +#define Lt SBGeneralCategoryLT +#define Lu SBGeneralCategoryLU +#define Mc SBGeneralCategoryMC +#define Me SBGeneralCategoryME +#define Mn SBGeneralCategoryMN +#define Nd SBGeneralCategoryND +#define Nl SBGeneralCategoryNL +#define No SBGeneralCategoryNO +#define Pc SBGeneralCategoryPC +#define Pd SBGeneralCategoryPD +#define Pe SBGeneralCategoryPE +#define Pf SBGeneralCategoryPF +#define Pi SBGeneralCategoryPI +#define Po SBGeneralCategoryPO +#define Ps SBGeneralCategoryPS +#define Sc SBGeneralCategorySC +#define Sk SBGeneralCategorySK +#define Sm SBGeneralCategorySM +#define So SBGeneralCategorySO +#define Zl SBGeneralCategoryZL +#define Zp SBGeneralCategoryZP +#define Zs SBGeneralCategoryZS + +static const SBUInt8 PrimaryGeneralCategoryData[11472] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, Cc, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + Zs, Po, Po, Po, Sc, Po, Po, Po, Ps, Pe, Po, Sm, Po, Pd, Po, Po, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Sm, Sm, Sm, Po, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + Po, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ps, Po, Pe, Sk, Pc, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + Sk, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ps, Sm, Pe, Sm, Cc, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + Zs, Po, Sc, Sc, Sc, Sc, So, Po, Sk, So, Lo, Pi, Sm, Cf, So, Sk, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + So, Sm, No, No, Sk, Ll, Po, Po, Sk, No, Lo, Pf, No, No, No, Po, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + Ll, Lu, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Lu, Lu, Ll, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + Lu, Lu, Ll, Lu, Lu, Ll, Lu, Lu, Lu, Ll, Ll, Ll, Lu, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Ll, Ll, Lu, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + Ll, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Ll, Lo, Lu, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + Lo, Lo, Lo, Lo, Lu, Lt, Ll, Lu, Lt, Ll, Lu, Lt, Ll, Lu, Ll, Lu, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + Ll, Lu, Lt, Ll, Lu, Ll, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + Lu, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Ll, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + Ll, Lu, Ll, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + Ll, Ll, Ll, Ll, Lo, Lo, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + Lm, Lm, Sk, Sk, Sk, Sk, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + Lm, Lm, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + Lm, Lm, Lm, Lm, Lm, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Lm, Sk, Lm, Sk, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + Lu, Ll, Lu, Ll, Lm, Sk, Lu, Ll, Cn, Cn, Lm, Ll, Ll, Ll, Po, Lu, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + Cn, Cn, Cn, Cn, Sk, Sk, Lu, Po, Lu, Lu, Lu, Cn, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + Lu, Lu, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + Ll, Ll, Lu, Lu, Lu, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + Ll, Ll, Ll, Ll, Lu, Ll, Sm, Lu, Ll, Lu, Lu, Ll, Ll, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + Lu, Ll, So, Mn, Mn, Mn, Mn, Mn, Me, Me, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Lm, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Po, Pd, Cn, Cn, So, So, Sc, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Pd, Mn, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + Po, Mn, Mn, Po, Mn, Mn, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + Lo, Lo, Lo, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + Cf, Cf, Cf, Cf, Cf, Cf, Sm, Sm, Sm, Po, Po, Sc, Po, Po, So, So, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Cf, Po, Po, Po, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Po, Po, Lo, Lo, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + Lo, Lo, Lo, Lo, Po, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cf, So, Mn, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + Mn, Mn, Mn, Mn, Mn, Lm, Lm, Mn, Mn, So, Mn, Mn, Mn, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, So, So, Lo, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cf, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + Lo, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + Mn, Mn, Mn, Mn, Lm, Lm, So, Po, Po, Po, Lm, Cn, Cn, Mn, Sc, Sc, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + Mn, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Lm, Mn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Cn, Cn, Po, Cn, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sk, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + Cf, Cf, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + Mn, Mn, Cf, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + Mn, Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mc, Mc, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + Lo, Lo, Mn, Mn, Po, Po, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + Po, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + Lo, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + Lo, Cn, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mn, Lo, Cn, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + Lo, Lo, Mn, Mn, Cn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + Lo, Lo, Sc, Sc, No, No, No, No, No, No, So, Sc, Lo, Po, Mn, Cn, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + Cn, Mn, Mn, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Mn, Cn, Mc, Mc, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + Mc, Mn, Mn, Cn, Cn, Cn, Cn, Mn, Mn, Cn, Cn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + Cn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + Mn, Mn, Lo, Lo, Lo, Mn, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + Cn, Mn, Mn, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + Mc, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mc, Cn, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + Po, Sc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + Cn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mn, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mc, Cn, Cn, Cn, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + So, Lo, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + Cn, Cn, Mn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Cn, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + Cn, Cn, Cn, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Mc, Mc, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + Mn, Mc, Mc, Cn, Cn, Cn, Mc, Mc, Mc, Cn, Mc, Mc, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + No, No, No, So, So, So, So, So, So, Sc, So, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + Mn, Mc, Mc, Mc, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + Mn, Mc, Mc, Mc, Mc, Cn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + Cn, Cn, Cn, Cn, Cn, Mn, Mn, Cn, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, No, No, No, No, No, No, No, So, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + Lo, Mn, Mc, Mc, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Lo, Mc, Mn, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + Mc, Mc, Mc, Mc, Mc, Cn, Mn, Mc, Mc, Cn, Mc, Mc, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + Cn, Cn, Cn, Cn, Cn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + Cn, Lo, Lo, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + Mn, Mn, Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + Mc, Mn, Mn, Mn, Mn, Cn, Mc, Mc, Mc, Cn, Mc, Mc, Mc, Mn, Lo, So, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + Cn, Cn, Cn, Cn, Lo, Lo, Lo, Mc, No, No, No, No, No, No, No, Lo, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + No, No, No, No, No, No, No, No, No, So, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + Cn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Mn, Cn, Cn, Cn, Cn, Mc, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + Mc, Mc, Mn, Mn, Mn, Cn, Mn, Cn, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + Cn, Cn, Mc, Mc, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + Lo, Mn, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Sc, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lm, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + Lo, Mn, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Lm, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + Lo, So, So, So, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + Po, Po, Po, So, Po, So, So, So, Mn, Mn, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + No, No, No, No, So, Mn, So, Mn, So, Mn, Ps, Pe, Ps, Pe, Mc, Mc, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + Mn, Mn, Mn, Mn, Mn, Po, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, So, So, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + So, So, So, So, So, So, Mn, So, So, So, So, So, So, Cn, So, So, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + Po, Po, Po, Po, Po, So, So, So, So, Po, Po, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mc, Mc, Mn, Mn, Lo, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mn, Mn, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + Mn, Lo, Mc, Mc, Mc, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Lo, Lo, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + Lo, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + Lo, Lo, Mn, Mc, Mc, Mn, Mn, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Lo, Mc, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Mc, Mc, Mc, Mn, So, So, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Cn, Lu, Cn, Cn, Cn, Cn, Cn, Lu, Cn, Cn, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Po, Lm, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + Lo, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + Pd, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, Po, Lo, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + Zs, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Ps, Pe, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Po, Po, Nl, Nl, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + Nl, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + Lo, Lo, Mn, Mn, Mn, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + Lo, Lo, Mn, Mn, Mc, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + Lo, Lo, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + Lo, Cn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + Lo, Lo, Lo, Lo, Mn, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + Mn, Mn, Mn, Mn, Po, Po, Po, Lm, Po, Po, Po, Sc, Lo, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + Po, Po, Po, Po, Po, Po, Pd, Po, Po, Po, Po, Mn, Mn, Mn, Cf, Mn, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + Lo, Lo, Lo, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + Mn, Mn, Mn, Mc, Mc, Mc, Mc, Mn, Mn, Mc, Mc, Mc, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + Mc, Mc, Mn, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mn, Mn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + So, Cn, Cn, Cn, Po, Po, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, Cn, Cn, Cn, So, So, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mc, Mc, Mn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + Lo, Lo, Lo, Lo, Lo, Mc, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + Mn, Mc, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + Po, Po, Po, Po, Po, Po, Po, Lm, Po, Po, Po, Po, Po, Po, Cn, Cn, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Me, Mn, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + Mn, Mn, Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + Mc, Mc, Mn, Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Po, Po, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + Po, So, So, So, So, So, So, So, So, So, So, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + Mn, Mn, Mn, Mn, So, So, So, So, So, So, So, So, So, Po, Po, Po, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + Mn, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + Lo, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mc, Mn, Mn, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mn, Mc, Mc, Mc, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + Mn, Mn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lm, Lm, Lm, Lm, Lm, Po, Po, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + Mn, Mn, Mn, Po, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + Mn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Mn, Lo, Lo, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + Lo, Lo, Lo, Lo, Mn, Lo, Lo, Mc, Mn, Mn, Lo, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Lu, Cn, Lu, Cn, Lu, Cn, Lu, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lt, Lt, Lt, Lt, Lt, Lt, Lt, Lt, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Ll, Sk, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + Sk, Sk, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + Ll, Ll, Ll, Ll, Cn, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Cn, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + Cn, Cn, Ll, Ll, Ll, Cn, Ll, Ll, Lu, Lu, Lu, Lu, Lt, Sk, Sk, Cn, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Zs, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + Pd, Pd, Pd, Pd, Pd, Pd, Po, Po, Pi, Pf, Ps, Pi, Pi, Pf, Ps, Pi, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Zl, Zp, Cf, Cf, Cf, Cf, Cf, Zs, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Pi, Pf, Po, Po, Po, Po, Pc, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + Pc, Po, Po, Po, Sm, Ps, Pe, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + Po, Po, Sm, Po, Pc, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Zs, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + Cf, Cf, Cf, Cf, Cf, Cn, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + No, Lm, Cn, Cn, No, No, No, No, No, No, Sm, Sm, Sm, Ps, Pe, Lm, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + No, No, No, No, No, No, No, No, No, No, Sm, Sm, Sm, Ps, Pe, Cn, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, Sc, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + Sc, Sc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Me, Me, Me, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + Me, Mn, Me, Me, Me, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + So, So, Lu, So, So, So, So, Lu, So, So, Ll, Lu, Lu, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + Lu, Lu, Lu, Ll, So, Lu, So, So, Sm, Lu, Lu, Lu, Lu, Lu, So, So, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + So, So, So, So, Lu, So, Lu, So, Lu, So, Lu, Lu, Lu, Lu, So, Ll, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + Lu, Lu, Lu, Lu, Ll, Lo, Lo, Lo, Lo, Ll, So, So, Ll, Ll, Lu, Lu, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + Sm, Sm, Sm, Sm, Sm, Lu, Ll, Ll, Ll, Ll, So, Sm, So, So, Ll, So, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + Nl, Nl, Nl, Lu, Ll, Nl, Nl, Nl, Nl, No, So, So, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + Sm, Sm, Sm, Sm, Sm, So, So, So, So, So, Sm, Sm, So, So, So, So, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + Sm, So, So, Sm, So, So, Sm, So, So, So, So, So, So, So, Sm, So, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + So, So, Sm, So, Sm, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + So, So, So, So, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + So, So, So, So, So, So, So, So, Ps, Pe, Ps, Pe, So, So, So, So, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + Sm, Sm, So, So, So, So, So, So, So, Ps, Pe, So, So, So, So, So, +/* DATA_BLOCK: -- 0x11B0..0x11BF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Sm, So, So, So, +/* DATA_BLOCK: -- 0x11C0..0x11CF -- */ + So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x11D0..0x11DF -- */ + Sm, Sm, Sm, Sm, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x11E0..0x11EF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x11F0..0x11FF -- */ + Sm, Sm, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1200..0x120F -- */ + So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1210..0x121F -- */ + No, No, No, No, No, No, No, No, No, No, No, No, So, So, So, So, +/* DATA_BLOCK: -- 0x1220..0x122F -- */ + So, So, So, So, So, So, So, So, So, So, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1230..0x123F -- */ + So, So, So, So, So, So, So, Sm, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1240..0x124F -- */ + So, Sm, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1250..0x125F -- */ + So, So, So, So, So, So, So, So, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x1260..0x126F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, Sm, +/* DATA_BLOCK: -- 0x1270..0x127F -- */ + So, So, So, So, So, So, So, So, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x1280..0x128F -- */ + Ps, Pe, Ps, Pe, Ps, Pe, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1290..0x129F -- */ + No, No, No, No, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x12A0..0x12AF -- */ + Sm, Sm, Sm, Sm, Sm, Ps, Pe, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12B0..0x12BF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x12C0..0x12CF -- */ + Sm, Sm, Sm, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, +/* DATA_BLOCK: -- 0x12D0..0x12DF -- */ + Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Sm, Sm, Sm, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12E0..0x12EF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Ps, Pe, Sm, Sm, Sm, Sm, +/* DATA_BLOCK: -- 0x12F0..0x12FF -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Ps, Pe, Sm, Sm, +/* DATA_BLOCK: -- 0x1300..0x130F -- */ + Sm, Sm, Sm, Sm, Sm, So, So, Sm, Sm, Sm, Sm, Sm, Sm, So, So, So, +/* DATA_BLOCK: -- 0x1310..0x131F -- */ + So, So, So, So, Cn, Cn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1320..0x132F -- */ + Lu, Ll, Lu, Lu, Lu, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x1330..0x133F -- */ + Lu, Ll, Lu, Ll, Ll, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Lm, Lu, Lu, +/* DATA_BLOCK: -- 0x1340..0x134F -- */ + Lu, Ll, Lu, Ll, Ll, So, So, So, So, So, So, Lu, Ll, Lu, Ll, Mn, +/* DATA_BLOCK: -- 0x1350..0x135F -- */ + Mn, Mn, Lu, Ll, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, No, Po, Po, +/* DATA_BLOCK: -- 0x1360..0x136F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Ll, Cn, Cn, Cn, Cn, Cn, Ll, Cn, Cn, +/* DATA_BLOCK: -- 0x1370..0x137F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lm, +/* DATA_BLOCK: -- 0x1380..0x138F -- */ + Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x1390..0x139F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x13A0..0x13AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x13B0..0x13BF -- */ + Po, Po, Pi, Pf, Pi, Pf, Po, Po, Po, Pi, Pf, Po, Pi, Pf, Po, Po, +/* DATA_BLOCK: -- 0x13C0..0x13CF -- */ + Po, Po, Po, Po, Po, Po, Po, Pd, Po, Po, Pd, Po, Pi, Pf, Po, Po, +/* DATA_BLOCK: -- 0x13D0..0x13DF -- */ + Pi, Pf, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Po, Po, Po, Po, Po, Lm, +/* DATA_BLOCK: -- 0x13E0..0x13EF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Pd, Pd, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x13F0..0x13FF -- */ + Pd, Po, Ps, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1400..0x140F -- */ + So, So, Po, Po, Po, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Pd, Cn, Cn, +/* DATA_BLOCK: -- 0x1410..0x141F -- */ + So, So, So, So, So, So, So, So, So, So, Cn, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1420..0x142F -- */ + So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1430..0x143F -- */ + So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1440..0x144F -- */ + Zs, Po, Po, Po, So, Lm, Lo, Nl, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, +/* DATA_BLOCK: -- 0x1450..0x145F -- */ + Ps, Pe, So, So, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Pd, Ps, Pe, Pe, +/* DATA_BLOCK: -- 0x1460..0x146F -- */ + So, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Mn, Mn, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x1470..0x147F -- */ + Pd, Lm, Lm, Lm, Lm, Lm, So, So, Nl, Nl, Nl, Lm, Lo, Po, So, So, +/* DATA_BLOCK: -- 0x1480..0x148F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Sk, Sk, Lm, Lm, Lo, +/* DATA_BLOCK: -- 0x1490..0x149F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Lm, Lm, Lm, Lo, +/* DATA_BLOCK: -- 0x14A0..0x14AF -- */ + Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x14B0..0x14BF -- */ + So, So, No, No, No, No, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x14C0..0x14CF -- */ + So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, So, +/* DATA_BLOCK: -- 0x14D0..0x14DF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, +/* DATA_BLOCK: -- 0x14E0..0x14EF -- */ + No, No, No, No, No, No, No, No, No, No, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x14F0..0x14FF -- */ + So, So, So, So, So, So, So, So, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1500..0x150F -- */ + So, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1510..0x151F -- */ + Lo, Lo, Lo, Lo, Lo, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1520..0x152F -- */ + So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1530..0x153F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Po, Po, Po, +/* DATA_BLOCK: -- 0x1540..0x154F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1550..0x155F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lo, Mn, +/* DATA_BLOCK: -- 0x1560..0x156F -- */ + Me, Me, Me, Po, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Lm, +/* DATA_BLOCK: -- 0x1570..0x157F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lm, Lm, Mn, Mn, +/* DATA_BLOCK: -- 0x1580..0x158F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, +/* DATA_BLOCK: -- 0x1590..0x159F -- */ + Mn, Mn, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x15A0..0x15AF -- */ + Sk, Sk, Sk, Sk, Sk, Sk, Sk, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x15B0..0x15BF -- */ + Sk, Sk, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x15C0..0x15CF -- */ + Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x15D0..0x15DF -- */ + Lm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x15E0..0x15EF -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lm, Sk, Sk, Lu, Ll, Lu, Ll, Lo, +/* DATA_BLOCK: -- 0x15F0..0x15FF -- */ + Lu, Ll, Lu, Ll, Ll, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x1600..0x160F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Lu, Lu, Lu, Lu, Ll, +/* DATA_BLOCK: -- 0x1610..0x161F -- */ + Lu, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x1620..0x162F -- */ + Lu, Ll, Lu, Ll, Lu, Lu, Lu, Lu, Ll, Lu, Ll, Lu, Lu, Ll, Lu, Ll, +/* DATA_BLOCK: -- 0x1630..0x163F -- */ + Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Ll, Lu, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1640..0x164F -- */ + Cn, Lm, Lm, Lm, Lm, Lu, Ll, Lo, Lm, Lm, Ll, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1650..0x165F -- */ + Lo, Lo, Mn, Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1660..0x166F -- */ + Lo, Lo, Lo, Mc, Mc, Mn, Mn, Mc, So, So, So, So, Mn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1670..0x167F -- */ + No, No, No, No, No, No, So, So, Sc, So, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1680..0x168F -- */ + Lo, Lo, Lo, Lo, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1690..0x169F -- */ + Mc, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x16A0..0x16AF -- */ + Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x16B0..0x16BF -- */ + Mc, Mc, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x16C0..0x16CF -- */ + Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Po, Po, Po, Lo, Po, Lo, Lo, Mn, +/* DATA_BLOCK: -- 0x16D0..0x16DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, +/* DATA_BLOCK: -- 0x16E0..0x16EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x16F0..0x16FF -- */ + Mn, Mn, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1700..0x170F -- */ + Lo, Lo, Lo, Mn, Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x1710..0x171F -- */ + Mc, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Lm, +/* DATA_BLOCK: -- 0x1720..0x172F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Po, Po, +/* DATA_BLOCK: -- 0x1730..0x173F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1740..0x174F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x1750..0x175F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x1760..0x176F -- */ + Mc, Mn, Mn, Mc, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1770..0x177F -- */ + Lo, Lo, Lo, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Cn, Cn, +/* DATA_BLOCK: -- 0x1780..0x178F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1790..0x179F -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, So, So, So, Lo, Mc, Mn, Mc, Lo, Lo, +/* DATA_BLOCK: -- 0x17A0..0x17AF -- */ + Mn, Lo, Mn, Mn, Mn, Lo, Lo, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x17B0..0x17BF -- */ + Lo, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x17C0..0x17CF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lm, Po, Po, +/* DATA_BLOCK: -- 0x17D0..0x17DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mn, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x17E0..0x17EF -- */ + Po, Po, Lo, Lm, Lm, Mc, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x17F0..0x17FF -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x1800..0x180F -- */ + Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1810..0x181F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sk, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x1820..0x182F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lm, Sk, Sk, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1830..0x183F -- */ + Lo, Lo, Lo, Mc, Mc, Mn, Mc, Mc, Mn, Mc, Mc, Po, Mc, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x1840..0x184F -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1850..0x185F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1860..0x186F -- */ + Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, Cs, +/* DATA_BLOCK: -- 0x1870..0x187F -- */ + Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, +/* DATA_BLOCK: -- 0x1880..0x188F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1890..0x189F -- */ + Cn, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Lo, Mn, Lo, +/* DATA_BLOCK: -- 0x18A0..0x18AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sm, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x18B0..0x18BF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x18C0..0x18CF -- */ + Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x18D0..0x18DF -- */ + Lo, Lo, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x18E0..0x18EF -- */ + Sk, Sk, Sk, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x18F0..0x18FF -- */ + So, So, So, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1900..0x190F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Pe, Ps, +/* DATA_BLOCK: -- 0x1910..0x191F -- */ + So, So, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1920..0x192F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1930..0x193F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Sc, So, So, So, +/* DATA_BLOCK: -- 0x1940..0x194F -- */ + Po, Po, Po, Po, Po, Po, Po, Ps, Pe, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1950..0x195F -- */ + Po, Pd, Pd, Pc, Pc, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, Pe, Ps, +/* DATA_BLOCK: -- 0x1960..0x196F -- */ + Pe, Ps, Pe, Ps, Pe, Po, Po, Ps, Pe, Po, Po, Po, Po, Pc, Pc, Pc, +/* DATA_BLOCK: -- 0x1970..0x197F -- */ + Po, Po, Po, Cn, Po, Po, Po, Po, Pd, Ps, Pe, Ps, Pe, Ps, Pe, Po, +/* DATA_BLOCK: -- 0x1980..0x198F -- */ + Po, Po, Sm, Pd, Sm, Sm, Sm, Cn, Po, Sc, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1990..0x199F -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x19A0..0x19AF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cf, +/* DATA_BLOCK: -- 0x19B0..0x19BF -- */ + Cn, Po, Po, Po, Sc, Po, Po, Po, Ps, Pe, Po, Sm, Po, Pd, Po, Po, +/* DATA_BLOCK: -- 0x19C0..0x19CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ps, Sm, Pe, Sm, Ps, +/* DATA_BLOCK: -- 0x19D0..0x19DF -- */ + Pe, Po, Ps, Pe, Po, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x19E0..0x19EF -- */ + Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x19F0..0x19FF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lm, +/* DATA_BLOCK: -- 0x1A00..0x1A0F -- */ + Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A10..0x1A1F -- */ + Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1A20..0x1A2F -- */ + Sc, Sc, Sm, Sk, So, Sc, Sc, Cn, So, Sm, Sm, Sm, Sm, So, So, Cn, +/* DATA_BLOCK: -- 0x1A30..0x1A3F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cf, Cf, Cf, So, So, Cn, Cn, +/* DATA_BLOCK: -- 0x1A40..0x1A4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1A50..0x1A5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1A60..0x1A6F -- */ + Po, Po, Po, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1A70..0x1A7F -- */ + No, No, No, No, Cn, Cn, Cn, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1A80..0x1A8F -- */ + Nl, Nl, Nl, Nl, Nl, No, No, No, No, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x1A90..0x1A9F -- */ + So, So, So, So, So, So, So, So, So, So, No, No, So, So, So, Cn, +/* DATA_BLOCK: -- 0x1AA0..0x1AAF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AB0..0x1ABF -- */ + So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AC0..0x1ACF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AD0..0x1ADF -- */ + Mn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1AE0..0x1AEF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1AF0..0x1AFF -- */ + No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1B00..0x1B0F -- */ + Lo, Nl, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Nl, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B10..0x1B1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B20..0x1B2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Po, +/* DATA_BLOCK: -- 0x1B30..0x1B3F -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1B40..0x1B4F -- */ + Po, Nl, Nl, Nl, Nl, Nl, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B50..0x1B5F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1B60..0x1B6F -- */ + Lu, Lu, Lu, Lu, Cn, Cn, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1B70..0x1B7F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B80..0x1B8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1B90..0x1B9F -- */ + Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1BA0..0x1BAF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x1BB0..0x1BBF -- */ + Lu, Lu, Lu, Cn, Lu, Lu, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1BC0..0x1BCF -- */ + Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x1BD0..0x1BDF -- */ + Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1BE0..0x1BEF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x1BF0..0x1BFF -- */ + Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1C00..0x1C0F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1C10..0x1C1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Cn, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x1C20..0x1C2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Po, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C30..0x1C3F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, So, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C40..0x1C4F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C50..0x1C5F -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1C60..0x1C6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, No, No, No, No, No, No, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1C70..0x1C7F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x1C80..0x1C8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, No, No, Lo, Lo, +/* DATA_BLOCK: -- 0x1C90..0x1C9F -- */ + Cn, Cn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1CA0..0x1CAF -- */ + Lo, Mn, Mn, Mn, Cn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1CB0..0x1CBF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1CC0..0x1CCF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x1CD0..0x1CDF -- */ + No, No, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1CE0..0x1CEF -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1CF0..0x1CFF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, No, No, Po, +/* DATA_BLOCK: -- 0x1D00..0x1D0F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, No, No, No, +/* DATA_BLOCK: -- 0x1D10..0x1D1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, So, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1D20..0x1D2F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Mn, Cn, Cn, Cn, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D30..0x1D3F -- */ + Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1D40..0x1D4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x1D50..0x1D5F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D60..0x1D6F -- */ + Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D70..0x1D7F -- */ + Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, Po, Po, Po, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1D80..0x1D8F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1D90..0x1D9F -- */ + Lu, Lu, Lu, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1DA0..0x1DAF -- */ + Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1DB0..0x1DBF -- */ + Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1DC0..0x1DCF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Lo, Lo, Lo, Lm, Lo, +/* DATA_BLOCK: -- 0x1DD0..0x1DDF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Pd, Lm, +/* DATA_BLOCK: -- 0x1DE0..0x1DEF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Sm, Sm, +/* DATA_BLOCK: -- 0x1DF0..0x1DFF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, +/* DATA_BLOCK: -- 0x1E00..0x1E0F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Mn, Mn, Pd, Cn, Cn, +/* DATA_BLOCK: -- 0x1E10..0x1E1F -- */ + Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E20..0x1E2F -- */ + Cn, Cn, Lo, Lo, Lo, Lm, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E30..0x1E3F -- */ + Po, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E40..0x1E4F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1E50..0x1E5F -- */ + No, No, No, No, No, No, No, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E60..0x1E6F -- */ + Mn, No, No, No, No, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E70..0x1E7F -- */ + Lo, Lo, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E80..0x1E8F -- */ + Lo, Lo, Lo, Lo, Lo, No, No, No, No, No, No, No, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1E90..0x1E9F -- */ + Mc, Mn, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1EA0..0x1EAF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1EB0..0x1EBF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, +/* DATA_BLOCK: -- 0x1EC0..0x1ECF -- */ + No, No, No, No, No, No, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x1ED0..0x1EDF -- */ + Mn, Lo, Lo, Mn, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x1EE0..0x1EEF -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Po, Po, Cf, Po, Po, +/* DATA_BLOCK: -- 0x1EF0..0x1EFF -- */ + Po, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cf, Cn, Cn, +/* DATA_BLOCK: -- 0x1F00..0x1F0F -- */ + Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x1F10..0x1F1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x1F20..0x1F2F -- */ + Mn, Mn, Mn, Mn, Mn, Cn, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x1F30..0x1F3F -- */ + Po, Po, Po, Po, Lo, Mc, Mc, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1F40..0x1F4F -- */ + Lo, Lo, Lo, Mn, Po, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1F50..0x1F5F -- */ + Lo, Lo, Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, +/* DATA_BLOCK: -- 0x1F60..0x1F6F -- */ + Mc, Lo, Lo, Lo, Lo, Po, Po, Po, Po, Mn, Mn, Mn, Mn, Po, Mc, Mn, +/* DATA_BLOCK: -- 0x1F70..0x1F7F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Lo, Po, Lo, Po, Po, Po, +/* DATA_BLOCK: -- 0x1F80..0x1F8F -- */ + Cn, No, No, No, No, No, No, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x1F90..0x1F9F -- */ + No, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1FA0..0x1FAF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mn, +/* DATA_BLOCK: -- 0x1FB0..0x1FBF -- */ + Mn, Mn, Mc, Mc, Mn, Mc, Mn, Mn, Po, Po, Po, Po, Po, Po, Mn, Lo, +/* DATA_BLOCK: -- 0x1FC0..0x1FCF -- */ + Lo, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x1FD0..0x1FDF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1FE0..0x1FEF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x1FF0..0x1FFF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2000..0x200F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, +/* DATA_BLOCK: -- 0x2010..0x201F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2020..0x202F -- */ + Mn, Mn, Mc, Mc, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x2030..0x203F -- */ + Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Mn, Mn, Lo, Mc, Mc, +/* DATA_BLOCK: -- 0x2040..0x204F -- */ + Mn, Mc, Mc, Mc, Mc, Cn, Cn, Mc, Mc, Cn, Cn, Mc, Mc, Mc, Cn, Cn, +/* DATA_BLOCK: -- 0x2050..0x205F -- */ + Lo, Cn, Cn, Cn, Cn, Cn, Cn, Mc, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2060..0x206F -- */ + Lo, Lo, Mc, Mc, Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2070..0x207F -- */ + Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2080..0x208F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x2090..0x209F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x20A0..0x20AF -- */ + Mn, Cn, Mc, Cn, Cn, Mc, Cn, Mc, Mc, Mc, Mc, Cn, Mc, Mc, Mn, Mc, +/* DATA_BLOCK: -- 0x20B0..0x20BF -- */ + Mn, Lo, Mn, Lo, Po, Po, Cn, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x20C0..0x20CF -- */ + Cn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x20D0..0x20DF -- */ + Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x20E0..0x20EF -- */ + Mc, Mc, Mn, Mn, Mn, Mc, Mn, Lo, Lo, Lo, Lo, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x20F0..0x20FF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Po, Po, Cn, Po, Mn, Lo, +/* DATA_BLOCK: -- 0x2100..0x210F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mc, Mc, Mc, Mc, Mn, +/* DATA_BLOCK: -- 0x2110..0x211F -- */ + Mn, Mc, Mn, Mn, Lo, Lo, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2120..0x212F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, +/* DATA_BLOCK: -- 0x2130..0x213F -- */ + Mc, Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mc, Mc, Mc, Mc, Mn, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x2140..0x214F -- */ + Mn, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x2150..0x215F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Lo, Lo, Lo, Lo, Mn, Mn, Cn, Cn, +/* DATA_BLOCK: -- 0x2160..0x216F -- */ + Mc, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x2170..0x217F -- */ + Mn, Po, Po, Po, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2180..0x218F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2190..0x219F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mc, Mn, Mc, Mc, +/* DATA_BLOCK: -- 0x21A0..0x21AF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Lo, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x21B0..0x21BF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, +/* DATA_BLOCK: -- 0x21C0..0x21CF -- */ + Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x21D0..0x21DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x21E0..0x21EF -- */ + Mc, Mc, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x21F0..0x21FF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, No, No, Po, Po, Po, So, +/* DATA_BLOCK: -- 0x2200..0x220F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2210..0x221F -- */ + No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x2220..0x222F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Cn, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2230..0x223F -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2240..0x224F -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Cn, Mc, Mc, Cn, Cn, Mn, Mn, Mc, Mn, Lo, +/* DATA_BLOCK: -- 0x2250..0x225F -- */ + Mc, Lo, Mc, Mn, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2260..0x226F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2270..0x227F -- */ + Lo, Mc, Mc, Mc, Mn, Mn, Mn, Mn, Cn, Cn, Mn, Mn, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x2280..0x228F -- */ + Mn, Lo, Po, Lo, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2290..0x229F -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x22A0..0x22AF -- */ + Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Lo, Mn, Mn, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x22B0..0x22BF -- */ + Po, Po, Po, Po, Po, Po, Po, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x22C0..0x22CF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mn, Mn, Mn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x22D0..0x22DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x22E0..0x22EF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, Mn, Po, Po, Po, Lo, Po, Po, +/* DATA_BLOCK: -- 0x22F0..0x22FF -- */ + Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2300..0x230F -- */ + Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2310..0x231F -- */ + Mn, Mc, Mn, Mn, Mn, Mc, Mn, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2320..0x232F -- */ + Lo, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2330..0x233F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mn, +/* DATA_BLOCK: -- 0x2340..0x234F -- */ + Lo, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2350..0x235F -- */ + Po, Po, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2360..0x236F -- */ + Cn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2370..0x237F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mc, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2380..0x238F -- */ + Mn, Mc, Mn, Mn, Mc, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2390..0x239F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x23A0..0x23AF -- */ + Lo, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Mn, Cn, Mn, Mn, Cn, Mn, +/* DATA_BLOCK: -- 0x23B0..0x23BF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Lo, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x23C0..0x23CF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x23D0..0x23DF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mc, Mc, Mc, Mc, Mc, Cn, +/* DATA_BLOCK: -- 0x23E0..0x23EF -- */ + Mn, Mn, Cn, Mc, Mc, Mn, Mc, Mn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x23F0..0x23FF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lo, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2400..0x240F -- */ + Lo, Lo, Lo, Mn, Mn, Mc, Mc, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2410..0x241F -- */ + Mn, Mn, Lo, Mc, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2420..0x242F -- */ + Lo, Lo, Lo, Lo, Mc, Mc, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Mc, Mc, +/* DATA_BLOCK: -- 0x2430..0x243F -- */ + Mn, Mc, Mn, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, Po, +/* DATA_BLOCK: -- 0x2440..0x244F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2450..0x245F -- */ + No, No, No, No, No, So, So, So, So, So, So, So, So, Sc, Sc, Sc, +/* DATA_BLOCK: -- 0x2460..0x246F -- */ + Sc, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2470..0x247F -- */ + So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x2480..0x248F -- */ + Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Nl, Cn, +/* DATA_BLOCK: -- 0x2490..0x249F -- */ + Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24A0..0x24AF -- */ + Lo, Po, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24B0..0x24BF -- */ + Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, +/* DATA_BLOCK: -- 0x24C0..0x24CF -- */ + Mn, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x24D0..0x24DF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x24E0..0x24EF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x24F0..0x24FF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mc, Mc, Mc, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2500..0x250F -- */ + Mn, Mn, Mn, Mn, Mn, Po, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2510..0x251F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Po, Po, Po, Po, Po, So, So, So, So, +/* DATA_BLOCK: -- 0x2520..0x252F -- */ + Lm, Lm, Lm, Lm, Po, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2530..0x253F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, No, No, No, No, No, +/* DATA_BLOCK: -- 0x2540..0x254F -- */ + No, No, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2550..0x255F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2560..0x256F -- */ + Lm, Lm, Lm, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2570..0x257F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Lm, Po, Po, Po, +/* DATA_BLOCK: -- 0x2580..0x258F -- */ + No, No, No, No, No, No, No, Po, Po, Po, Po, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2590..0x259F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Cn, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x25A0..0x25AF -- */ + Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x25B0..0x25BF -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x25C0..0x25CF -- */ + Lo, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x25D0..0x25DF -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x25E0..0x25EF -- */ + Mc, Mc, Mc, Mc, Mc, Mc, Mc, Mc, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x25F0..0x25FF -- */ + Mn, Mn, Mn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, +/* DATA_BLOCK: -- 0x2600..0x260F -- */ + Lm, Lm, Po, Lm, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2610..0x261F -- */ + Mc, Mc, Lm, Lm, Nl, Nl, Nl, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2620..0x262F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, +/* DATA_BLOCK: -- 0x2630..0x263F -- */ + Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2640..0x264F -- */ + Lm, Lm, Lm, Lm, Cn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Lm, Lm, Cn, +/* DATA_BLOCK: -- 0x2650..0x265F -- */ + Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2660..0x266F -- */ + Lo, Lo, Lo, Cn, Cn, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2670..0x267F -- */ + Cn, Cn, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2680..0x268F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Cn, So, Mn, Mn, Po, +/* DATA_BLOCK: -- 0x2690..0x269F -- */ + Cf, Cf, Cf, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x26A0..0x26AF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, So, So, So, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x26B0..0x26BF -- */ + So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x26C0..0x26CF -- */ + Sm, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x26D0..0x26DF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x26E0..0x26EF -- */ + So, So, So, So, So, So, So, Cn, Cn, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x26F0..0x26FF -- */ + So, So, So, So, So, Mc, Mc, Mn, Mn, Mn, So, So, So, Mc, Mc, Mc, +/* DATA_BLOCK: -- 0x2700..0x270F -- */ + Mc, Mc, Mc, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Cf, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2710..0x271F -- */ + Mn, Mn, Mn, So, So, Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, So, +/* DATA_BLOCK: -- 0x2720..0x272F -- */ + So, So, So, So, So, So, So, So, So, So, Mn, Mn, Mn, Mn, So, So, +/* DATA_BLOCK: -- 0x2730..0x273F -- */ + So, So, Mn, Mn, Mn, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2740..0x274F -- */ + No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2750..0x275F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2760..0x276F -- */ + Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2770..0x277F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, +/* DATA_BLOCK: -- 0x2780..0x278F -- */ + Ll, Ll, Ll, Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2790..0x279F -- */ + Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x27A0..0x27AF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x27B0..0x27BF -- */ + Cn, Cn, Lu, Cn, Cn, Lu, Lu, Cn, Cn, Lu, Lu, Lu, Lu, Cn, Lu, Lu, +/* DATA_BLOCK: -- 0x27C0..0x27CF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Cn, Ll, Cn, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x27D0..0x27DF -- */ + Ll, Ll, Ll, Ll, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x27E0..0x27EF -- */ + Ll, Ll, Ll, Ll, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Cn, Cn, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x27F0..0x27FF -- */ + Lu, Lu, Lu, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Cn, Ll, Ll, +/* DATA_BLOCK: -- 0x2800..0x280F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Cn, Lu, Lu, Lu, Lu, Cn, +/* DATA_BLOCK: -- 0x2810..0x281F -- */ + Lu, Lu, Lu, Lu, Lu, Cn, Lu, Cn, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2820..0x282F -- */ + Lu, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2830..0x283F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2840..0x284F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2850..0x285F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2860..0x286F -- */ + Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2870..0x287F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2880..0x288F -- */ + Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x2890..0x289F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x28A0..0x28AF -- */ + Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x28B0..0x28BF -- */ + Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x28C0..0x28CF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, +/* DATA_BLOCK: -- 0x28D0..0x28DF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, +/* DATA_BLOCK: -- 0x28E0..0x28EF -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, +/* DATA_BLOCK: -- 0x28F0..0x28FF -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2900..0x290F -- */ + Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Lu, Sm, Ll, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2910..0x291F -- */ + Ll, Ll, Ll, Sm, Ll, Ll, Ll, Ll, Ll, Ll, Lu, Ll, Cn, Cn, Nd, Nd, +/* DATA_BLOCK: -- 0x2920..0x292F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, So, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2930..0x293F -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, So, So, So, +/* DATA_BLOCK: -- 0x2940..0x294F -- */ + So, So, So, So, So, Mn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2950..0x295F -- */ + So, So, So, So, Mn, So, So, Po, Po, Po, Po, Po, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2960..0x296F -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2970..0x297F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Lo, Ll, Ll, Ll, Ll, Ll, +/* DATA_BLOCK: -- 0x2980..0x298F -- */ + Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Ll, Cn, +/* DATA_BLOCK: -- 0x2990..0x299F -- */ + Cn, Cn, Cn, Cn, Cn, Ll, Ll, Ll, Ll, Ll, Ll, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29A0..0x29AF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x29B0..0x29BF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Mn, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x29C0..0x29CF -- */ + Mn, Mn, Cn, Mn, Mn, Cn, Mn, Mn, Mn, Mn, Mn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x29D0..0x29DF -- */ + Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, +/* DATA_BLOCK: -- 0x29E0..0x29EF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Mn, +/* DATA_BLOCK: -- 0x29F0..0x29FF -- */ + Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lm, Lm, Lm, Lm, Lm, Lm, Lm, Cn, Cn, +/* DATA_BLOCK: -- 0x2A00..0x2A0F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Lo, So, +/* DATA_BLOCK: -- 0x2A10..0x2A1F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Cn, +/* DATA_BLOCK: -- 0x2A20..0x2A2F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2A30..0x2A3F -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Cn, Sc, +/* DATA_BLOCK: -- 0x2A40..0x2A4F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lm, Mn, Mn, Mn, Mn, +/* DATA_BLOCK: -- 0x2A50..0x2A5F -- */ + Lo, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Cn, Cn, Cn, Cn, Po, +/* DATA_BLOCK: -- 0x2A60..0x2A6F -- */ + Lo, Lo, Lo, Mn, Lo, Lo, Mn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Mn, Mn, +/* DATA_BLOCK: -- 0x2A70..0x2A7F -- */ + Lo, Lo, Lo, Lo, Lo, Mn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Lo, Lm, +/* DATA_BLOCK: -- 0x2A80..0x2A8F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Cn, +/* DATA_BLOCK: -- 0x2A90..0x2A9F -- */ + Lo, Lo, Lo, Lo, Lo, Cn, Cn, No, No, No, No, No, No, No, No, No, +/* DATA_BLOCK: -- 0x2AA0..0x2AAF -- */ + Ll, Ll, Ll, Ll, Mn, Mn, Mn, Mn, Mn, Mn, Mn, Lm, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2AB0..0x2ABF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, So, No, No, No, +/* DATA_BLOCK: -- 0x2AC0..0x2ACF -- */ + Sc, No, No, No, No, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2AD0..0x2ADF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, So, No, +/* DATA_BLOCK: -- 0x2AE0..0x2AEF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, No, Cn, Cn, +/* DATA_BLOCK: -- 0x2AF0..0x2AFF -- */ + Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B00..0x2B0F -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B10..0x2B1F -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, Lo, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2B20..0x2B2F -- */ + Cn, Cn, Lo, Cn, Cn, Cn, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B30..0x2B3F -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, Cn, Lo, +/* DATA_BLOCK: -- 0x2B40..0x2B4F -- */ + Cn, Lo, Lo, Cn, Lo, Cn, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B50..0x2B5F -- */ + Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Cn, Lo, Cn, +/* DATA_BLOCK: -- 0x2B60..0x2B6F -- */ + Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B70..0x2B7F -- */ + Cn, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, Cn, Lo, Lo, Lo, Lo, Lo, +/* DATA_BLOCK: -- 0x2B80..0x2B8F -- */ + Sm, Sm, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2B90..0x2B9F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2BA0..0x2BAF -- */ + Cn, So, So, So, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2BB0..0x2BBF -- */ + No, No, No, No, No, No, No, No, No, No, No, No, No, So, So, So, +/* DATA_BLOCK: -- 0x2BC0..0x2BCF -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, +/* DATA_BLOCK: -- 0x2BD0..0x2BDF -- */ + Cn, Cn, Cn, Cn, Cn, Cn, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2BE0..0x2BEF -- */ + So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2BF0..0x2BFF -- */ + So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2C00..0x2C0F -- */ + So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2C10..0x2C1F -- */ + So, So, So, So, So, So, So, So, So, So, So, Sk, Sk, Sk, Sk, Sk, +/* DATA_BLOCK: -- 0x2C20..0x2C2F -- */ + So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, So, So, So, So, +/* DATA_BLOCK: -- 0x2C30..0x2C3F -- */ + So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2C40..0x2C4F -- */ + Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Sm, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2C50..0x2C5F -- */ + So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, So, So, +/* DATA_BLOCK: -- 0x2C60..0x2C6F -- */ + So, So, So, So, So, So, So, Cn, So, Cn, Cn, Cn, Cn, So, So, So, +/* DATA_BLOCK: -- 0x2C70..0x2C7F -- */ + So, So, So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, So, +/* DATA_BLOCK: -- 0x2C80..0x2C8F -- */ + So, So, So, So, So, So, So, So, So, So, So, Cn, Cn, Cn, Cn, So, +/* DATA_BLOCK: -- 0x2C90..0x2C9F -- */ + So, So, So, Cn, So, So, So, So, So, So, So, So, So, So, So, So, +/* DATA_BLOCK: -- 0x2CA0..0x2CAF -- */ + Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, Nd, So, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2CB0..0x2CBF -- */ + Cn, Cf, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, Cn, +/* DATA_BLOCK: -- 0x2CC0..0x2CCF -- */ + Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Co, Cn, Cn +}; + +static const SBUInt16 MainGeneralCategoryIndexes[4288] = { +/* INDEX_BLOCK: -- 0x0000..0x003F -- */ + 0x0000, 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0000, 0x0000, 0x0070, 0x0080, + 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00D0, 0x00D0, 0x00E0, 0x00F0, 0x00D0, 0x00D0, 0x0100, + 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x00D0, 0x0170, 0x00D0, 0x00D0, 0x00D0, 0x0180, + 0x0190, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x01A0, 0x00B0, 0x01B0, 0x01C0, 0x01D0, 0x01E0, 0x01F0, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0210, 0x0220, 0x0230, 0x0240, 0x00B0, + 0x0250, 0x0260, 0x00D0, 0x0270, +/* INDEX_BLOCK: -- 0x0040..0x007F -- */ + 0x0090, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00D0, 0x0280, 0x00D0, 0x00D0, 0x00D0, + 0x0290, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x02A0, 0x0090, 0x02B0, 0x00B0, 0x00B0, + 0x02C0, 0x02D0, 0x0200, 0x02E0, 0x02F0, 0x0300, 0x0310, 0x0320, 0x0330, 0x0340, 0x0300, 0x0300, + 0x0350, 0x0200, 0x0360, 0x0370, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0380, 0x0390, 0x03A0, + 0x03B0, 0x03C0, 0x0300, 0x0200, 0x03D0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x03E0, 0x03F0, + 0x0400, 0x0300, 0x0410, 0x0420, +/* INDEX_BLOCK: -- 0x0080..0x00BF -- */ + 0x0300, 0x0430, 0x0440, 0x0450, 0x0300, 0x0460, 0x0470, 0x0300, 0x0480, 0x0490, 0x0300, 0x0300, + 0x04A0, 0x0200, 0x04B0, 0x0200, 0x04C0, 0x0300, 0x0300, 0x04D0, 0x04E0, 0x04F0, 0x0500, 0x0510, + 0x0520, 0x0530, 0x0540, 0x0550, 0x0560, 0x0570, 0x0580, 0x0590, 0x05A0, 0x0530, 0x0540, 0x05B0, + 0x05C0, 0x05D0, 0x05E0, 0x05F0, 0x0600, 0x0610, 0x0540, 0x0620, 0x0630, 0x0640, 0x0580, 0x0650, + 0x0660, 0x0530, 0x0540, 0x0670, 0x0680, 0x0690, 0x0580, 0x06A0, 0x06B0, 0x06C0, 0x06D0, 0x06E0, + 0x06F0, 0x0700, 0x05E0, 0x0710, +/* INDEX_BLOCK: -- 0x00C0..0x00FF -- */ + 0x0720, 0x0730, 0x0540, 0x0740, 0x0750, 0x0760, 0x0580, 0x0770, 0x0780, 0x0730, 0x0540, 0x0790, + 0x07A0, 0x07B0, 0x0580, 0x07C0, 0x07D0, 0x0730, 0x0300, 0x07E0, 0x07F0, 0x0800, 0x0580, 0x0810, + 0x0820, 0x0830, 0x0300, 0x0840, 0x0850, 0x0860, 0x05E0, 0x0870, 0x0880, 0x0300, 0x0300, 0x0890, + 0x08A0, 0x08B0, 0x08C0, 0x08C0, 0x08D0, 0x0300, 0x08E0, 0x08F0, 0x0900, 0x0910, 0x08C0, 0x08C0, + 0x0920, 0x0930, 0x0940, 0x0950, 0x0960, 0x0300, 0x0970, 0x0980, 0x0990, 0x09A0, 0x0200, 0x09B0, + 0x09C0, 0x09D0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0100..0x013F -- */ + 0x0300, 0x0300, 0x09E0, 0x09F0, 0x0A00, 0x0A10, 0x0A20, 0x0A30, 0x0A40, 0x0A50, 0x0090, 0x0090, + 0x0A60, 0x00B0, 0x00B0, 0x0A70, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0A80, 0x0A90, 0x0300, 0x0300, 0x0A80, 0x0300, 0x0300, 0x0AA0, 0x0AB0, 0x0AC0, 0x0300, 0x0300, + 0x0300, 0x0AB0, 0x0300, 0x0300, 0x0300, 0x0AD0, 0x0AE0, 0x0AF0, 0x0300, 0x0B00, 0x0090, 0x0090, + 0x0090, 0x0090, 0x0090, 0x0B10, +/* INDEX_BLOCK: -- 0x0140..0x017F -- */ + 0x0B20, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0B30, 0x0300, 0x0B40, 0x0B50, 0x0300, 0x0300, 0x0300, 0x0300, 0x0B60, 0x0B70, + 0x0300, 0x0B80, 0x0300, 0x0B90, 0x0300, 0x0BA0, 0x0BB0, 0x0BC0, 0x0300, 0x0300, 0x0300, 0x0BD0, + 0x0BE0, 0x0BF0, 0x0C00, 0x0C10, +/* INDEX_BLOCK: -- 0x0180..0x01BF -- */ + 0x0C20, 0x0C00, 0x0300, 0x0300, 0x0C30, 0x0300, 0x0300, 0x0C40, 0x0C50, 0x0300, 0x0C60, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0C70, 0x0300, 0x0C80, 0x0C90, 0x0CA0, 0x0CB0, 0x0300, 0x0CC0, 0x0CD0, + 0x0300, 0x0300, 0x0CE0, 0x0300, 0x0CF0, 0x0D00, 0x0D10, 0x0D10, 0x0300, 0x0D20, 0x0300, 0x0300, + 0x0300, 0x0D30, 0x0D40, 0x0D50, 0x0C00, 0x0C00, 0x0D60, 0x0D70, 0x0200, 0x0D80, 0x0D90, 0x08C0, + 0x0DA0, 0x0300, 0x0300, 0x0DB0, 0x0DC0, 0x0A00, 0x0DD0, 0x0DE0, 0x0DF0, 0x0300, 0x0E00, 0x0400, + 0x0300, 0x0300, 0x0E10, 0x0E20, +/* INDEX_BLOCK: -- 0x01C0..0x01FF -- */ + 0x0300, 0x0300, 0x0E30, 0x0E40, 0x0E50, 0x0400, 0x0300, 0x0E60, 0x0E70, 0x0090, 0x0090, 0x0E80, + 0x0E90, 0x0EA0, 0x0EB0, 0x0EC0, 0x00B0, 0x00B0, 0x0ED0, 0x01B0, 0x01B0, 0x01B0, 0x0EE0, 0x0EF0, + 0x00B0, 0x0F00, 0x01B0, 0x01B0, 0x0200, 0x0200, 0x0200, 0x0200, 0x00D0, 0x00D0, 0x00D0, 0x00D0, + 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x0F10, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, 0x00D0, + 0x0F20, 0x0F30, 0x0F20, 0x0F20, 0x0F30, 0x0F40, 0x0F20, 0x0F50, 0x0F60, 0x0F60, 0x0F60, 0x0F70, + 0x0F80, 0x0F90, 0x0FA0, 0x0FB0, +/* INDEX_BLOCK: -- 0x0200..0x023F -- */ + 0x0FC0, 0x0FD0, 0x0FE0, 0x0FF0, 0x1000, 0x1010, 0x1020, 0x1030, 0x1040, 0x1050, 0x1060, 0x1060, + 0x1070, 0x1080, 0x1090, 0x10A0, 0x10B0, 0x10C0, 0x10D0, 0x10E0, 0x10F0, 0x1100, 0x1110, 0x1110, + 0x1120, 0x1130, 0x1140, 0x0D10, 0x1150, 0x1160, 0x0D10, 0x1170, 0x1180, 0x1180, 0x1180, 0x1180, + 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, + 0x1190, 0x0D10, 0x11A0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x11B0, 0x0D10, 0x11C0, 0x1180, 0x11D0, + 0x0D10, 0x11E0, 0x11F0, 0x0D10, +/* INDEX_BLOCK: -- 0x0240..0x027F -- */ + 0x0D10, 0x0D10, 0x0B00, 0x08C0, 0x1200, 0x08C0, 0x1100, 0x1100, 0x1100, 0x1210, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x1220, 0x1100, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x1230, 0x1240, 0x0D10, 0x0D10, 0x1250, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x1260, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1270, 0x1280, 0x1100, 0x1290, 0x0D10, 0x0D10, + 0x12A0, 0x1180, 0x12B0, 0x1180, +/* INDEX_BLOCK: -- 0x0280..0x02BF -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, + 0x12C0, 0x12D0, 0x1180, 0x1180, 0x1180, 0x12E0, 0x1180, 0x12F0, 0x1180, 0x1180, 0x1180, 0x1180, + 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, 0x1180, + 0x0D10, 0x0D10, 0x0D10, 0x1180, 0x1300, 0x0D10, 0x0D10, 0x1310, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, +/* INDEX_BLOCK: -- 0x02C0..0x02FF -- */ + 0x0090, 0x0090, 0x0090, 0x00B0, 0x00B0, 0x00B0, 0x1320, 0x1330, 0x00D0, 0x00D0, 0x00D0, 0x00D0, + 0x00D0, 0x00D0, 0x1340, 0x1350, 0x00B0, 0x00B0, 0x1360, 0x0300, 0x0300, 0x0300, 0x1370, 0x1380, + 0x0300, 0x1390, 0x13A0, 0x13A0, 0x13A0, 0x13A0, 0x0200, 0x0200, 0x13B0, 0x13C0, 0x13D0, 0x13E0, + 0x13F0, 0x1400, 0x08C0, 0x08C0, 0x0D10, 0x1410, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1420, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x1430, 0x08C0, 0x0D10, +/* INDEX_BLOCK: -- 0x0300..0x033F -- */ + 0x1440, 0x1450, 0x1460, 0x1470, 0x0880, 0x0300, 0x0300, 0x0300, 0x0300, 0x1480, 0x0B20, 0x0300, + 0x0300, 0x0300, 0x0300, 0x1490, 0x14A0, 0x0300, 0x0300, 0x0880, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0C80, 0x14B0, 0x0300, 0x0300, 0x0D10, 0x0D10, 0x14C0, 0x0300, 0x0D10, 0x14D0, 0x14E0, 0x0D10, + 0x14F0, 0x1500, 0x0D10, 0x0D10, 0x14E0, 0x0D10, 0x0D10, 0x1500, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, +/* INDEX_BLOCK: -- 0x0340..0x037F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0380..0x03BF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x03C0..0x03FF -- */ + 0x0300, 0x1510, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0400..0x043F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0970, 0x0D10, 0x0D10, 0x0D10, + 0x1520, 0x0300, 0x0300, 0x0E60, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1530, 0x0300, 0x1540, 0x08C0, + 0x00D0, 0x00D0, 0x1550, 0x1560, 0x00D0, 0x1570, 0x0300, 0x0300, 0x0300, 0x0300, 0x1580, 0x1590, + 0x01F0, 0x15A0, 0x15B0, 0x15C0, 0x00D0, 0x00D0, 0x00D0, 0x15D0, 0x15E0, 0x15F0, 0x1600, 0x1610, + 0x1620, 0x1630, 0x08C0, 0x1640, +/* INDEX_BLOCK: -- 0x0440..0x047F -- */ + 0x1650, 0x0300, 0x1660, 0x1670, 0x0300, 0x0300, 0x0300, 0x1680, 0x1690, 0x0300, 0x0300, 0x16A0, + 0x16B0, 0x0C00, 0x0200, 0x16C0, 0x0400, 0x0300, 0x16D0, 0x0300, 0x16E0, 0x16F0, 0x0300, 0x0970, + 0x04C0, 0x0300, 0x0300, 0x1700, 0x1710, 0x1720, 0x1730, 0x1740, 0x0300, 0x0300, 0x1750, 0x1760, + 0x1770, 0x1780, 0x0300, 0x1790, 0x0300, 0x0300, 0x0300, 0x17A0, 0x17B0, 0x17C0, 0x17D0, 0x17E0, + 0x17F0, 0x1800, 0x13A0, 0x00B0, 0x00B0, 0x1810, 0x1820, 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x0300, 0x0300, 0x1830, 0x0C00, +/* INDEX_BLOCK: -- 0x0480..0x04BF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1840, 0x0300, + 0x1850, 0x0300, 0x0300, 0x0CE0, +/* INDEX_BLOCK: -- 0x04C0..0x04FF -- */ + 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, + 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, + 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, + 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, + 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, 0x1860, + 0x1860, 0x1860, 0x1860, 0x1860, +/* INDEX_BLOCK: -- 0x0500..0x053F -- */ + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, +/* INDEX_BLOCK: -- 0x0540..0x057F -- */ + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0CC0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CF0, 0x08C0, 0x08C0, + 0x1880, 0x1890, 0x18A0, 0x18B0, 0x18C0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x18D0, + 0x18E0, 0x18F0, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0580..0x05BF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1900, 0x0D10, 0x0300, 0x0300, 0x0300, + 0x0300, 0x1910, 0x0300, 0x0300, 0x1920, 0x08C0, 0x08C0, 0x1930, 0x0200, 0x1940, 0x0200, 0x1950, + 0x1960, 0x1970, 0x1980, 0x1990, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x19A0, + 0x19B0, 0x0020, 0x0030, 0x0040, 0x0050, 0x19C0, 0x19D0, 0x19E0, 0x0300, 0x19F0, 0x0300, 0x0C80, + 0x1A00, 0x1A10, 0x1A20, 0x1A30, +/* INDEX_BLOCK: -- 0x05C0..0x05FF -- */ + 0x1A40, 0x0300, 0x0AC0, 0x1A50, 0x0CC0, 0x0CC0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0470, 0x1A60, 0x1100, 0x1100, 0x1A70, 0x1110, 0x1110, 0x1110, 0x1A80, + 0x1A90, 0x1AA0, 0x1AB0, 0x08C0, 0x08C0, 0x0D10, 0x0D10, 0x1AC0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0970, 0x0300, 0x0300, 0x0300, 0x0640, 0x1AD0, 0x1AE0, + 0x0300, 0x0300, 0x1AF0, 0x0300, 0x1B00, 0x0300, 0x0300, 0x1B10, 0x0300, 0x1B20, 0x0300, 0x0300, + 0x1B30, 0x1B40, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0600..0x063F -- */ + 0x0090, 0x0090, 0x1B50, 0x00B0, 0x00B0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CC0, 0x0C00, 0x0090, + 0x0090, 0x1B60, 0x00B0, 0x1B70, 0x0300, 0x0300, 0x1B80, 0x0300, 0x0300, 0x0300, 0x1B90, 0x1BA0, + 0x1BA0, 0x1BB0, 0x1BC0, 0x1BD0, 0x0300, 0x0300, 0x0300, 0x1840, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x1390, 0x0300, 0x0C70, 0x1B80, 0x08C0, 0x1BE0, 0x01B0, 0x01B0, 0x1BF0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0640..0x067F -- */ + 0x1C00, 0x0300, 0x0300, 0x1C10, 0x0300, 0x1C20, 0x0300, 0x1C30, 0x0300, 0x0C80, 0x1C40, 0x08C0, + 0x08C0, 0x08C0, 0x0300, 0x1C50, 0x0300, 0x1C60, 0x0300, 0x1C70, 0x0300, 0x0CF0, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x0300, 0x1C80, 0x1100, 0x1C90, 0x1100, 0x1100, 0x1CA0, 0x1CB0, 0x0300, 0x1CC0, + 0x1CD0, 0x1CE0, 0x0300, 0x1CF0, 0x0300, 0x1D00, 0x08C0, 0x08C0, 0x1D10, 0x0300, 0x1D20, 0x1D30, + 0x0300, 0x0300, 0x0300, 0x1D40, 0x0300, 0x1D50, 0x0300, 0x1D60, 0x0300, 0x1D70, 0x1D80, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0680..0x06BF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0C40, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x0090, 0x1D90, + 0x00B0, 0x00B0, 0x00B0, 0x1DA0, 0x0300, 0x0300, 0x1DB0, 0x0C00, 0x1DC0, 0x0090, 0x1DD0, 0x00B0, + 0x1DE0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x1100, 0x1DF0, 0x0300, 0x0300, 0x1E00, 0x1E10, 0x1E20, 0x1E30, 0x08C0, 0x1E40, + 0x0300, 0x1D00, 0x1E50, 0x0300, 0x03E0, 0x1E60, 0x08C0, 0x0300, 0x1E70, 0x08C0, 0x08C0, 0x0300, + 0x1E80, 0x08C0, 0x0300, 0x1390, +/* INDEX_BLOCK: -- 0x06C0..0x06FF -- */ + 0x1E90, 0x0300, 0x0300, 0x1EA0, 0x1EB0, 0x1C90, 0x1EC0, 0x1ED0, 0x0DF0, 0x0300, 0x0300, 0x1EE0, + 0x1EF0, 0x0300, 0x0C40, 0x0C00, 0x1F00, 0x0300, 0x1F10, 0x1F20, 0x1F30, 0x0300, 0x0300, 0x1F40, + 0x0DF0, 0x0300, 0x0300, 0x1F50, 0x1F60, 0x1F70, 0x1F80, 0x1F90, 0x0300, 0x0610, 0x1FA0, 0x1FB0, + 0x1FC0, 0x08C0, 0x08C0, 0x08C0, 0x1FD0, 0x1FE0, 0x1FF0, 0x0300, 0x0300, 0x2000, 0x2010, 0x0C00, + 0x2020, 0x0530, 0x0540, 0x2030, 0x2040, 0x2050, 0x2060, 0x2070, 0x2080, 0x0300, 0x0300, 0x2090, + 0x20A0, 0x20B0, 0x20C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0700..0x073F -- */ + 0x0300, 0x0300, 0x0300, 0x20D0, 0x20E0, 0x20F0, 0x1E10, 0x08C0, 0x0300, 0x0300, 0x0300, 0x2100, + 0x2110, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x2120, 0x2130, 0x2140, 0x2150, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, 0x2160, + 0x2170, 0x0C00, 0x2180, 0x08C0, 0x0300, 0x0300, 0x2190, 0x21A0, 0x0C00, 0x21B0, 0x21C0, 0x08C0, + 0x0300, 0x21D0, 0x21E0, 0x21F0, 0x1390, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0740..0x077F -- */ + 0x0300, 0x0300, 0x1FA0, 0x2200, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0090, 0x0090, + 0x00B0, 0x00B0, 0x0940, 0x2210, 0x2220, 0x2230, 0x0300, 0x2240, 0x2250, 0x0C00, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x2260, 0x0300, 0x0300, 0x2270, 0x2280, 0x08C0, 0x2290, 0x0300, 0x0300, 0x22A0, + 0x22B0, 0x22C0, 0x0300, 0x0300, 0x22D0, 0x22E0, 0x22F0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C40, + 0x2300, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2310, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x2320, 0x0C00, +/* INDEX_BLOCK: -- 0x0780..0x07BF -- */ + 0x0540, 0x0300, 0x2120, 0x2330, 0x2340, 0x0940, 0x0AF0, 0x2350, 0x0300, 0x2360, 0x2370, 0x2380, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2390, 0x0300, 0x0300, 0x23A0, 0x23B0, 0x0C00, 0x23C0, 0x0300, + 0x23D0, 0x23E0, 0x0C00, 0x0300, 0x0300, 0x23F0, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x2400, + 0x2410, 0x0730, 0x0300, 0x2420, 0x2430, 0x2440, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0640, + 0x1100, 0x2450, 0x2460, 0x2470, +/* INDEX_BLOCK: -- 0x07C0..0x07FF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CF0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0800..0x083F -- */ + 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x2480, 0x2490, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x1840, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0840..0x087F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0880..0x08BF -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x24A0, +/* INDEX_BLOCK: -- 0x08C0..0x08FF -- */ + 0x0300, 0x0300, 0x0300, 0x24B0, 0x24C0, 0x24D0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0900..0x093F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0470, +/* INDEX_BLOCK: -- 0x0940..0x097F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x1390, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0980..0x09BF -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x24E0, 0x24F0, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x09C0..0x09FF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C40, + 0x0300, 0x0C80, 0x1720, 0x0300, 0x0300, 0x0300, 0x0300, 0x0C80, 0x0C00, 0x0300, 0x0CC0, 0x2500, + 0x0300, 0x0300, 0x0300, 0x2510, 0x2520, 0x2530, 0x2540, 0x2550, 0x0300, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0A00..0x0A3F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2560, 0x0300, 0x2570, 0x0C00, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0090, 0x0090, 0x00B0, 0x00B0, 0x1100, 0x2580, 0x0090, 0x2590, 0x00B0, 0x25A0, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x0300, 0x0300, 0x25B0, 0x25C0, 0x25D0, 0x25D0, 0x25E0, 0x25F0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x2600, 0x2610, +/* INDEX_BLOCK: -- 0x0A40..0x0A7F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0C70, 0x08C0, 0x2620, 0x0300, 0x0C80, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x2630, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0A80..0x0ABF -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x2640, +/* INDEX_BLOCK: -- 0x0AC0..0x0AFF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x2630, 0x2650, 0x08C0, 0x2660, 0x2670, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CE0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0B00..0x0B3F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0470, 0x0970, 0x0C40, 0x2680, 0x2690, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0B40..0x0B7F -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x26A0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x26B0, 0x0D10, 0x1AB0, 0x0D10, 0x26C0, + 0x0200, 0x0200, 0x0D80, 0x0200, 0x26D0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x1420, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0B80..0x0BBF -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x1430, 0x0D10, 0x0D10, 0x26E0, 0x0D10, 0x0D10, 0x0D10, 0x26F0, 0x2700, + 0x2710, 0x0D10, 0x2720, 0x0D10, 0x0D10, 0x0D10, 0x1200, 0x08C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x2730, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1100, 0x2740, 0x1100, 0x2740, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1520, 0x1100, 0x1CD0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0BC0..0x0BFF -- */ + 0x0090, 0x2750, 0x00B0, 0x2760, 0x2770, 0x2780, 0x0F20, 0x0090, 0x2790, 0x27A0, 0x27B0, 0x27C0, + 0x27D0, 0x0090, 0x2750, 0x00B0, 0x27E0, 0x27F0, 0x00B0, 0x2800, 0x2810, 0x2820, 0x2830, 0x0090, + 0x2840, 0x00B0, 0x0090, 0x2750, 0x00B0, 0x2760, 0x2770, 0x00B0, 0x0F20, 0x0090, 0x2790, 0x2830, + 0x0090, 0x2840, 0x00B0, 0x0090, 0x2750, 0x00B0, 0x2850, 0x0090, 0x2860, 0x2870, 0x2880, 0x2890, + 0x00B0, 0x28A0, 0x0090, 0x28B0, 0x28C0, 0x28D0, 0x28E0, 0x00B0, 0x28F0, 0x0090, 0x2900, 0x00B0, + 0x2910, 0x21B0, 0x21B0, 0x21B0, +/* INDEX_BLOCK: -- 0x0C00..0x0C3F -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0200, 0x0200, 0x0200, 0x2920, + 0x0200, 0x0200, 0x2930, 0x2940, 0x2950, 0x2960, 0x02D0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0C40..0x0C7F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x2970, 0x2980, 0x2990, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0C80..0x0CBF -- */ + 0x29A0, 0x29B0, 0x29C0, 0x01B0, 0x01B0, 0x01B0, 0x29D0, 0x08C0, 0x29E0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0300, 0x0970, 0x29F0, 0x2A00, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x2A10, 0x08C0, 0x0300, 0x0300, 0x2A20, 0x2A30, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0CC0..0x0CFF -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x0300, 0x2A40, 0x0C00, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x24E0, 0x2A50, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0300, 0x0C80, 0x2A60, 0x2A70, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x2A80, 0x0C80, +/* INDEX_BLOCK: -- 0x0D00..0x0D3F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x2A90, 0x26D0, 0x08C0, 0x08C0, 0x0090, 0x0090, 0x2790, 0x00B0, 0x2AA0, 0x1720, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0D40..0x0D7F -- */ + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1F80, 0x1100, 0x1100, 0x2AB0, 0x2AC0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x1F80, 0x1100, 0x2AD0, 0x2AE0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x2AF0, 0x0300, 0x2B00, 0x2B10, + 0x2B20, 0x2B30, 0x2B40, 0x2B50, 0x2B60, 0x0CE0, 0x2B70, 0x0CE0, 0x08C0, 0x08C0, 0x08C0, 0x2B80, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0D80..0x0DBF -- */ + 0x0D10, 0x0D10, 0x2B90, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x1420, 0x14D0, 0x2BA0, + 0x2BA0, 0x2BA0, 0x0D10, 0x1430, 0x2BB0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x2BC0, 0x08C0, 0x08C0, 0x08C0, 0x2BD0, 0x0D10, 0x2BE0, 0x0D10, 0x0D10, 0x2B90, + 0x2BF0, 0x2C00, 0x1430, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x2C10, +/* INDEX_BLOCK: -- 0x0DC0..0x0DFF -- */ + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x2C20, 0x1AA0, 0x1AA0, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0B00, 0x2B90, 0x1AB0, +/* INDEX_BLOCK: -- 0x0E00..0x0E3F -- */ + 0x2B90, 0x0D10, 0x0D10, 0x0D10, 0x2C30, 0x0B00, 0x0D10, 0x0D10, 0x2C30, 0x0D10, 0x2BC0, 0x2B90, + 0x2C00, 0x2C40, 0x08C0, 0x08C0, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, + 0x0D10, 0x2C30, 0x2BC0, 0x1AA0, 0x2C50, 0x0D10, 0x0D10, 0x0D10, 0x2C60, 0x2C70, 0x2C80, 0x2BF0, + 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x0D10, 0x2C90, 0x0D10, 0x0D10, + 0x0D10, 0x0D10, 0x0D10, 0x2CA0, +/* INDEX_BLOCK: -- 0x0E40..0x0E7F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x08C0, 0x08C0, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0E80..0x0EBF -- */ + 0x0300, 0x0CC0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0EC0..0x0EFF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CC0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x0F00..0x0F3F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0640, 0x0300, +/* INDEX_BLOCK: -- 0x0F40..0x0F7F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0CC0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0F80..0x0FBF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CC0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x0FC0..0x0FFF -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0470, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, +/* INDEX_BLOCK: -- 0x1000..0x103F -- */ + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0CF0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x1040..0x107F -- */ + 0x2CB0, 0x08C0, 0x24B0, 0x24B0, 0x24B0, 0x24B0, 0x24B0, 0x24B0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, 0x08C0, + 0x08C0, 0x08C0, 0x08C0, 0x08C0, +/* INDEX_BLOCK: -- 0x1080..0x10BF -- */ + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, 0x1870, + 0x1870, 0x1870, 0x1870, 0x2CC0 +}; + +static const SBUInt16 BranchGeneralCategoryIndexes[1088] = { + 0x0000, 0x0040, 0x0080, 0x00C0, 0x0100, 0x0140, 0x0180, 0x01C0, 0x0200, 0x0240, 0x0280, 0x02C0, + 0x0300, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0380, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x03C0, 0x0400, 0x0440, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0480, 0x04C0, 0x04C0, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, 0x0740, 0x0780, + 0x07C0, 0x0800, 0x0840, 0x0880, 0x0340, 0x08C0, 0x0340, 0x0340, 0x0900, 0x0940, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0980, 0x0840, 0x09C0, 0x0A00, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0A40, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0A80, + 0x0AC0, 0x0840, 0x0840, 0x0B00, 0x0840, 0x0840, 0x0840, 0x0B40, 0x0B80, 0x0BC0, 0x0C00, 0x0C40, + 0x0C80, 0x0CC0, 0x0D00, 0x0D40, 0x0D80, 0x0DC0, 0x0E00, 0x0840, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x0E40, 0x0340, 0x0340, 0x0340, 0x0340, 0x0E80, 0x0340, 0x0340, 0x0340, 0x0340, 0x0EC0, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0F00, 0x0F40, 0x0840, 0x0840, 0x0F80, 0x0840, + 0x0340, 0x0340, 0x0340, 0x0340, 0x0FC0, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, 0x0340, + 0x0340, 0x1000, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x1040, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, 0x0840, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x1080, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, + 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x0500, 0x1080 +}; + +SB_INTERNAL SBGeneralCategory LookupGeneralCategory(SBCodepoint codepoint) { + if (codepoint <= 0x10FFFF) { + return PrimaryGeneralCategoryData[ + MainGeneralCategoryIndexes[ + BranchGeneralCategoryIndexes[ + codepoint / 0x0400 + ] + (codepoint % 0x0400) / 0x0010 + ] + (codepoint % 0x0010) + ]; + } + + return Cn; +} + +#undef Cc +#undef Cf +#undef Cn +#undef Co +#undef Cs +#undef Ll +#undef Lm +#undef Lo +#undef Lt +#undef Lu +#undef Mc +#undef Me +#undef Mn +#undef Nd +#undef Nl +#undef No +#undef Pc +#undef Pd +#undef Pe +#undef Pf +#undef Pi +#undef Po +#undef Ps +#undef Sc +#undef Sk +#undef Sm +#undef So +#undef Zl +#undef Zp +#undef Zs diff --git a/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.h b/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.h new file mode 100644 index 000000000..7d21f7f78 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/GeneralCategoryLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H +#define _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H + +#include +#include +#include +#include + +SB_INTERNAL SBGeneralCategory LookupGeneralCategory(SBCodepoint codepoint); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/IsolatingRun.c b/src/thirdparty/SheenBidi/Source/IsolatingRun.c new file mode 100644 index 000000000..86ce9cd9a --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/IsolatingRun.c @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "BidiChain.h" +#include "BracketQueue.h" +#include "BracketType.h" +#include "LevelRun.h" +#include "PairingLookup.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBLog.h" +#include "IsolatingRun.h" + +static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun); + +static void AttachLevelRunLinks(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + const LevelRun *baseLevelRun = isolatingRun->baseLevelRun; + const LevelRun *current; + const LevelRun *next; + + isolatingRun->_originalLink = BidiChainGetNext(chain, chain->roller); + BidiChainSetNext(chain, chain->roller, baseLevelRun->firstLink); + + /* Iterate over level runs and attach their links to form an isolating run. */ + for (current = baseLevelRun; (next = current->next); current = next) { + BidiChainSetNext(chain, current->lastLink, next->firstLink); + } + BidiChainSetNext(chain, current->lastLink, chain->roller); + + isolatingRun->_lastLevelRun = current; + isolatingRun->_sos = RunExtrema_SOR(baseLevelRun->extrema); + + if (!RunKindIsPartialIsolate(baseLevelRun->kind)) { + isolatingRun->_eos = RunExtrema_EOR(current->extrema); + } else { + SBLevel paragraphLevel = isolatingRun->paragraphLevel; + SBLevel runLevel = baseLevelRun->level; + SBLevel eosLevel = (runLevel > paragraphLevel ? runLevel : paragraphLevel); + isolatingRun->_eos = ((eosLevel & 1) ? SBBidiTypeR : SBBidiTypeL); + } +} + +static void AttachOriginalLinks(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + const LevelRun *current; + + BidiChainSetNext(chain, chain->roller, isolatingRun->_originalLink); + + /* Iterate over level runs and attach original subsequent links. */ + for (current = isolatingRun->baseLevelRun; current; current = current->next) { + BidiChainSetNext(chain, current->lastLink, current->subsequentLink); + } +} + +static BidiLink ResolveWeakTypes(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorLink; + SBBidiType sos; + + SBBidiType w1PriorType; + SBBidiType w2StrongType; + SBBidiType w4PriorType; + SBBidiType w5PriorType; + SBBidiType w7StrongType; + + priorLink = roller; + sos = isolatingRun->_sos; + + w1PriorType = sos; + w2StrongType = sos; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBoolean forceMerge = SBFalse; + + /* Rule W1 */ + if (type == SBBidiTypeNSM) { + /* Change the 'type' variable as well because it can be EN on which W2 depends. */ + type = (SBBidiTypeIsIsolate(w1PriorType) ? SBBidiTypeON : w1PriorType); + BidiChainSetType(chain, link, type); + + /* Fix for 3rd point of rule N0. */ + if (w1PriorType == SBBidiTypeON) { + forceMerge = SBTrue; + } + } + w1PriorType = type; + + /* Rule W2 */ + if (type == SBBidiTypeEN) { + if (w2StrongType == SBBidiTypeAL) { + BidiChainSetType(chain, link, SBBidiTypeAN); + } + } + /* + * Rule W3 + * NOTE: It is safe to apply W3 in 'else-if' statement because it only depends on type AL. + * Even if W2 changes EN to AN, there won't be any harm. + */ + else if (type == SBBidiTypeAL) { + BidiChainSetType(chain, link, SBBidiTypeR); + } + + if (SBBidiTypeIsStrong(type)) { + /* Save the strong type as it is checked in W2. */ + w2StrongType = type; + } + + if ((type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) || forceMerge) { + BidiChainAbsorbNext(chain, priorLink); + } else { + priorLink = link; + } + } + + priorLink = roller; + w4PriorType = sos; + w5PriorType = sos; + w7StrongType = sos; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBidiType nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link)); + + /* Rule W4 */ + if (BidiChainIsSingle(chain, link) + && SBBidiTypeIsNumberSeparator(type) + && SBBidiTypeIsNumber(w4PriorType) + && (w4PriorType == nextType) + && (w4PriorType == SBBidiTypeEN || type == SBBidiTypeCS)) + { + /* Change the current type as well because it can be EN on which W5 depends. */ + type = w4PriorType; + BidiChainSetType(chain, link, type); + } + w4PriorType = type; + + /* Rule W5 */ + if (type == SBBidiTypeET && (w5PriorType == SBBidiTypeEN || nextType == SBBidiTypeEN)) { + /* Change the current type as well because it is EN on which W7 depends. */ + type = SBBidiTypeEN; + BidiChainSetType(chain, link, type); + } + w5PriorType = type; + + switch (type) { + /* Rule W6 */ + case SBBidiTypeET: + case SBBidiTypeCS: + case SBBidiTypeES: + BidiChainSetType(chain, link, SBBidiTypeON); + break; + + /* + * Rule W7 + * NOTE: W7 is expected to be applied after W6. However this is not the case here. The + * reason is that W6 can only create the type ON which is not tested in W7 by any + * means. So it won't affect the algorithm. + */ + case SBBidiTypeEN: + if (w7StrongType == SBBidiTypeL) { + BidiChainSetType(chain, link, SBBidiTypeL); + } + break; + + /* + * Save the strong type for W7. + * NOTE: The strong type is expected to be saved after applying W7 because W7 itself creates + * a strong type. However the strong type being saved here is based on the type after + * W5. This won't effect the algorithm because a single link contains all consecutive + * EN types. This means that even if W7 creates a strong type, it will be saved in + * next iteration. + */ + case SBBidiTypeL: + case SBBidiTypeR: + w7StrongType = type; + break; + } + + if (type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) { + BidiChainAbsorbNext(chain, priorLink); + } else { + priorLink = link; + } + } + + return priorLink; +} + +static SBBoolean ResolveBrackets(IsolatingRunRef isolatingRun) +{ + const SBCodepointSequence *sequence = isolatingRun->codepointSequence; + SBUInteger paragraphOffset = isolatingRun->paragraphOffset; + BracketQueueRef queue = &isolatingRun->_bracketQueue; + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorStrongLink; + SBLevel runLevel; + + priorStrongLink = BidiLinkNone; + runLevel = isolatingRun->baseLevelRun->level; + + BracketQueueReset(queue, SBLevelAsNormalBidiType(runLevel)); + + BidiChainForEach(chain, roller, link) { + SBUInteger stringIndex; + SBCodepoint codepoint; + SBBidiType type; + + SBCodepoint bracketValue; + BracketType bracketType; + + type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeON: + stringIndex = BidiChainGetOffset(chain, link) + paragraphOffset; + codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + bracketValue = LookupBracketPair(codepoint, &bracketType); + + switch (bracketType) { + case BracketTypeOpen: + if (BracketQueueGetOpenPairCount(queue) >= BracketQueueMaxOpenPairs) { + /* Stop further processing. */ + return SBTrue; + } + if (!BracketQueueEnqueue(queue, priorStrongLink, link, bracketValue)) { + return SBFalse; + } + break; + + case BracketTypeClose: + BracketQueueClosePair(queue, link, codepoint); + break; + } + break; + + case SBBidiTypeEN: + case SBBidiTypeAN: + type = SBBidiTypeR; + + case SBBidiTypeR: + case SBBidiTypeL: + BracketQueueAssignInnerStrongType(queue, type); + priorStrongLink = link; + break; + } + } + + BracketQueueMarkPopulated(queue); + ResolveAvailableBracketPairs(isolatingRun); + + return SBTrue; +} + +static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun) +{ + BracketQueueRef queue = &isolatingRun->_bracketQueue; + BidiChainRef chain = isolatingRun->bidiChain; + + SBLevel runLevel; + SBBidiType embeddingDirection; + SBBidiType oppositeDirection; + + runLevel = isolatingRun->baseLevelRun->level; + embeddingDirection = SBLevelAsNormalBidiType(runLevel); + oppositeDirection = SBLevelAsOppositeBidiType(runLevel); + + while (queue->pairCount > 0) { + BidiLink openingLink = BracketQueueGetOpeningLink(queue); + BidiLink closingLink = BracketQueueGetClosingLink(queue); + SBBidiType innerStrongType = BracketQueueGetInnerStrongType(queue); + SBBidiType pairType; + + /* Rule: N0.b */ + if (innerStrongType == embeddingDirection) { + pairType = innerStrongType; + } + /* Rule: N0.c */ + else if (innerStrongType == oppositeDirection) { + BidiLink priorStrongLink; + SBBidiType priorStrongType; + + priorStrongLink = BracketQueueGetPriorStrongLink(queue); + + if (priorStrongLink != BidiLinkNone) { + BidiLink link; + + priorStrongType = BidiChainGetType(chain, priorStrongLink); + if (SBBidiTypeIsNumber(priorStrongType)) { + priorStrongType = SBBidiTypeR; + } + + link = BidiChainGetNext(chain, priorStrongLink); + + /* + * Iterate over in-between links to find the proper prior strong type because there + * might be resolved brackets with different strong types. + */ + while (link != openingLink) { + SBBidiType type = BidiChainGetType(chain, link); + if (type == SBBidiTypeL || type == SBBidiTypeR) { + priorStrongType = type; + } + + link = BidiChainGetNext(chain, link); + } + } else { + priorStrongType = isolatingRun->_sos; + } + + /* Rule: N0.c.1 */ + if (priorStrongType == oppositeDirection) { + pairType = oppositeDirection; + } + /* Rule: N0.c.2 */ + else { + pairType = embeddingDirection; + } + } + /* Rule: N0.d */ + else { + pairType = SBBidiTypeNil; + } + + if (pairType != SBBidiTypeNil) { + /* Do the substitution */ + BidiChainSetType(chain, openingLink, pairType); + BidiChainSetType(chain, closingLink, pairType); + } + + BracketQueueDequeue(queue); + } +} + +static void ResolveNeutrals(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + SBLevel runLevel; + SBBidiType strongType; + BidiLink neutralLink; + + runLevel = isolatingRun->baseLevelRun->level; + strongType = isolatingRun->_sos; + neutralLink = BidiLinkNone; + + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBBidiType nextType; + + SBAssert(SBBidiTypeIsStrongOrNumber(type) || SBBidiTypeIsNeutralOrIsolate(type)); + + switch (type) { + case SBBidiTypeL: + strongType = SBBidiTypeL; + break; + + case SBBidiTypeR: + case SBBidiTypeEN: + case SBBidiTypeAN: + strongType = SBBidiTypeR; + break; + + case SBBidiTypeB: + case SBBidiTypeS: + case SBBidiTypeWS: + case SBBidiTypeON: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + if (neutralLink == BidiLinkNone) { + neutralLink = link; + } + + nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link)); + if (SBBidiTypeIsNumber(nextType)) { + nextType = SBBidiTypeR; + } else if (nextType == SBBidiTypeNil) { + nextType = isolatingRun->_eos; + } + + if (SBBidiTypeIsStrong(nextType)) { + /* Rules N1, N2 */ + SBBidiType resolvedType = (strongType == nextType + ? strongType + : SBLevelAsNormalBidiType(runLevel)); + + do { + BidiChainSetType(chain, neutralLink, resolvedType); + neutralLink = BidiChainGetNext(chain, neutralLink); + } while (neutralLink != BidiChainGetNext(chain, link)); + + neutralLink = BidiLinkNone; + } + break; + } + } +} + +static void ResolveImplicitLevels(IsolatingRunRef isolatingRun) +{ + BidiChainRef chain = isolatingRun->bidiChain; + BidiLink roller = chain->roller; + BidiLink link; + + SBLevel runLevel = isolatingRun->baseLevelRun->level; + + if ((runLevel & 1) == 0) { + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBLevel level = BidiChainGetLevel(chain, link); + + SBAssert(SBBidiTypeIsStrongOrNumber(type)); + + /* Rule I1 */ + if (type == SBBidiTypeR) { + BidiChainSetLevel(chain, link, level + 1); + } else if (type != SBBidiTypeL) { + BidiChainSetLevel(chain, link, level + 2); + } + } + } else { + BidiChainForEach(chain, roller, link) { + SBBidiType type = BidiChainGetType(chain, link); + SBLevel level = BidiChainGetLevel(chain, link); + + SBAssert(SBBidiTypeIsStrongOrNumber(type)); + + /* Rule I2 */ + if (type != SBBidiTypeR) { + BidiChainSetLevel(chain, link, level + 1); + } + } + } +} + +SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun, MemoryRef memory) +{ + BracketQueueInitialize(&isolatingRun->_bracketQueue, memory); +} + +SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun) +{ + BidiLink lastLink; + BidiLink subsequentLink; + + SB_LOG_BLOCK_OPENER("Identified Isolating Run"); + + /* Attach level run links to form isolating run. */ + AttachLevelRunLinks(isolatingRun); + /* Save last subsequent link. */ + subsequentLink = isolatingRun->_lastLevelRun->subsequentLink; + + SB_LOG_STATEMENT("Range", 1, SB_LOG_RUN_RANGE(isolatingRun)); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_STATEMENT("Level", 1, SB_LOG_LEVEL(isolatingRun->baseLevelRun->level)); + SB_LOG_STATEMENT("SOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_sos)); + SB_LOG_STATEMENT("EOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_eos)); + + /* Rules W1-W7 */ + lastLink = ResolveWeakTypes(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Weak Types"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rule N0 */ + if (!ResolveBrackets(isolatingRun)) { + return SBFalse; + } + + SB_LOG_BLOCK_OPENER("Resolved Brackets"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rules N1, N2 */ + ResolveNeutrals(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Neutrals"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Rules I1, I2 */ + ResolveImplicitLevels(isolatingRun); + SB_LOG_BLOCK_OPENER("Resolved Implicit Levels"); + SB_LOG_STATEMENT("Levels", 1, SB_LOG_RUN_LEVELS(isolatingRun)); + SB_LOG_BLOCK_CLOSER(); + + /* Re-attach original links. */ + AttachOriginalLinks(isolatingRun); + /* Attach new final link (of isolating run) with last subsequent link. */ + BidiChainSetNext(isolatingRun->bidiChain, lastLink, subsequentLink); + + SB_LOG_BLOCK_CLOSER(); + + return SBTrue; +} diff --git a/src/thirdparty/SheenBidi/Source/IsolatingRun.h b/src/thirdparty/SheenBidi/Source/IsolatingRun.h new file mode 100644 index 000000000..5d1254c9c --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/IsolatingRun.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ISOLATING_RUN_H +#define _SB_INTERNAL_ISOLATING_RUN_H + +#include + +#include "BidiChain.h" +#include "BracketQueue.h" +#include "LevelRun.h" +#include "Memory.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" + +typedef struct _IsolatingRun { + const SBCodepointSequence *codepointSequence; + const SBBidiType *bidiTypes; + BidiChainRef bidiChain; + const LevelRun *baseLevelRun; + const LevelRun *_lastLevelRun; + BracketQueue _bracketQueue; + SBUInteger paragraphOffset; + BidiLink _originalLink; + SBBidiType _sos; + SBBidiType _eos; + SBLevel paragraphLevel; +} IsolatingRun, *IsolatingRunRef; + +SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun, MemoryRef memory); +SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/LevelRun.c b/src/thirdparty/SheenBidi/Source/LevelRun.c new file mode 100644 index 000000000..1557d3aa8 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/LevelRun.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "BidiChain.h" +#include "RunExtrema.h" +#include "RunKind.h" +#include "SBAssert.h" +#include "LevelRun.h" + +SB_INTERNAL void LevelRunInitialize(LevelRun *levelRun, + BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink, + SBBidiType sor, SBBidiType eor) +{ + SBBidiType firstType = BidiChainGetType(bidiChain, firstLink); + SBBidiType lastType = BidiChainGetType(bidiChain, lastLink); + + levelRun->next = NULL; + levelRun->firstLink = firstLink; + levelRun->lastLink = lastLink; + levelRun->subsequentLink = BidiChainGetNext(bidiChain, lastLink); + levelRun->extrema = RunExtremaMake(sor, eor); + levelRun->kind = RunKindMake + ( + SBBidiTypeIsIsolateInitiator(lastType), + SBBidiTypeIsIsolateTerminator(firstType) + ); + levelRun->level = BidiChainGetLevel(bidiChain, firstLink); +} + +SB_INTERNAL void LevelRunAttach(LevelRun *levelRun, LevelRun *next) +{ + /* Only the runs of same level can be attached. */ + SBAssert(levelRun->level == next->level); + /* No other run can be attached with a simple run. */ + SBAssert(!RunKindIsSimple(levelRun->kind)); + /* No other run can be attached with a complete isolating run. */ + SBAssert(!RunKindIsCompleteIsolate(levelRun->kind)); + /* Only a terminating run can be attached with an isolating run. */ + SBAssert(RunKindIsIsolate(levelRun->kind) && RunKindIsTerminating(next->kind)); + /* The next run must be unattached. */ + SBAssert(!RunKindIsAttachedTerminating(next->kind)); + + if (RunKindIsTerminating(next->kind)) { + RunKindMakeAttached(next->kind); + } + + if (RunKindIsIsolate(levelRun->kind)) { + RunKindMakeComplete(levelRun->kind); + } + + levelRun->next = next; +} diff --git a/src/thirdparty/SheenBidi/Source/LevelRun.h b/src/thirdparty/SheenBidi/Source/LevelRun.h new file mode 100644 index 000000000..6ae1ebdbc --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/LevelRun.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_LEVEL_RUN_H +#define _SB_INTERNAL_LEVEL_RUN_H + +#include + +#include "BidiChain.h" +#include "RunExtrema.h" +#include "RunKind.h" +#include "SBBase.h" + +typedef struct _LevelRun { + const struct _LevelRun *next; /**< Reference to the next sequence of run links. */ + BidiLink firstLink; /**< First link of the run. */ + BidiLink lastLink; /**< Last link of the run. */ + BidiLink subsequentLink; /**< Subsequent link of the run. */ + RunExtrema extrema; + RunKind kind; + SBLevel level; +} LevelRun; + +SB_INTERNAL void LevelRunInitialize(LevelRun *levelRun, + BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink, + SBBidiType sor, SBBidiType eor); +SB_INTERNAL void LevelRunAttach(LevelRun *levelRun, LevelRun *next); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/Memory.c b/src/thirdparty/SheenBidi/Source/Memory.c new file mode 100644 index 000000000..df8516573 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Memory.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "SBAllocator.h" +#include "SBAssert.h" +#include "Memory.h" + +/** + * Computes the total size required for a set of memory chunks. + */ +static SBUInteger CalculateTotalSize(const SBUInteger *chunkSizes, SBUInteger chunkCount) +{ + SBUInteger totalSize = 0; + SBUInteger index; + + for (index = 0; index < chunkCount; index++) { + totalSize += chunkSizes[index]; + } + + return totalSize; +} + +/** + * Splits a contiguous memory block into multiple logical chunks. + */ +static void SplitMemoryBlock(void *pointer, + const SBUInteger *chunkSizes, SBUInteger chunkCount, void **outPointers) +{ + SBUInt8 *chunkPointer = pointer; + SBUInteger offset = 0; + SBUInteger index; + + for (index = 0; index < chunkCount; index++) { + outPointers[index] = chunkPointer + offset; + offset += chunkSizes[index]; + } +} + +SB_INTERNAL void MemoryInitialize(MemoryRef memory) +{ + memory->_list = NULL; +} + +SB_INTERNAL void *MemoryAllocateBlock(MemoryRef memory, MemoryType type, SBUInteger size) +{ + void *pointer = NULL; + + /* Size MUST be greater than zero. */ + SBAssert(size > 0); + + if (type == MemoryTypeScratch) { + pointer = SBAllocatorAllocateScratch(NULL, size); + } + + if (!pointer) { + MemoryListRef memoryList = memory->_list; + + if (memoryList) { + const SBUInteger headerSize = sizeof(MemoryBlock); + + pointer = SBAllocatorAllocateBlock(NULL, headerSize + size); + + if (pointer) { + SBUInt8 *base = pointer; + MemoryBlockRef block; + + block = pointer; + block->next = NULL; + + memoryList->last->next = block; + memoryList->last = block; + + pointer = base + headerSize; + } + } else { + const SBUInteger headerSize = sizeof(MemoryList); + + pointer = SBAllocatorAllocateBlock(NULL, headerSize + size); + + if (pointer) { + SBUInt8 *base = pointer; + + memoryList = pointer; + memoryList->first.next = NULL; + memoryList->last = &memoryList->first; + + memory->_list = memoryList; + + pointer = base + headerSize; + } + } + } + + return pointer; +} + +SB_INTERNAL SBBoolean MemoryAllocateChunks(MemoryRef memory, MemoryType type, + const SBUInteger *chunkSizes, SBUInteger chunkCount, void **outPointers) +{ + SBUInteger totalSize = CalculateTotalSize(chunkSizes, chunkCount); + SBBoolean succeeded = SBFalse; + void *pointer; + + /* Total size MUST be greater than zero. */ + SBAssert(totalSize > 0); + + pointer = MemoryAllocateBlock(memory, type, totalSize); + + if (pointer) { + SplitMemoryBlock(pointer, chunkSizes, chunkCount, outPointers); + succeeded = SBTrue; + } + + return succeeded; +} + +SB_INTERNAL void MemoryFinalize(MemoryRef memory) +{ + MemoryListRef memoryList = memory->_list; + + if (memoryList) { + MemoryBlockRef block = &memoryList->first; + + while (block) { + MemoryBlockRef next = block->next; + /* Deallocate the block along with its data as they were allocated together. */ + SBAllocatorDeallocateBlock(NULL, block); + + block = next; + } + } +} diff --git a/src/thirdparty/SheenBidi/Source/Memory.h b/src/thirdparty/SheenBidi/Source/Memory.h new file mode 100644 index 000000000..268d784b0 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Memory.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_MEMORY_H +#define _SB_INTERNAL_MEMORY_H + +#include + +#include +#include + +/** + * Represents a single dynamically allocated memory block. + * Each block stores a pointer to the next block, forming a singly linked list. The usable memory + * begins immediately after the `MemoryBlock` structure. + */ +typedef struct _MemoryBlock { + struct _MemoryBlock *next; +} MemoryBlock, *MemoryBlockRef; + +/** + * Represents a linked list of memory blocks used for managing dynamic allocations. + * The list always includes a sentinel `first` block, and a pointer to the last block to allow + * efficient appending. + */ +typedef struct _MemoryList { + MemoryBlock first; + MemoryBlockRef last; +} MemoryList, *MemoryListRef; + +/** + * Base structure for managing internal memory allocations. + * Intended to be embedded in other structs (e.g., Object). + */ +typedef struct Memory { + MemoryListRef _list; +} Memory, *MemoryRef; + +enum { + MemoryTypePermanent = 0, + MemoryTypeScratch = 1 +}; +typedef SBUInt8 MemoryType; + +#define MemoryMake() { NULL } + +/** + * Initializes a Memory structure to prepare it for allocations. + * + * @param memory + * The Memory instance to initialize. + */ +SB_INTERNAL void MemoryInitialize(MemoryRef memory); + +/** + * Allocates a single contiguous memory block of the given size. The block is tracked internally + * and released by `MemoryFinalize()`. + * + * @param memory + * The Memory to allocate from. + * @param size + * Size of the memory block to allocate. + * @return + * Pointer to the allocated memory block, or NULL on failure. + */ +SB_INTERNAL void *MemoryAllocateBlock(MemoryRef memory, MemoryType type, SBUInteger size); + +/** + * Allocates a single contiguous memory block and splits it into multiple chunks. The entire memory + * block is tracked internally and released by `MemoryFinalize()`. + * + * @param memory + * The Memory to allocate from. + * @param chunkSizes + * Array of chunk sizes. + * @param chunkCount + * Number of chunks. + * @param outPointers + * Output array to receive chunk pointers. + * @return + * `SBTrue` if successful, `SBFalse` otherwise. + */ +SB_INTERNAL SBBoolean MemoryAllocateChunks(MemoryRef memory, MemoryType type, + const SBUInteger *chunkSizes, SBUInteger chunkCount, void **outPointers); + +/** + * Frees all memory blocks tracked by the given Memory. + * + * @param memory + * The Memory to finalize. + */ +SB_INTERNAL void MemoryFinalize(MemoryRef memory); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/Object.c b/src/thirdparty/SheenBidi/Source/Object.c new file mode 100644 index 000000000..752614b19 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Object.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "AtomicUInt.h" +#include "Memory.h" +#include "SBAssert.h" +#include "Object.h" + +SB_INTERNAL ObjectRef ObjectCreate(const SBUInteger *chunkSizes, SBUInteger chunkCount, + void **outPointers, FinalizeFunc finalizer) +{ + ObjectBaseRef base = NULL; + Memory memory; + + /* Number of chunks MUST be greater than or equal to one. */ + SBAssert(chunkCount >= 1); + /* Size of first chunk MUST be greater than the size of ObjectBase structure. */ + SBAssert(chunkSizes[0] > sizeof(ObjectBase)); + + MemoryInitialize(&memory); + + if (MemoryAllocateChunks(&memory, MemoryTypePermanent, chunkSizes, chunkCount, outPointers)) { + base = outPointers[0]; + base->memory = memory; + base->finalize = finalizer; + + AtomicUIntInitialize(&base->retainCount, 1); + } + + return base; +} + +SB_INTERNAL ObjectRef ObjectRetain(ObjectRef object) +{ + ObjectBaseRef base = (ObjectBaseRef)object; + + AtomicUIntIncrement(&base->retainCount); + + return object; +} + +SB_INTERNAL void ObjectRelease(ObjectRef object) +{ + ObjectBaseRef base = (ObjectBaseRef)object; + + if (AtomicUIntDecrement(&base->retainCount) == 0) { + if (base->finalize) { + base->finalize(object); + } + + MemoryFinalize(&base->memory); + } +} diff --git a/src/thirdparty/SheenBidi/Source/Object.h b/src/thirdparty/SheenBidi/Source/Object.h new file mode 100644 index 000000000..734594c42 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Object.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_OBJECT_H +#define _SB_INTERNAL_OBJECT_H + +#include + +#include +#include + +#include "AtomicUInt.h" +#include "Memory.h" + +/** + * Represents a generic reference-counted object backed by a memory arena. + */ +typedef void *ObjectRef; + +/** + * Function signature for finalizing a reference-counted object. + * This is called once the reference count reaches zero. + * + * @param object + * The object being finalized. + */ +typedef void (*FinalizeFunc)(ObjectRef object); + +/** + * Internal structure representing the base of an object. + */ +typedef struct ObjectBase { + Memory memory; + FinalizeFunc finalize; + AtomicUInt retainCount; +} ObjectBase, *ObjectBaseRef; + +#ifndef SB_CONFIG_ALLOW_NON_ATOMIC_FALLBACK + +#if !defined(HAS_ATOMIC_UINT_SUPPORT) +#error "No atomic operations available. For thread-unsafe reference counting, manually define \ +`SB_CONFIG_ALLOW_NON_ATOMIC_FALLBACK`." +#endif + +#endif + +#define ObjectBaseMake() { MemoryMake(), NULL, 0 } + +/** + * Creates a reference-counted object and allocates memory chunks for it. + * + * This function allocates a single contiguous memory block and divides it into chunks according to + * the provided `chunkSizes`. The addresses of these chunks are returned in the `outPointers` array. + * + * The first chunk (i.e., `outPointers[0]`) MUST correspond to a user-defined struct that has + * `ObjectBase` as its **first field**. This is critical because all Object-related functionalities + * such as reference counting, memory management, and finalization rely on being able to treat the + * object as an `ObjectBaseRef`. + * + * Example: + * ``` + * typedef struct MyObject { + * ObjectBase base; // MUST be first + * int field1; + * float field2; + * } MyObject; + * + * SBUInteger sizes[] = { sizeof(MyObject), otherSize1, otherSize2 }; + * void *pointers[3]; + * MyObject *obj = ObjectCreate(sizes, 3, pointers, FinalizeMyObject); + * ``` + * + * @param chunkSizes + * An array of sizes (in bytes) for each memory chunk. + * @param chunkCount + * Number of chunks (must be >= 1). + * @param outPointers + * Output array to receive the addresses of the allocated chunks. + * @param finalizer + * Optional function to finalize the object when its reference count drops to zero. + * @return + * A reference to the created object (same as `outPointers[0]`), or NULL if allocation failed. + */ +SB_INTERNAL ObjectRef ObjectCreate(const SBUInteger *chunkSizes, SBUInteger chunkCount, + void **outPointers, FinalizeFunc finalizer); + +/** + * Retains the object by incrementing its reference count. + * + * @param object + * The object to retain. + * @return + * The same object. + */ +SB_INTERNAL ObjectRef ObjectRetain(ObjectRef object); + +/** + * Releases the object by decrementing its reference count. When the count reaches zero, the + * finalizer (if any) is called, and all associated memory is freed. + * + * @param object + * The object to release. + */ +SB_INTERNAL void ObjectRelease(ObjectRef object); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/Once.c b/src/thirdparty/SheenBidi/Source/Once.c new file mode 100644 index 000000000..a4c2e3060 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Once.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ThreadFence.h" +#include "Once.h" + +SB_INTERNAL SBBoolean OnceTryExecute(OnceRef once, void(*func)(void *info), void *info) +{ + SBBoolean result = SBTrue; + + if (!once->executed) { + result = AtomicFlagTestAndSet(&once->flag) == SBFalse; + + if (result) { + func(info); + ThreadFence(); + once->executed = SBTrue; + } + } + + return result; +} diff --git a/src/thirdparty/SheenBidi/Source/Once.h b/src/thirdparty/SheenBidi/Source/Once.h new file mode 100644 index 000000000..6e1fda68c --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/Once.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ONCE_H +#define _SB_INTERNAL_ONCE_H + +#include +#include + +#include "AtomicFlag.h" +#include "ThreadFence.h" + +#if defined(HAS_ATOMIC_FLAG_SUPPORT) && defined(HAS_THREAD_FENCE_SUPPORT) +#define HAS_ONCE_SUPPORT +#endif + +typedef struct _Once { + SBBoolean executed; + AtomicFlag flag; +} Once, *OnceRef; + +#define OnceMake() { SBFalse, AtomicFlagMake() } + +SB_INTERNAL SBBoolean OnceTryExecute(OnceRef once, void(*func)(void *info), void *info); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/PairingLookup.c b/src/thirdparty/SheenBidi/Source/PairingLookup.c new file mode 100644 index 000000000..9cd706372 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/PairingLookup.c @@ -0,0 +1,267 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: (37)+2310+(617*2) = 3618 Bytes + */ + +#include "PairingLookup.h" + +static const SBInt16 PairDifferences[37] = { + 0, 1, -1, 2, -2, 16, -16, 3, -3, 2016, 2527, 1923, 1914, 1918, + 2250, 138, 7, -7, 1824, 2104, 2108, 2106, 1316, -138, 8, -8, -1316, + -1914, -1918, -1923, -1824, -2016, -2104, -2106, -2108, -2250, -2527 +}; + +static const SBUInt8 PairData[2310] = { +/* DATA_BLOCK: -- 0x0000..0x0069 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 132, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x006A..0x00D3 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, + 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x00D4..0x013D -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x013E..0x01A7 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x01A8..0x0211 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0212..0x027B -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x027C..0x02E5 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x02E6..0x034F -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 7, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 14, 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, 0, 0, + 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 1, + 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0350..0x03B9 -- */ + 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, + 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 19, 0, 20, 21, + 0, 21, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 22, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x03BA..0x0423 -- */ + 0, 1, 2, 1, 2, 23, 0, 0, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 0, 0, 1, 2, 24, 24, 24, 0, 16, 16, 0, 0, 25, 25, 25, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0424..0x048D -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, + 130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x048E..0x04F7 -- */ + 0, 0, 0, 1, 2, 65, 130, 0, 1, 2, 0, 3, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 0, 26, 1, 2, 0, 0, 0, 1, 2, 1, 2, + 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x04F8..0x0561 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 71, + 129, 66, 136, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 27, 0, 0, 0, 0, 28, + 0, 0, 29, 1, 2, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, +/* DATA_BLOCK: -- 0x0562..0x05CB -- */ + 2, 0, 1, 2, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, + 1, 2, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 2, 0, 0, + 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x05CC..0x0635 -- */ + 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, +/* DATA_BLOCK: -- 0x0636..0x069F -- */ + 1, 2, 1, 2, 1, 2, 1, 2, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32, + 0, 0, 0, 0, 33, 34, 33, 0, 0, 0, 0, 0, 0, 1, 2, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x06A0..0x0709 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x070A..0x0773 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, + 1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 1, 2, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, +/* DATA_BLOCK: -- 0x0774..0x07DD -- */ + 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 65, 130, 65, 130, 65, 130, 65, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x07DE..0x0847 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x0848..0x08B1 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, +/* DATA_BLOCK: -- 0x08B2..0x0905 -- */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, + 0, 132, 0, 65, 130, 0, 65, 130, +}; + +static const SBUInt16 PairIndexes[617] = { + 0x0000, 0x006A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x013E, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x01A8, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0212, 0x027C, 0x00D4, 0x00D4, 0x00D4, 0x02E6, 0x0350, + 0x03BA, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0424, + 0x048E, 0x00D4, 0x00D4, 0x00D4, 0x04F8, 0x0562, 0x05CC, 0x0636, 0x00D4, 0x00D4, 0x06A0, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x070A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0774, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, + 0x00D4, 0x00D4, 0x07DE, 0x0848, 0x08B2 +}; + +SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint) +{ + if (codepoint <= 0xFF63) { + SBInt16 diff = PairDifferences[ + PairData[ + PairIndexes[ + codepoint / 0x06A + ] + (codepoint % 0x06A) + ] & BracketTypeInverseMask + ]; + + if (diff != 0) { + return (codepoint + diff); + } + } + + return 0; +} + +SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *type) +{ + if (codepoint <= 0xFF63) { + SBUInt8 data = PairData[ + PairIndexes[ + codepoint / 0x06A + ] + (codepoint % 0x06A) + ]; + *type = (data & BracketTypePrimaryMask); + + if (*type != 0) { + SBInt16 diff = PairDifferences[ + data & BracketTypeInverseMask + ]; + return (codepoint + diff); + } + } else { + *type = BracketTypeNone; + } + + return 0; +} diff --git a/src/thirdparty/SheenBidi/Source/PairingLookup.h b/src/thirdparty/SheenBidi/Source/PairingLookup.h new file mode 100644 index 000000000..0b422aeb6 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/PairingLookup.h @@ -0,0 +1,18 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_PAIRING_LOOKUP_H +#define _SB_INTERNAL_PAIRING_LOOKUP_H + +#include +#include +#include + +#include "BracketType.h" + +SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint); +SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *bracketType); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/RunExtrema.h b/src/thirdparty/SheenBidi/Source/RunExtrema.h new file mode 100644 index 000000000..3ce68d340 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/RunExtrema.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_RUN_EXTREMA_H +#define _SB_INTERNAL_RUN_EXTREMA_H + +#include "SBBase.h" + +enum { + RunExtremaLeadingL = SBBidiTypeL << 0, + RunExtremaLeadingR = SBBidiTypeR << 0, + + RunExtremaTrailingL = SBBidiTypeL << 4, + RunExtremaTrailingR = SBBidiTypeR << 4 +}; +typedef SBUInt8 RunExtrema; + +#define RunExtremaMake(sor, eor) \ +(RunExtrema) \ +( \ + ((sor) << 0) \ + | ((eor) << 4) \ +) + +#define RunExtrema_SOR(e) \ +(RunExtrema) \ +( \ + (e) & 0xF \ +) + +#define RunExtrema_EOR(e) \ +(RunExtrema) \ +( \ + (e) >> 4 \ +) + +#endif diff --git a/src/thirdparty/SheenBidi/Source/RunKind.h b/src/thirdparty/SheenBidi/Source/RunKind.h new file mode 100644 index 000000000..ebda9fa55 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/RunKind.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2014-2019 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_RUN_KIND_H +#define _SB_INTERNAL_RUN_KIND_H + +#include "SBBase.h" + +enum { + RunKindSimple = 0x00, + + RunKindIsolate = 0x01, + RunKindPartial = 0x02, + RunKindPartialIsolate = RunKindIsolate | RunKindPartial, + + RunKindTerminating = 0x04, + RunKindAttached = 0x08 +}; +typedef SBUInt8 RunKind; + +#define RunKindMake(i, t) \ +( \ + ((i) ? RunKindPartialIsolate : 0) \ + | ((t) ? RunKindTerminating : 0) \ +) + +#define RunKindMakeComplete(k) \ +( \ + (k) &= ~RunKindPartial \ +) + +#define RunKindMakeAttached(k) \ +( \ + (k) |= RunKindAttached \ +) + +#define RunKindIsSimple(k) \ +( \ + (k) == RunKindSimple \ +) + +#define RunKindIsIsolate(k) \ +( \ + (k) & RunKindIsolate \ +) + +#define RunKindIsTerminating(k) \ +( \ + (k) & RunKindTerminating \ +) + +#define RunKindIsPartialIsolate(k) \ +( \ + (k) & RunKindPartial \ +) + +#define RunKindIsCompleteIsolate(k) \ +( \ + ((k) & RunKindPartialIsolate) \ + == RunKindIsolate \ +) + +#define RunKindIsAttachedTerminating(k) \ +( \ + (k) & RunKindAttached \ +) + +#endif diff --git a/src/thirdparty/SheenBidi/Source/RunQueue.c b/src/thirdparty/SheenBidi/Source/RunQueue.c new file mode 100644 index 000000000..c5cca5828 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/RunQueue.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "LevelRun.h" +#include "Memory.h" +#include "RunKind.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "RunQueue.h" + +#define MakeRunQueuePosition() \ + { NULL, SBInvalidIndex } +#define SetRunQueuePosition(rqi, _list, _index) \ + ((rqi).list = (_list), (rqi).index = (_index)) +#define IsInvalidRunQueuePosition(rqi) \ + ((rqi).list == NULL) + +static const RunQueuePosition InvalidRunQueuePosition = MakeRunQueuePosition(); + +static RunQueueListRef AllocateRunQueueListPool(RunQueueRef queue) +{ + const SBUInteger newCapacity = queue->count; + const SBUInteger embeddedCount = RunQueueListElementCount; + const SBUInteger listCount = (newCapacity + embeddedCount - 1) / embeddedCount; + const SBUInteger blockSize = sizeof(RunQueueList) * listCount; + RunQueueList *pool; + + pool = MemoryAllocateBlock(queue->_memory, MemoryTypeScratch, blockSize); + + if (pool) { + RunQueueListRef previous; + RunQueueListRef current; + SBUInteger index; + + /* First element. */ + current = &pool[0]; + current->previous = NULL; + previous = current; + + /* Middle elements. */ + for (index = 1; index < listCount - 1; index++) { + current = &pool[index]; + current->previous = previous; + previous->next = current; + previous = current; + } + + /* Last element. */ + current->previous = previous; + current->next = NULL; + } + + return pool; +} + +static void AddRunQueueListToReusablePool(RunQueueRef queue, RunQueueListRef list) +{ + RunQueueListRef head = queue->_listPool; + + if (head) { + head->previous = list; + } + + list->previous = NULL; + list->next = head; + + queue->_listPool = list; +} + +static RunQueueListRef GetReusableRunQueueList(RunQueueRef queue) +{ + RunQueueListRef head = queue->_listPool; + RunQueueListRef list = NULL; + + if (!head) { + head = AllocateRunQueueListPool(queue); + } + + if (head) { + list = head; + head = head->next; + + list->previous = NULL; + list->next = NULL; + + if (head) { + head->previous = NULL; + } + queue->_listPool = head; + } + + return list; +} + +static LevelRun *InsertRunQueueElement(RunQueueRef queue) +{ + RunQueueListRef rearList = queue->_rearList; + LevelRun *element = NULL; + + if ((queue->_rearTop + 1) < RunQueueListElementCount) { + queue->_rearTop += 1; + queue->count += 1; + + element = &rearList->elements[queue->_rearTop]; + } else { + RunQueueListRef previousList = rearList; + + rearList = GetReusableRunQueueList(queue); + + if (rearList) { + rearList->previous = previousList; + previousList->next = rearList; + + queue->_rearList = rearList; + queue->_rearTop = 0; + queue->count += 1; + + element = &rearList->elements[0]; + } + } + + return element; +} + +static void FindPreviousPartialRun(RunQueueRef queue) +{ + RunQueuePosition partial = queue->_lastPartialRun; + + if (!IsInvalidRunQueuePosition(partial)) { + RunQueuePosition front = queue->_front; + RunQueueListRef breakList = front.list->previous; + RunQueuePosition current; + + SetRunQueuePosition(current, partial.list, partial.index + 1); + + do { + SBUInteger start = (current.list == front.list ? front.index : 0); + + while (current.index-- > start) { + const LevelRun *levelRun = ¤t.list->elements[current.index]; + + if (RunKindIsPartialIsolate(levelRun->kind)) { + queue->_lastPartialRun = current; + return; + } + } + + current.list = current.list->previous; + current.index = RunQueueListElementCount; + } while (current.list != breakList); + + /* No more partial run. */ + queue->_lastPartialRun = InvalidRunQueuePosition; + } +} + +SB_INTERNAL void RunQueueInitialize(RunQueueRef queue, MemoryRef memory) +{ + queue->_memory = memory; + + /* Initialize first list. */ + queue->_firstList.previous = NULL; + queue->_firstList.next = NULL; + + /* Initialize rest of the elements. */ + queue->_listPool = NULL; + queue->_rearList = &queue->_firstList; + queue->_rearTop = SBInvalidIndex; + queue->_front = InvalidRunQueuePosition; + queue->_lastPartialRun = InvalidRunQueuePosition; + queue->count = 0; +} + +SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRun *levelRun) +{ + SBBoolean isEnqueued = SBFalse; + LevelRun *element; + + element = InsertRunQueueElement(queue); + + if (element) { + /* Copy the level run into the current element. */ + *element = *levelRun; + + /* Complete the latest isolating run with this terminating run. */ + if (!IsInvalidRunQueuePosition(queue->_lastPartialRun) + && RunKindIsTerminating(element->kind)) { + LevelRun *incompleteRun = &queue->_lastPartialRun.list->elements[queue->_lastPartialRun.index]; + LevelRunAttach(incompleteRun, element); + FindPreviousPartialRun(queue); + } + + /* Save the location of the isolating run. */ + if (RunKindIsIsolate(element->kind)) { + SetRunQueuePosition(queue->_lastPartialRun, queue->_rearList, queue->_rearTop); + } + + if (IsInvalidRunQueuePosition(queue->_front)) { + /* This is the first element in the queue. */ + SetRunQueuePosition(queue->_front, queue->_rearList, queue->_rearTop); + } + + isEnqueued = SBTrue; + } + + return isEnqueued; +} + +SB_INTERNAL void RunQueueDequeue(RunQueueRef queue) +{ + /* The queue should not be empty. */ + SBAssert(queue->count > 0); + + if ((queue->_front.index + 1) < RunQueueListElementCount) { + queue->_front.index += 1; + } else { + RunQueueListRef frontList = queue->_front.list; + + queue->_front.list = frontList->next; + queue->_front.index = 0; + + if (queue->_front.list) { + queue->_front.list->previous = NULL; + } + + AddRunQueueListToReusablePool(queue, frontList); + } + + queue->count -= 1; + + if (queue->count == 0) { + queue->_front = InvalidRunQueuePosition; + } +} + +SB_INTERNAL const LevelRun *RunQueueGetFront(RunQueueRef queue) +{ + return &queue->_front.list->elements[queue->_front.index]; +} diff --git a/src/thirdparty/SheenBidi/Source/RunQueue.h b/src/thirdparty/SheenBidi/Source/RunQueue.h new file mode 100644 index 000000000..1d22130dd --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/RunQueue.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_RUN_QUEUE_H +#define _SB_INTERNAL_RUN_QUEUE_H + +#include +#include + +#include "LevelRun.h" +#include "Memory.h" + +#define RunQueueListElementCount 8 + +typedef struct _RunQueueList { + LevelRun elements[RunQueueListElementCount]; + + struct _RunQueueList *previous; /**< Reference to the previous list of queue elements */ + struct _RunQueueList *next; /**< Reference to the next list of queue elements */ +} RunQueueList, *RunQueueListRef; + +typedef struct _RunQueuePosition { + RunQueueListRef list; /**< Reference to the list containing the element */ + SBUInteger index; /**< Index of the element in the list */ +} RunQueuePosition; + +typedef struct _RunQueue { + MemoryRef _memory; + RunQueueList _firstList; /**< First list of elements, which is part of the queue */ + RunQueueListRef _listPool; /**< Pool of reusable lists */ + RunQueueListRef _rearList; /**< The list containing rear element of the queue */ + SBUInteger _rearTop; /**< Index of rear element in rear list */ + RunQueuePosition _front; /**< Position of the front element */ + RunQueuePosition _lastPartialRun; /**< Position of the last partial run */ + SBUInteger count; /**< Number of elements the queue contains */ +} RunQueue, *RunQueueRef; + +SB_INTERNAL void RunQueueInitialize(RunQueueRef queue, MemoryRef memory); + +SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRun *levelRun); +SB_INTERNAL void RunQueueDequeue(RunQueueRef queue); + +SB_INTERNAL const LevelRun *RunQueueGetFront(RunQueueRef queue); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBAlgorithm.c b/src/thirdparty/SheenBidi/Source/SBAlgorithm.c new file mode 100644 index 000000000..bbc246e06 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBAlgorithm.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "BidiTypeLookup.h" +#include "Object.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBCodepointSequence.h" +#include "SBLog.h" +#include "SBParagraph.h" +#include "SBAlgorithm.h" + +typedef SBAlgorithm *SBMutableAlgorithmRef; + +#define ALGORITHM 0 +#define BIDI_TYPES 1 +#define COUNT 2 + +static SBMutableAlgorithmRef AllocateAlgorithm(SBUInteger stringLength) +{ + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT] = { 0 }; + SBMutableAlgorithmRef algorithm; + + sizes[ALGORITHM] = sizeof(SBAlgorithm); + sizes[BIDI_TYPES] = sizeof(SBBidiType) * stringLength; + + algorithm = ObjectCreate(sizes, COUNT, pointers, NULL); + + if (algorithm) { + algorithm->fixedTypes = pointers[BIDI_TYPES]; + } + + return algorithm; +} + +#undef ALGORITHM +#undef BIDI_TYPES +#undef COUNT + +static SBAlgorithmRef CreateAlgorithm(const SBCodepointSequence *codepointSequence) +{ + SBUInteger stringLength = codepointSequence->stringLength; + SBMutableAlgorithmRef algorithm; + + SB_LOG_BLOCK_OPENER("Algorithm Input"); + SB_LOG_STATEMENT("Codepoints", 1, SB_LOG_CODEPOINT_SEQUENCE(codepointSequence)); + SB_LOG_BLOCK_CLOSER(); + + algorithm = AllocateAlgorithm(stringLength); + + if (algorithm) { + algorithm->codepointSequence = *codepointSequence; + + SBCodepointSequenceDetermineBidiTypes(codepointSequence, algorithm->fixedTypes); + + SB_LOG_BLOCK_OPENER("Determined Types"); + SB_LOG_STATEMENT("Types", 1, SB_LOG_BIDI_TYPES_ARRAY(algorithm->fixedTypes, stringLength)); + SB_LOG_BLOCK_CLOSER(); + + SB_LOG_BREAKER(); + } + + return algorithm; +} + +SBAlgorithmRef SBAlgorithmCreate(const SBCodepointSequence *codepointSequence) +{ + SBAlgorithmRef algorithm = NULL; + + if (SBCodepointSequenceIsValid(codepointSequence)) { + algorithm = CreateAlgorithm(codepointSequence); + } + + return algorithm; +} + +const SBBidiType *SBAlgorithmGetBidiTypesPtr(SBAlgorithmRef algorithm) +{ + return algorithm->fixedTypes; +} + +void SBAlgorithmGetParagraphBoundary(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *actualLength, SBUInteger *separatorLength) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBBidiType *bidiTypes = algorithm->fixedTypes; + + SBUIntegerNormalizeRange(codepointSequence->stringLength, ¶graphOffset, &suggestedLength); + + SBCodepointSequenceGetParagraphBoundary( + codepointSequence, bidiTypes, paragraphOffset, suggestedLength, + actualLength, separatorLength + ); +} + +SBParagraphRef SBAlgorithmCreateParagraph(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence; + SBUInteger stringLength = codepointSequence->stringLength; + SBParagraphRef paragraph = NULL; + + SBUIntegerNormalizeRange(stringLength, ¶graphOffset, &suggestedLength); + + if (suggestedLength > 0) { + paragraph = SBParagraphCreateWithAlgorithm( + algorithm, paragraphOffset, suggestedLength, baseLevel + ); + } + + return paragraph; +} + +SBAlgorithmRef SBAlgorithmRetain(SBAlgorithmRef algorithm) +{ + return ObjectRetain((ObjectRef)algorithm); +} + +void SBAlgorithmRelease(SBAlgorithmRef algorithm) +{ + ObjectRelease((ObjectRef)algorithm); +} diff --git a/src/thirdparty/SheenBidi/Source/SBAlgorithm.h b/src/thirdparty/SheenBidi/Source/SBAlgorithm.h new file mode 100644 index 000000000..0fdd5bef1 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBAlgorithm.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ALGORITHM_H +#define _SB_INTERNAL_ALGORITHM_H + +#include +#include +#include +#include +#include + +#include "Object.h" + +typedef struct _SBAlgorithm { + ObjectBase _base; + SBCodepointSequence codepointSequence; + SBBidiType *fixedTypes; +} SBAlgorithm; + +SB_INTERNAL SBUInteger SBAlgorithmGetSeparatorLength(SBAlgorithmRef algorithm, SBUInteger separatorIndex); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBAllocator.c b/src/thirdparty/SheenBidi/Source/SBAllocator.c new file mode 100644 index 000000000..69090d47f --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBAllocator.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "AtomicPointer.h" +#include "Object.h" +#include "Once.h" +#include "SBBase.h" +#include "ThreadLocalStorage.h" +#include "SBAllocator.h" + +typedef SBAllocator *SBMutableAllocatorRef; +typedef AtomicPointerType(SBAllocator) SBAtomicAllocatorRef; + +static SBAtomicAllocatorRef DefaultAllocator = NULL; + +#ifndef SB_CONFIG_DISABLE_SCRATCH_MEMORY + +#if defined(HAS_ATOMIC_POINTER_SUPPORT) && defined(HAS_TLS_SUPPORT) && defined(HAS_ONCE_SUPPORT) +#define USE_SCRATCH_MEMORY +#else +#error "Scratch memory functionality requires atomic operations, thread-local, and once support. \ +To proceed without scratch memory, manually define `SB_CONFIG_DISABLE_SCRATCH_MEMORY`." +#endif + +#endif + +#ifdef USE_SCRATCH_MEMORY + +typedef struct _Buffer { + struct _Buffer *next; + SBUInteger offset; + SBUInt8 data[SB_CONFIG_SCRATCH_BUFFER_SIZE]; +} Buffer, *BufferRef; +typedef AtomicPointerType(Buffer) AtomicBufferRef; + +static Buffer BufferPool[SB_CONFIG_SCRATCH_POOL_SIZE]; +static AtomicBufferRef BufferStack = NULL; +static ThreadLocalStorage ScratchBuffer; + +#define ALIGN_UP(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + +static void InitializeBufferStack(void *info) +{ + SBUInteger index; + + for (index = 0; index < SB_CONFIG_SCRATCH_POOL_SIZE - 1; index++) { + BufferPool[index].next = &BufferPool[index + 1]; + BufferPool[index].offset = 0; + } + + BufferPool[SB_CONFIG_SCRATCH_POOL_SIZE - 1].next = NULL; + BufferPool[SB_CONFIG_SCRATCH_POOL_SIZE - 1].offset = 0; + AtomicPointerStore(&BufferStack, &BufferPool[0]); +} + +static SBBoolean TryLazyInitializeBufferStack(void) +{ + static Once once = OnceMake(); + return OnceTryExecute(&once, InitializeBufferStack, NULL); +} + +static BufferRef DetachBuffer(void) +{ + BufferRef buffer = NULL; + + if (TryLazyInitializeBufferStack()) { + BufferRef expected = NULL; + + do { + buffer = AtomicPointerLoad(&BufferStack); + expected = buffer; + + if (!buffer) { + break; + } + } while (!AtomicPointerCompareAndSet(&BufferStack, &expected, buffer->next)); + } + + return buffer; +} + +static void RecycleBuffer(BufferRef buffer) +{ + BufferRef top; + BufferRef expected; + + buffer->offset = 0; + + do { + top = AtomicPointerLoad(&BufferStack); + expected = top; + buffer->next = top; + } while (!AtomicPointerCompareAndSet(&BufferStack, &expected, buffer)); +} + +static void InitializeScratchBuffer(void *info) +{ + ThreadLocalStorageInitialize(ScratchBuffer); +} + +static SBBoolean TryLazyInitializeScratchBuffer(void) +{ + static Once once = OnceMake(); + return OnceTryExecute(&once, InitializeScratchBuffer, NULL); +} + +static void *NativeAllocateScratch(SBUInteger size, void *info) +{ + void *pointer = NULL; + + if (TryLazyInitializeScratchBuffer()) { + BufferRef buffer = ThreadLocalStorageGet(ScratchBuffer); + + if (!buffer) { + buffer = DetachBuffer(); + + if (buffer) { + ThreadLocalStorageSet(ScratchBuffer, buffer); + } + } + + if (buffer) { + SBUInteger alignedSize = ALIGN_UP(size, sizeof(void *)); + SBUInteger limit = buffer->offset + alignedSize; + + if (limit <= SB_CONFIG_SCRATCH_BUFFER_SIZE) { + pointer = buffer->data + buffer->offset; + buffer->offset += alignedSize; + } + } + } + + return pointer; +} + +static void NativeResetScratch(void *info) +{ + if (TryLazyInitializeScratchBuffer()) { + BufferRef buffer = ThreadLocalStorageGet(ScratchBuffer); + + if (buffer) { + ThreadLocalStorageSet(ScratchBuffer, NULL); + RecycleBuffer(buffer); + } + } +} + +#else + +#define NativeAllocateScratch NULL +#define NativeResetScratch NULL + +#endif + +static void *NativeAllocateBlock(SBUInteger size, void *info) +{ + return malloc(size); +} + +static void *NativeReallocateBlock(void *pointer, SBUInteger size, void *info) +{ + return realloc(pointer, size); +} + +static void NativeDeallocateBlock(void *pointer, void *info) +{ + free(pointer); +} + +static SBAllocator NativeAllocator = SBAllocatorMake( + NativeAllocateBlock, NativeReallocateBlock, NativeDeallocateBlock, + NativeAllocateScratch, NativeResetScratch, NULL); + +static void FinalizeAllocator(ObjectRef object) +{ + SBAllocatorRef allocator = object; + + if (allocator->_protocol.finalize) { + allocator->_protocol.finalize(allocator->_info); + } +} + +static SBAllocatorRef SBAllocatorGetCurrent(void) +{ + SBAllocatorRef allocator = AtomicPointerLoad(&DefaultAllocator); + + if (!allocator) { + allocator = &NativeAllocator; + } + + return allocator; +} + +SB_INTERNAL void *SBAllocatorAllocateBlock(SBAllocatorRef allocator, SBUInteger size) +{ + if (!allocator) { + allocator = SBAllocatorGetCurrent(); + } + + return allocator->_protocol.allocateBlock(size, allocator->_info); +} + +SB_INTERNAL void *SBAllocatorReallocateBlock(SBAllocatorRef allocator, void *pointer, SBUInteger newSize) +{ + if (!allocator) { + allocator = SBAllocatorGetCurrent(); + } + + return allocator->_protocol.reallocateBlock(pointer, newSize, allocator->_info); +} + +SB_INTERNAL void SBAllocatorDeallocateBlock(SBAllocatorRef allocator, void *pointer) +{ + if (!allocator) { + allocator = SBAllocatorGetCurrent(); + } + + allocator->_protocol.deallocateBlock(pointer, allocator->_info); +} + +SB_INTERNAL void *SBAllocatorAllocateScratch(SBAllocatorRef allocator, SBUInteger size) +{ + SBAllocatorAllocateScratchFunc func; + void *pointer = NULL; + + if (!allocator) { + allocator = SBAllocatorGetCurrent(); + } + + func = allocator->_protocol.allocateScratch; + + if (func) { + pointer = func(size, allocator->_info); + } + + return pointer; +} + +SB_INTERNAL void SBAllocatorResetScratch(SBAllocatorRef allocator) +{ + SBAllocatorResetScratchFunc func; + + if (!allocator) { + allocator = SBAllocatorGetCurrent(); + } + + func = allocator->_protocol.resetScratch; + + if (func) { + func(allocator->_info); + } +} + +SBAllocatorRef SBAllocatorGetDefault(void) +{ + return AtomicPointerLoad(&DefaultAllocator); +} + +void SBAllocatorSetDefault(SBAllocatorRef allocator) +{ + AtomicPointerStore(&DefaultAllocator, (SBAllocator *)allocator); +} + +SBAllocatorRef SBAllocatorCreate(const SBAllocatorProtocol *protocol, void *info) +{ + const SBUInteger size = sizeof(SBAllocator); + void *pointer = NULL; + SBMutableAllocatorRef allocator = NULL; + + allocator = ObjectCreate(&size, 1, &pointer, FinalizeAllocator); + + if (allocator) { + allocator->_info = info; + allocator->_protocol = *protocol; + } + + return allocator; +} + +SBAllocatorRef SBAllocatorRetain(SBAllocatorRef allocator) +{ + return ObjectRetain((ObjectRef)allocator); +} + +void SBAllocatorRelease(SBAllocatorRef allocator) +{ + ObjectRelease((ObjectRef)allocator); +} diff --git a/src/thirdparty/SheenBidi/Source/SBAllocator.h b/src/thirdparty/SheenBidi/Source/SBAllocator.h new file mode 100644 index 000000000..aeb74289d --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBAllocator.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ALLOCATOR_H +#define _SB_INTERNAL_ALLOCATOR_H + +#include + +#include "Object.h" + +typedef struct _SBAllocator { + ObjectBase _base; + void *_info; + SBAllocatorProtocol _protocol; +} SBAllocator; + +#define SBAllocatorMake(allocateBlock, reallocateBlock, deallocateBlock, \ + allocateScratch, resetScratch, finalize) \ +{ \ + ObjectBaseMake(), \ + NULL, \ + { \ + allocateBlock, reallocateBlock, deallocateBlock, \ + allocateScratch, resetScratch, finalize \ + } \ +} + +SB_INTERNAL void *SBAllocatorAllocateBlock(SBAllocatorRef allocator, SBUInteger size); +SB_INTERNAL void *SBAllocatorReallocateBlock(SBAllocatorRef allocator, void *pointer, SBUInteger newSize); +SB_INTERNAL void SBAllocatorDeallocateBlock(SBAllocatorRef allocator, void *pointer); + +SB_INTERNAL void *SBAllocatorAllocateScratch(SBAllocatorRef allocator, SBUInteger size); +SB_INTERNAL void SBAllocatorResetScratch(SBAllocatorRef allocator); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBAssert.h b/src/thirdparty/SheenBidi/Source/SBAssert.h new file mode 100644 index 000000000..22923c72b --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBAssert.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_ASSERT_H +#define _SB_INTERNAL_ASSERT_H + +#include + +#define SBAssert(exp) assert(exp) + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBBase.c b/src/thirdparty/SheenBidi/Source/SBBase.c new file mode 100644 index 000000000..8c2b0df0d --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBBase.c @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "SBBase.h" + +static const char LibraryVersion[] = SHEENBIDI_VERSION_STRING; + +#define TAG(a, b, c, d) \ +(SBUInt32) \ +( \ + ((SBUInt8)(a) << 24) \ + | ((SBUInt8)(b) << 16) \ + | ((SBUInt8)(c) << 8) \ + | ((SBUInt8)(d) << 0) \ +) + +SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength, + SBUInteger *rangeOffset, SBUInteger *rangeLength) +{ + /** + * Assume: + * Actual Length = 10 + * + * Case 1: + * Offset = 0, Length = 10 + * Result: + * Offset = 0, Length = 10 + * + * Case 2: + * Offset = 0, Length = 11 + * Result: + * Offset = 0, Length = 10 + * + * Case 3: + * Offset = 1, Length = -1 (MAX) + * Result: + * Offset = 1, Length = 9 + * + * Case 4: + * Offset = 10, Length = 0 + * Result: + * Offset = Invalid, Length = 0 + * + * Case 5: + * Offset = -1 (MAX), Length = 1 + * Result: + * Offset = Invalid, Length = 0 + */ + + if (*rangeOffset < actualLength) { + SBUInteger possibleLimit = *rangeOffset + *rangeLength; + + if (*rangeOffset <= possibleLimit && possibleLimit <= actualLength) { + /* The range is valid. Nothing to do here. */ + } else { + *rangeLength = actualLength - *rangeOffset; + } + } else { + *rangeOffset = SBInvalidIndex; + *rangeLength = 0; + } +} + +SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength, + SBUInteger rangeOffset, SBUInteger rangeLength) +{ + SBUInteger possibleLimit = rangeOffset + rangeLength; + + return rangeOffset < actualLength + && rangeOffset <= possibleLimit + && possibleLimit <= actualLength; +} + +SBUInt32 SBScriptGetOpenTypeTag(SBScript script) +{ + /* Reference: https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags */ + /* Dated: 05/31/2024 */ + + switch (script) { + case SBScriptADLM: + return TAG('a', 'd', 'l', 'm'); + case SBScriptAHOM: + return TAG('a', 'h', 'o', 'm'); + case SBScriptHLUW: + return TAG('h', 'l', 'u', 'w'); + case SBScriptARAB: + return TAG('a', 'r', 'a', 'b'); + case SBScriptARMN: + return TAG('a', 'r', 'm', 'n'); + case SBScriptAVST: + return TAG('a', 'v', 's', 't'); + case SBScriptBALI: + return TAG('b', 'a', 'l', 'i'); + case SBScriptBAMU: + return TAG('b', 'a', 'm', 'u'); + case SBScriptBASS: + return TAG('b', 'a', 's', 's'); + case SBScriptBATK: + return TAG('b', 'a', 't', 'k'); + /* case SBScriptBENG: + return TAG('b', 'e', 'n', 'g'); */ + case SBScriptBENG: + return TAG('b', 'n', 'g', '2'); + case SBScriptBERF: + return TAG('b', 'e', 'r', 'f'); + case SBScriptBHKS: + return TAG('b', 'h', 'k', 's'); + case SBScriptBOPO: + return TAG('b', 'o', 'p', 'o'); + case SBScriptBRAH: + return TAG('b', 'r', 'a', 'h'); + case SBScriptBRAI: + return TAG('b', 'r', 'a', 'i'); + case SBScriptBUGI: + return TAG('b', 'u', 'g', 'i'); + case SBScriptBUHD: + return TAG('b', 'u', 'h', 'd'); + /* case SBScript____: + return TAG('b', 'y', 'z', 'm'); */ + case SBScriptCANS: + return TAG('c', 'a', 'n', 's'); + case SBScriptCARI: + return TAG('c', 'a', 'r', 'i'); + case SBScriptAGHB: + return TAG('a', 'g', 'h', 'b'); + case SBScriptCAKM: + return TAG('c', 'a', 'k', 'm'); + case SBScriptCHAM: + return TAG('c', 'h', 'a', 'm'); + case SBScriptCHER: + return TAG('c', 'h', 'e', 'r'); + case SBScriptCHRS: + return TAG('c', 'h', 'r', 's'); + case SBScriptHANI: + return TAG('h', 'a', 'n', 'i'); + case SBScriptCOPT: + return TAG('c', 'o', 'p', 't'); + case SBScriptCPRT: + return TAG('c', 'p', 'r', 't'); + case SBScriptCPMN: + return TAG('c', 'p', 'm', 'n'); + case SBScriptCYRL: + return TAG('c', 'y', 'r', 'l'); + case SBScriptDSRT: + return TAG('d', 's', 'r', 't'); + /* case SBScriptDEVA: + return TAG('d', 'e', 'v', 'a'); */ + case SBScriptDEVA: + return TAG('d', 'e', 'v', '2'); + case SBScriptDIAK: + return TAG('d', 'i', 'a', 'k'); + case SBScriptDOGR: + return TAG('d', 'o', 'g', 'r'); + case SBScriptDUPL: + return TAG('d', 'u', 'p', 'l'); + case SBScriptEGYP: + return TAG('e', 'g', 'y', 'p'); + case SBScriptELBA: + return TAG('e', 'l', 'b', 'a'); + case SBScriptELYM: + return TAG('e', 'l', 'y', 'm'); + case SBScriptETHI: + return TAG('e', 't', 'h', 'i'); + case SBScriptGARA: + return TAG('g', 'a', 'r', 'a'); + case SBScriptGEOR: + return TAG('g', 'e', 'o', 'r'); + case SBScriptGLAG: + return TAG('g', 'l', 'a', 'g'); + case SBScriptGOTH: + return TAG('g', 'o', 't', 'h'); + case SBScriptGRAN: + return TAG('g', 'r', 'a', 'n'); + case SBScriptGREK: + return TAG('g', 'r', 'e', 'k'); + /* case SBScriptGUJR: + return TAG('g', 'u', 'j', 'r'); */ + case SBScriptGUJR: + return TAG('g', 'j', 'r', '2'); + case SBScriptGONG: + return TAG('g', 'o', 'n', 'g'); + /* case SBScriptGURU: + return TAG('g', 'u', 'r', 'u'); */ + case SBScriptGURU: + return TAG('g', 'u', 'r', '2'); + case SBScriptGUKH: + return TAG('g', 'u', 'k', 'h'); + case SBScriptHANG: + return TAG('h', 'a', 'n', 'g'); + /* case SBScriptHANG: + return TAG('j', 'a', 'm', 'o'); */ + case SBScriptROHG: + return TAG('r', 'o', 'h', 'g'); + case SBScriptHANO: + return TAG('h', 'a', 'n', 'o'); + case SBScriptHATR: + return TAG('h', 'a', 't', 'r'); + case SBScriptHEBR: + return TAG('h', 'e', 'b', 'r'); + case SBScriptHIRA: + return TAG('k', 'a', 'n', 'a'); + case SBScriptARMI: + return TAG('a', 'r', 'm', 'i'); + case SBScriptPHLI: + return TAG('p', 'h', 'l', 'i'); + case SBScriptPRTI: + return TAG('p', 'r', 't', 'i'); + case SBScriptJAVA: + return TAG('j', 'a', 'v', 'a'); + case SBScriptKTHI: + return TAG('k', 't', 'h', 'i'); + /* case SBScriptKNDA: + return TAG('k', 'n', 'd', 'a'); */ + case SBScriptKNDA: + return TAG('k', 'n', 'd', '2'); + case SBScriptKANA: + return TAG('k', 'a', 'n', 'a'); + case SBScriptKAWI: + return TAG('k', 'a', 'w', 'i'); + case SBScriptKALI: + return TAG('k', 'a', 'l', 'i'); + case SBScriptKHAR: + return TAG('k', 'h', 'a', 'r'); + case SBScriptKITS: + return TAG('k', 'i', 't', 's'); + case SBScriptKHMR: + return TAG('k', 'h', 'm', 'r'); + case SBScriptKHOJ: + return TAG('k', 'h', 'o', 'j'); + case SBScriptSIND: + return TAG('s', 'i', 'n', 'd'); + case SBScriptKRAI: + return TAG('k', 'r', 'a', 'i'); + case SBScriptLAOO: + return TAG('l', 'a', 'o', ' '); + case SBScriptLATN: + return TAG('l', 'a', 't', 'n'); + case SBScriptLEPC: + return TAG('l', 'e', 'p', 'c'); + case SBScriptLIMB: + return TAG('l', 'i', 'm', 'b'); + case SBScriptLINA: + return TAG('l', 'i', 'n', 'a'); + case SBScriptLINB: + return TAG('l', 'i', 'n', 'b'); + case SBScriptLISU: + return TAG('l', 'i', 's', 'u'); + case SBScriptLYCI: + return TAG('l', 'y', 'c', 'i'); + case SBScriptLYDI: + return TAG('l', 'y', 'd', 'i'); + case SBScriptMAHJ: + return TAG('m', 'a', 'h', 'j'); + case SBScriptMAKA: + return TAG('m', 'a', 'k', 'a'); + /* case SBScriptMLYM: + return TAG('m', 'l', 'y', 'm'); */ + case SBScriptMLYM: + return TAG('m', 'l', 'm', '2'); + case SBScriptMAND: + return TAG('m', 'a', 'n', 'd'); + case SBScriptMANI: + return TAG('m', 'a', 'n', 'i'); + case SBScriptMARC: + return TAG('m', 'a', 'r', 'c'); + case SBScriptGONM: + return TAG('g', 'o', 'n', 'm'); + /* case SBScript____: + return TAG('m', 'a', 't', 'h'); */ + case SBScriptMEDF: + return TAG('m', 'e', 'd', 'f'); + case SBScriptMTEI: + return TAG('m', 't', 'e', 'i'); + case SBScriptMEND: + return TAG('m', 'e', 'n', 'd'); + case SBScriptMERC: + return TAG('m', 'e', 'r', 'c'); + case SBScriptMERO: + return TAG('m', 'e', 'r', 'o'); + case SBScriptPLRD: + return TAG('p', 'l', 'r', 'd'); + case SBScriptMODI: + return TAG('m', 'o', 'd', 'i'); + case SBScriptMONG: + return TAG('m', 'o', 'n', 'g'); + case SBScriptMROO: + return TAG('m', 'r', 'o', 'o'); + case SBScriptMULT: + return TAG('m', 'u', 'l', 't'); + /* case SBScript___: + return TAG('m', 'u', 's', 'c'); */ + /* case SBScriptMYMR: + return TAG('m', 'y', 'm', 'r'); */ + case SBScriptMYMR: + return TAG('m', 'y', 'm', '2'); + case SBScriptNBAT: + return TAG('n', 'b', 'a', 't'); + case SBScriptNAGM: + return TAG('n', 'a', 'g', 'm'); + case SBScriptNAND: + return TAG('n', 'a', 'n', 'd'); + case SBScriptNEWA: + return TAG('n', 'e', 'w', 'a'); + case SBScriptTALU: + return TAG('t', 'a', 'l', 'u'); + case SBScriptNKOO: + return TAG('n', 'k', 'o', ' '); + case SBScriptNSHU: + return TAG('n', 's', 'h', 'u'); + case SBScriptHMNP: + return TAG('h', 'm', 'n', 'p'); + /* case SBScriptORYA: + return TAG('o', 'r', 'y', 'a'); */ + case SBScriptORYA: + return TAG('o', 'r', 'y', '2'); + case SBScriptOGAM: + return TAG('o', 'g', 'a', 'm'); + case SBScriptOLCK: + return TAG('o', 'l', 'c', 'k'); + case SBScriptONAO: + return TAG('o', 'n', 'a', 'o'); + case SBScriptITAL: + return TAG('i', 't', 'a', 'l'); + case SBScriptHUNG: + return TAG('h', 'u', 'n', 'g'); + case SBScriptNARB: + return TAG('n', 'a', 'r', 'b'); + case SBScriptPERM: + return TAG('p', 'e', 'r', 'm'); + case SBScriptXPEO: + return TAG('x', 'p', 'e', 'o'); + case SBScriptSOGO: + return TAG('s', 'o', 'g', 'o'); + case SBScriptSARB: + return TAG('s', 'a', 'r', 'b'); + case SBScriptORKH: + return TAG('o', 'r', 'k', 'h'); + case SBScriptOUGR: + return TAG('o', 'u', 'g', 'r'); + case SBScriptOSGE: + return TAG('o', 's', 'g', 'e'); + case SBScriptOSMA: + return TAG('o', 's', 'm', 'a'); + case SBScriptHMNG: + return TAG('h', 'm', 'n', 'g'); + case SBScriptPALM: + return TAG('p', 'a', 'l', 'm'); + case SBScriptPAUC: + return TAG('p', 'a', 'u', 'c'); + case SBScriptPHAG: + return TAG('p', 'h', 'a', 'g'); + case SBScriptPHNX: + return TAG('p', 'h', 'n', 'x'); + case SBScriptPHLP: + return TAG('p', 'h', 'l', 'p'); + case SBScriptRJNG: + return TAG('r', 'j', 'n', 'g'); + case SBScriptRUNR: + return TAG('r', 'u', 'n', 'r'); + case SBScriptSAMR: + return TAG('s', 'a', 'm', 'r'); + case SBScriptSAUR: + return TAG('s', 'a', 'u', 'r'); + case SBScriptSHRD: + return TAG('s', 'h', 'r', 'd'); + case SBScriptSHAW: + return TAG('s', 'h', 'a', 'w'); + case SBScriptSIDD: + return TAG('s', 'i', 'd', 'd'); + case SBScriptSIDT: + return TAG('s', 'i', 'd', 't'); + case SBScriptSGNW: + return TAG('s', 'g', 'n', 'w'); + case SBScriptSINH: + return TAG('s', 'i', 'n', 'h'); + case SBScriptSOGD: + return TAG('s', 'o', 'g', 'd'); + case SBScriptSORA: + return TAG('s', 'o', 'r', 'a'); + case SBScriptSOYO: + return TAG('s', 'o', 'y', 'o'); + case SBScriptXSUX: + return TAG('x', 's', 'u', 'x'); + case SBScriptSUND: + return TAG('s', 'u', 'n', 'd'); + case SBScriptSUNU: + return TAG('s', 'u', 'n', 'u'); + case SBScriptSYLO: + return TAG('s', 'y', 'l', 'o'); + case SBScriptSYRC: + return TAG('s', 'y', 'r', 'c'); + case SBScriptTGLG: + return TAG('t', 'g', 'l', 'g'); + case SBScriptTAGB: + return TAG('t', 'a', 'g', 'b'); + case SBScriptTALE: + return TAG('t', 'a', 'l', 'e'); + case SBScriptLANA: + return TAG('l', 'a', 'n', 'a'); + case SBScriptTAVT: + return TAG('t', 'a', 'v', 't'); + case SBScriptTAKR: + return TAG('t', 'a', 'k', 'r'); + /* case SBScriptTAML: + return TAG('t', 'a', 'm', 'l'); */ + case SBScriptTAML: + return TAG('t', 'm', 'l', '2'); + case SBScriptTNSA: + return TAG('t', 'n', 's', 'a'); + case SBScriptTANG: + return TAG('t', 'a', 'n', 'g'); + case SBScriptTAYO: + return TAG('t', 'a', 'y', 'o'); + /* case SBScriptTELU: + return TAG('t', 'e', 'l', 'u'); */ + case SBScriptTELU: + return TAG('t', 'e', 'l', '2'); + case SBScriptTHAA: + return TAG('t', 'h', 'a', 'a'); + case SBScriptTHAI: + return TAG('t', 'h', 'a', 'i'); + case SBScriptTIBT: + return TAG('t', 'i', 'b', 't'); + case SBScriptTFNG: + return TAG('t', 'f', 'n', 'g'); + case SBScriptTIRH: + return TAG('t', 'i', 'r', 'h'); + case SBScriptTODR: + return TAG('t', 'o', 'd', 'r'); + case SBScriptTOLS: + return TAG('t', 'o', 'l', 's'); + case SBScriptTOTO: + return TAG('t', 'o', 't', 'o'); + case SBScriptTUTG: + return TAG('t', 'u', 't', 'g'); + case SBScriptUGAR: + return TAG('u', 'g', 'a', 'r'); + case SBScriptVAII: + return TAG('v', 'a', 'i', ' '); + case SBScriptVITH: + return TAG('v', 'i', 't', 'h'); + case SBScriptWCHO: + return TAG('w', 'c', 'h', 'o'); + case SBScriptWARA: + return TAG('w', 'a', 'r', 'a'); + case SBScriptYEZI: + return TAG('y', 'e', 'z', 'i'); + case SBScriptYIII: + return TAG('y', 'i', ' ', ' '); + case SBScriptZANB: + return TAG('z', 'a', 'n', 'b'); + default: + return TAG('D', 'F', 'L', 'T'); + } +} + +SBUInt32 SBScriptGetUnicodeTag(SBScript script) +{ + switch (script) { + case SBScriptADLM: + return TAG('A', 'd', 'l', 'm'); + case SBScriptAGHB: + return TAG('A', 'g', 'h', 'b'); + case SBScriptAHOM: + return TAG('A', 'h', 'o', 'm'); + case SBScriptARAB: + return TAG('A', 'r', 'a', 'b'); + case SBScriptARMI: + return TAG('A', 'r', 'm', 'i'); + case SBScriptARMN: + return TAG('A', 'r', 'm', 'n'); + case SBScriptAVST: + return TAG('A', 'v', 's', 't'); + case SBScriptBALI: + return TAG('B', 'a', 'l', 'i'); + case SBScriptBAMU: + return TAG('B', 'a', 'm', 'u'); + case SBScriptBASS: + return TAG('B', 'a', 's', 's'); + case SBScriptBATK: + return TAG('B', 'a', 't', 'k'); + case SBScriptBENG: + return TAG('B', 'e', 'n', 'g'); + case SBScriptBERF: + return TAG('B', 'e', 'r', 'f'); + case SBScriptBHKS: + return TAG('B', 'h', 'k', 's'); + case SBScriptBOPO: + return TAG('B', 'o', 'p', 'o'); + case SBScriptBRAH: + return TAG('B', 'r', 'a', 'h'); + case SBScriptBRAI: + return TAG('B', 'r', 'a', 'i'); + case SBScriptBUGI: + return TAG('B', 'u', 'g', 'i'); + case SBScriptBUHD: + return TAG('B', 'u', 'h', 'd'); + case SBScriptCAKM: + return TAG('C', 'a', 'k', 'm'); + case SBScriptCANS: + return TAG('C', 'a', 'n', 's'); + case SBScriptCARI: + return TAG('C', 'a', 'r', 'i'); + case SBScriptCHAM: + return TAG('C', 'h', 'a', 'm'); + case SBScriptCHER: + return TAG('C', 'h', 'e', 'r'); + case SBScriptCHRS: + return TAG('C', 'h', 'r', 's'); + case SBScriptCOPT: + return TAG('C', 'o', 'p', 't'); + case SBScriptCPMN: + return TAG('C', 'p', 'm', 'n'); + case SBScriptCPRT: + return TAG('C', 'p', 'r', 't'); + case SBScriptCYRL: + return TAG('C', 'y', 'r', 'l'); + case SBScriptDEVA: + return TAG('D', 'e', 'v', 'a'); + case SBScriptDIAK: + return TAG('D', 'i', 'a', 'k'); + case SBScriptDOGR: + return TAG('D', 'o', 'g', 'r'); + case SBScriptDSRT: + return TAG('D', 's', 'r', 't'); + case SBScriptDUPL: + return TAG('D', 'u', 'p', 'l'); + case SBScriptEGYP: + return TAG('E', 'g', 'y', 'p'); + case SBScriptELBA: + return TAG('E', 'l', 'b', 'a'); + case SBScriptELYM: + return TAG('E', 'l', 'y', 'm'); + case SBScriptETHI: + return TAG('E', 't', 'h', 'i'); + case SBScriptGARA: + return TAG('G', 'a', 'r', 'a'); + case SBScriptGEOR: + return TAG('G', 'e', 'o', 'r'); + case SBScriptGLAG: + return TAG('G', 'l', 'a', 'g'); + case SBScriptGONG: + return TAG('G', 'o', 'n', 'g'); + case SBScriptGONM: + return TAG('G', 'o', 'n', 'm'); + case SBScriptGOTH: + return TAG('G', 'o', 't', 'h'); + case SBScriptGRAN: + return TAG('G', 'r', 'a', 'n'); + case SBScriptGREK: + return TAG('G', 'r', 'e', 'k'); + case SBScriptGUJR: + return TAG('G', 'u', 'j', 'r'); + case SBScriptGUKH: + return TAG('G', 'u', 'k', 'h'); + case SBScriptGURU: + return TAG('G', 'u', 'r', 'u'); + case SBScriptHANG: + return TAG('H', 'a', 'n', 'g'); + case SBScriptHANI: + return TAG('H', 'a', 'n', 'i'); + case SBScriptHANO: + return TAG('H', 'a', 'n', 'o'); + case SBScriptHATR: + return TAG('H', 'a', 't', 'r'); + case SBScriptHEBR: + return TAG('H', 'e', 'b', 'r'); + case SBScriptHIRA: + return TAG('H', 'i', 'r', 'a'); + case SBScriptHLUW: + return TAG('H', 'l', 'u', 'w'); + case SBScriptHMNG: + return TAG('H', 'm', 'n', 'g'); + case SBScriptHMNP: + return TAG('H', 'm', 'n', 'p'); + case SBScriptHUNG: + return TAG('H', 'u', 'n', 'g'); + case SBScriptITAL: + return TAG('I', 't', 'a', 'l'); + case SBScriptJAVA: + return TAG('J', 'a', 'v', 'a'); + case SBScriptKALI: + return TAG('K', 'a', 'l', 'i'); + case SBScriptKANA: + return TAG('K', 'a', 'n', 'a'); + case SBScriptKAWI: + return TAG('K', 'a', 'w', 'i'); + case SBScriptKHAR: + return TAG('K', 'h', 'a', 'r'); + case SBScriptKHMR: + return TAG('K', 'h', 'm', 'r'); + case SBScriptKHOJ: + return TAG('K', 'h', 'o', 'j'); + case SBScriptKITS: + return TAG('K', 'i', 't', 's'); + case SBScriptKNDA: + return TAG('K', 'n', 'd', 'a'); + case SBScriptKRAI: + return TAG('K', 'r', 'a', 'i'); + case SBScriptKTHI: + return TAG('K', 't', 'h', 'i'); + case SBScriptLANA: + return TAG('L', 'a', 'n', 'a'); + case SBScriptLAOO: + return TAG('L', 'a', 'o', 'o'); + case SBScriptLATN: + return TAG('L', 'a', 't', 'n'); + case SBScriptLEPC: + return TAG('L', 'e', 'p', 'c'); + case SBScriptLIMB: + return TAG('L', 'i', 'm', 'b'); + case SBScriptLINA: + return TAG('L', 'i', 'n', 'a'); + case SBScriptLINB: + return TAG('L', 'i', 'n', 'b'); + case SBScriptLISU: + return TAG('L', 'i', 's', 'u'); + case SBScriptLYCI: + return TAG('L', 'y', 'c', 'i'); + case SBScriptLYDI: + return TAG('L', 'y', 'd', 'i'); + case SBScriptMAHJ: + return TAG('M', 'a', 'h', 'j'); + case SBScriptMAKA: + return TAG('M', 'a', 'k', 'a'); + case SBScriptMAND: + return TAG('M', 'a', 'n', 'd'); + case SBScriptMANI: + return TAG('M', 'a', 'n', 'i'); + case SBScriptMARC: + return TAG('M', 'a', 'r', 'c'); + case SBScriptMEDF: + return TAG('M', 'e', 'd', 'f'); + case SBScriptMEND: + return TAG('M', 'e', 'n', 'd'); + case SBScriptMERC: + return TAG('M', 'e', 'r', 'c'); + case SBScriptMERO: + return TAG('M', 'e', 'r', 'o'); + case SBScriptMLYM: + return TAG('M', 'l', 'y', 'm'); + case SBScriptMODI: + return TAG('M', 'o', 'd', 'i'); + case SBScriptMONG: + return TAG('M', 'o', 'n', 'g'); + case SBScriptMROO: + return TAG('M', 'r', 'o', 'o'); + case SBScriptMTEI: + return TAG('M', 't', 'e', 'i'); + case SBScriptMULT: + return TAG('M', 'u', 'l', 't'); + case SBScriptMYMR: + return TAG('M', 'y', 'm', 'r'); + case SBScriptNAGM: + return TAG('N', 'a', 'g', 'm'); + case SBScriptNAND: + return TAG('N', 'a', 'n', 'd'); + case SBScriptNARB: + return TAG('N', 'a', 'r', 'b'); + case SBScriptNBAT: + return TAG('N', 'b', 'a', 't'); + case SBScriptNEWA: + return TAG('N', 'e', 'w', 'a'); + case SBScriptNKOO: + return TAG('N', 'k', 'o', 'o'); + case SBScriptNSHU: + return TAG('N', 's', 'h', 'u'); + case SBScriptOGAM: + return TAG('O', 'g', 'a', 'm'); + case SBScriptOLCK: + return TAG('O', 'l', 'c', 'k'); + case SBScriptONAO: + return TAG('O', 'n', 'a', 'o'); + case SBScriptORKH: + return TAG('O', 'r', 'k', 'h'); + case SBScriptORYA: + return TAG('O', 'r', 'y', 'a'); + case SBScriptOSGE: + return TAG('O', 's', 'g', 'e'); + case SBScriptOSMA: + return TAG('O', 's', 'm', 'a'); + case SBScriptOUGR: + return TAG('O', 'u', 'g', 'r'); + case SBScriptPALM: + return TAG('P', 'a', 'l', 'm'); + case SBScriptPAUC: + return TAG('P', 'a', 'u', 'c'); + case SBScriptPERM: + return TAG('P', 'e', 'r', 'm'); + case SBScriptPHAG: + return TAG('P', 'h', 'a', 'g'); + case SBScriptPHLI: + return TAG('P', 'h', 'l', 'i'); + case SBScriptPHLP: + return TAG('P', 'h', 'l', 'p'); + case SBScriptPHNX: + return TAG('P', 'h', 'n', 'x'); + case SBScriptPLRD: + return TAG('P', 'l', 'r', 'd'); + case SBScriptPRTI: + return TAG('P', 'r', 't', 'i'); + case SBScriptRJNG: + return TAG('R', 'j', 'n', 'g'); + case SBScriptROHG: + return TAG('R', 'o', 'h', 'g'); + case SBScriptRUNR: + return TAG('R', 'u', 'n', 'r'); + case SBScriptSAMR: + return TAG('S', 'a', 'm', 'r'); + case SBScriptSARB: + return TAG('S', 'a', 'r', 'b'); + case SBScriptSAUR: + return TAG('S', 'a', 'u', 'r'); + case SBScriptSGNW: + return TAG('S', 'g', 'n', 'w'); + case SBScriptSHAW: + return TAG('S', 'h', 'a', 'w'); + case SBScriptSHRD: + return TAG('S', 'h', 'r', 'd'); + case SBScriptSIDD: + return TAG('S', 'i', 'd', 'd'); + case SBScriptSIDT: + return TAG('S', 'i', 'd', 't'); + case SBScriptSIND: + return TAG('S', 'i', 'n', 'd'); + case SBScriptSINH: + return TAG('S', 'i', 'n', 'h'); + case SBScriptSOGD: + return TAG('S', 'o', 'g', 'd'); + case SBScriptSOGO: + return TAG('S', 'o', 'g', 'o'); + case SBScriptSORA: + return TAG('S', 'o', 'r', 'a'); + case SBScriptSOYO: + return TAG('S', 'o', 'y', 'o'); + case SBScriptSUND: + return TAG('S', 'u', 'n', 'd'); + case SBScriptSUNU: + return TAG('S', 'u', 'n', 'u'); + case SBScriptSYLO: + return TAG('S', 'y', 'l', 'o'); + case SBScriptSYRC: + return TAG('S', 'y', 'r', 'c'); + case SBScriptTAGB: + return TAG('T', 'a', 'g', 'b'); + case SBScriptTAKR: + return TAG('T', 'a', 'k', 'r'); + case SBScriptTALE: + return TAG('T', 'a', 'l', 'e'); + case SBScriptTALU: + return TAG('T', 'a', 'l', 'u'); + case SBScriptTAML: + return TAG('T', 'a', 'm', 'l'); + case SBScriptTANG: + return TAG('T', 'a', 'n', 'g'); + case SBScriptTAVT: + return TAG('T', 'a', 'v', 't'); + case SBScriptTAYO: + return TAG('T', 'a', 'y', 'o'); + case SBScriptTELU: + return TAG('T', 'e', 'l', 'u'); + case SBScriptTFNG: + return TAG('T', 'f', 'n', 'g'); + case SBScriptTGLG: + return TAG('T', 'g', 'l', 'g'); + case SBScriptTHAA: + return TAG('T', 'h', 'a', 'a'); + case SBScriptTHAI: + return TAG('T', 'h', 'a', 'i'); + case SBScriptTIBT: + return TAG('T', 'i', 'b', 't'); + case SBScriptTIRH: + return TAG('T', 'i', 'r', 'h'); + case SBScriptTNSA: + return TAG('T', 'n', 's', 'a'); + case SBScriptTODR: + return TAG('T', 'o', 'd', 'r'); + case SBScriptTOLS: + return TAG('T', 'o', 'l', 's'); + case SBScriptTOTO: + return TAG('T', 'o', 't', 'o'); + case SBScriptTUTG: + return TAG('T', 'u', 't', 'g'); + case SBScriptUGAR: + return TAG('U', 'g', 'a', 'r'); + case SBScriptVAII: + return TAG('V', 'a', 'i', 'i'); + case SBScriptVITH: + return TAG('V', 'i', 't', 'h'); + case SBScriptWARA: + return TAG('W', 'a', 'r', 'a'); + case SBScriptWCHO: + return TAG('W', 'c', 'h', 'o'); + case SBScriptXPEO: + return TAG('X', 'p', 'e', 'o'); + case SBScriptXSUX: + return TAG('X', 's', 'u', 'x'); + case SBScriptYEZI: + return TAG('Y', 'e', 'z', 'i'); + case SBScriptYIII: + return TAG('Y', 'i', 'i', 'i'); + case SBScriptZANB: + return TAG('Z', 'a', 'n', 'b'); + case SBScriptZINH: + return TAG('Z', 'i', 'n', 'h'); + case SBScriptZYYY: + return TAG('Z', 'y', 'y', 'y'); + case SBScriptZZZZ: + return TAG('Z', 'z', 'z', 'z'); + default: + return 0; + } +} + +const char *SBVersionGetString(void) +{ + return LibraryVersion; +} diff --git a/src/thirdparty/SheenBidi/Source/SBBase.h b/src/thirdparty/SheenBidi/Source/SBBase.h new file mode 100644 index 000000000..9726e084f --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBBase.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_BASE_H +#define _SB_INTERNAL_BASE_H + +#include +#include +#include +#include + +/* ---------- Compiler Version Detection ---------- */ + +/* Detect GCC and its version */ +#if defined(__GNUC__) && !defined(__clang__) +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +#define GCC_VERSION 0 +#endif + +/* Detect Clang and its version */ +#if defined(__clang__) +#define CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +#define CLANG_VERSION 0 +#endif + +/* Detect MSVC and its version */ +#if defined(_MSC_VER) +#define MSVC_VERSION _MSC_VER +#else +#define MSVC_VERSION 0 +#endif + +/* ---------- Atomic Support Feature Detection ---------- */ + +/* Prefer C11 atomics if available */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) +#define USE_C11_ATOMICS + +/* Fallback to compiler intrinsics for GCC/Clang */ +#elif defined(__GNUC__) || defined(__clang__) +/* Modern __atomic builtins (GCC 4.7+, Clang 3.1+) */ +#if GCC_VERSION >= 407 || CLANG_VERSION >= 301 +#define USE_ATOMIC_BUILTINS +/* Legacy __sync builtins (GCC 4.1+, Clang 1.0+) */ +#elif GCC_VERSION >= 401 || CLANG_VERSION >= 100 +#define USE_SYNC_BUILTINS +#endif + +/* Windows-specific intrinsics */ +#elif defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) + +#if MSVC_VERSION >= 1700 /* VS 2012+ */ +#define USE_WIN_INTRINSICS +#else +#define USE_WIN_INTERLOCKED +#endif + +#endif + + +/** + * A value that indicates an invalid unsigned index. + */ +#define SBInvalidIndex (SBUInteger)(-1) + +SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength, + SBUInteger *rangeOffset, SBUInteger *rangeLength); + +SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength, + SBUInteger rangeOffset, SBUInteger rangeLength); + + +#define SBNumberGetMax(first, second) \ +( \ + (first) > (second) \ + ? (first) \ + : (second) \ +) + +#define SBNumberLimitIncrement(number, limit) \ +( \ + (number) < (limit) \ + ? (number) + (1) \ + : (limit) \ +) + +#define SBNumberLimitDecrement(number, limit) \ +( \ + (number) > (limit) \ + ? (number) - (1) \ + : (limit) \ +) + +#define SBNumberRingAdd(number, count, capacity) \ + (((number) + (count)) % (capacity)) + +#define SBNumberRingIncrement(number, capacity) \ + SBNumberRingAdd(number, 1, capacity) + +#define SBNumberRingSubtract(number, count, capacity) \ + (((number) + (capacity) - (count)) % (capacity)) + +#define SBNumberRingDecrement(number, capacity) \ + SBNumberRingSubtract(number, 1, capacity) + + +#define SBLevelAsNormalBidiType(level) \ +( \ + ((level) & 1) \ + ? SBBidiTypeR \ + : SBBidiTypeL \ +) + +#define SBLevelAsOppositeBidiType(level) \ +( \ + ((level) & 1) \ + ? SBBidiTypeL \ + : SBBidiTypeR \ +) + + +#define SBBidiTypeIsEqual(t1, t2) ((t1) == (t2)) + +#define SBBidiTypeIsNumber(t) SBUInt8InRange(t, SBBidiTypeAN, SBBidiTypeEN) +#define SBBidiTypeIsIsolate(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypePDI) + +#define SBBidiTypeIsStrongOrNumber(t) (SBBidiTypeIsStrong(t) || SBBidiTypeIsNumber(t)) +#define SBBidiTypeIsNumberSeparator(t) SBUInt8InRange(t, SBBidiTypeES, SBBidiTypeCS) +#define SBBidiTypeIsIsolateInitiator(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypeFSI) +#define SBBidiTypeIsIsolateTerminator(t) SBBidiTypeIsEqual(t, SBBidiTypePDI) +#define SBBidiTypeIsNeutralOrIsolate(t) SBUInt8InRange(t, SBBidiTypeWS, SBBidiTypePDI) + +#define SBScriptIsCommonOrInherited(s) ((s) <= SBScriptZYYY) + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBCodepoint.c b/src/thirdparty/SheenBidi/Source/SBCodepoint.c new file mode 100644 index 000000000..3901b6b84 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBCodepoint.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "BidiTypeLookup.h" +#include "GeneralCategoryLookup.h" +#include "PairingLookup.h" +#include "ScriptLookup.h" +#include "SBCodepoint.h" + +typedef struct { + SBUInt8 valid; + SBUInt8 total; + SBUInt8 start; + SBUInt8 end; +} UTF8State; + +static const UTF8State UTF8StateTable[9] = { + { 1, 0, 0x00, 0x00 }, { 0, 0, 0x00, 0x00 }, { 1, 2, 0x80, 0xBF }, { 1, 3, 0xA0, 0xBF }, + { 1, 3, 0x80, 0xBF }, { 1, 3, 0x80, 0x9F }, { 1, 4, 0x90, 0xBF }, { 1, 4, 0x80, 0xBF }, + { 1, 4, 0x80, 0x8F } +}; + +static const SBUInt8 UTF8LookupTable[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, +/* LEAD: -- 80..BF -- */ + 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, +/* LEAD: -- C0..C1 -- */ + 1, 1, +/* LEAD: -- C2..DF -- */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +/* LEAD: -- E0..E0 -- */ + 3, +/* LEAD: -- E1..EC -- */ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +/* LEAD: -- ED..ED -- */ + 5, +/* LEAD: -- EE..EF -- */ + 4, 4, +/* LEAD: -- F0..F0 -- */ + 6, +/* LEAD: -- F1..F3 -- */ + 7, 7, 7, +/* LEAD: -- F4..F4 -- */ + 8, +/* LEAD: -- F5..F7 -- */ + 1, 1, 1, +/* LEAD: -- F8..FB -- */ + 1, 1, 1, 1, +/* LEAD: -- FC..FD -- */ + 1, 1, +/* LEAD: -- FE..FF -- */ + 1, 1 +}; + +SB_INTERNAL SBBoolean SBCodepointIsCanonicalEquivalentBracket( + SBCodepoint codepoint, SBCodepoint bracket) +{ + SBCodepoint canonical; + + switch (codepoint) { + case 0x2329: + canonical = 0x3008; + break; + case 0x3008: + canonical = 0x2329; + break; + + case 0x232A: + canonical = 0x3009; + break; + case 0x3009: + canonical = 0x232A; + break; + + default: + canonical = codepoint; + break; + } + + return bracket == codepoint || bracket == canonical; +} + +SBBidiType SBCodepointGetBidiType(SBCodepoint codepoint) +{ + return LookupBidiType(codepoint); +} + +SBGeneralCategory SBCodepointGetGeneralCategory(SBCodepoint codepoint) +{ + return LookupGeneralCategory(codepoint); +} + +SBCodepoint SBCodepointGetMirror(SBCodepoint codepoint) +{ + return LookupMirror(codepoint); +} + +SBScript SBCodepointGetScript(SBCodepoint codepoint) +{ + return LookupScript(codepoint); +} + +SBCodepoint SBCodepointDecodeNextFromUTF8(const SBUInt8 *buffer, SBUInteger length, SBUInteger *index) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if (*index < length) { + SBUInt8 lead = buffer[*index]; + UTF8State state = UTF8StateTable[UTF8LookupTable[lead]]; + SBUInteger limit = *index + state.total; + + if (limit > length) { + limit = length; + state.valid = SBFalse; + } + + codepoint = lead & (0x7F >> state.total); + + while (++(*index) < limit) { + SBUInt8 byte = buffer[*index]; + + if (byte >= state.start && byte <= state.end) { + codepoint = (codepoint << 6) | (byte & 0x3F); + } else { + state.valid = SBFalse; + break; + } + + state.start = 0x80; + state.end = 0xBF; + } + + if (!state.valid) { + codepoint = SBCodepointFaulty; + } + } + + return codepoint; +} + +SBCodepoint SBCodepointDecodePreviousFromUTF8(const SBUInt8 *buffer, SBUInteger length, SBUInteger *index) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if ((*index - 1) < length) { + SBUInteger startIndex = *index; + SBUInteger limitIndex; + SBUInteger continuation; + + continuation = 4; + + while (continuation-- && --startIndex) { + SBUInt8 codeUnit = buffer[startIndex]; + + if ((codeUnit & 0xC0) != 0x80) { + break; + } + } + + limitIndex = startIndex; + codepoint = SBCodepointDecodeNextFromUTF8(buffer, length, &limitIndex); + + if (limitIndex == *index) { + *index = startIndex; + } else { + codepoint = SBCodepointFaulty; + *index -= 1; + } + } + + return codepoint; +} + +SBCodepoint SBCodepointDecodeNextFromUTF16(const SBUInt16 *buffer, SBUInteger length, SBUInteger *index) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if (*index < length) { + SBUInt16 lead; + + codepoint = SBCodepointFaulty; + + lead = buffer[*index]; + *index += 1; + + if (!SBCodepointIsSurrogate(lead)) { + codepoint = lead; + } else if (lead <= 0xDBFF) { + if (*index < length) { + SBUInt16 trail = buffer[*index]; + + if (SBUInt16InRange(trail, 0xDC00, 0xDFFF)) { + codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000); + *index += 1; + } + } + } + } + + return codepoint; +} + +SBCodepoint SBCodepointDecodePreviousFromUTF16(const SBUInt16 *buffer, SBUInteger length, SBUInteger *index) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + if ((*index - 1) < length) { + SBUInt16 trail; + + codepoint = SBCodepointFaulty; + + *index -= 1; + trail = buffer[*index]; + + if (!SBCodepointIsSurrogate(trail)) { + codepoint = trail; + } else if (trail >= 0xDC00) { + if (*index > 0) { + SBUInt16 lead = buffer[*index - 1]; + + if (SBUInt16InRange(lead, 0xD800, 0xDBFF)) { + codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000); + *index -= 1; + } + } + } + } + + return codepoint; +} diff --git a/src/thirdparty/SheenBidi/Source/SBCodepoint.h b/src/thirdparty/SheenBidi/Source/SBCodepoint.h new file mode 100644 index 000000000..ecaf4c80f --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBCodepoint.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_CODEPOINT_H +#define _SB_INTERNAL_CODEPOINT_H + +#include +#include + +SB_INTERNAL SBBoolean SBCodepointIsCanonicalEquivalentBracket( + SBCodepoint codepoint, SBCodepoint bracket); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBCodepointSequence.c b/src/thirdparty/SheenBidi/Source/SBCodepointSequence.c new file mode 100644 index 000000000..aa572e437 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBCodepointSequence.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "BidiTypeLookup.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBCodepointSequence.h" + +SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *sequence) +{ + if (sequence) { + SBBoolean encodingValid = SBFalse; + + switch (sequence->stringEncoding) { + case SBStringEncodingUTF8: + case SBStringEncodingUTF16: + case SBStringEncodingUTF32: + encodingValid = SBTrue; + break; + } + + return (encodingValid && sequence->stringBuffer && sequence->stringLength > 0); + } + + return SBFalse; +} + +SB_INTERNAL SBUInteger SBCodepointSequenceGetSeparatorLength( + const SBCodepointSequence *sequence, SBUInteger separatorIndex) +{ + SBUInteger stringIndex = separatorIndex; + SBCodepoint codepoint; + SBUInteger separatorLength; + + codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + separatorLength = stringIndex - separatorIndex; + + if (codepoint == '\r') { + /* Don't break in between 'CR' and 'LF'. */ + if (stringIndex < sequence->stringLength) { + codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + + if (codepoint == '\n') { + separatorLength = stringIndex - separatorIndex; + } + } + } + + return separatorLength; +} + +SB_INTERNAL void SBCodepointSequenceDetermineBidiTypes( + const SBCodepointSequence *sequence, SBBidiType *bidiTypes) +{ + SBUInteger stringIndex = 0; + SBUInteger firstIndex = 0; + SBCodepoint codepoint; + + while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex)) != SBCodepointInvalid) { + bidiTypes[firstIndex] = LookupBidiType(codepoint); + + /* Subsequent code units get 'BN' type. */ + while (++firstIndex < stringIndex) { + bidiTypes[firstIndex] = SBBidiTypeBN; + } + } +} + +SB_INTERNAL void SBCodepointSequenceGetParagraphBoundary( + const SBCodepointSequence *sequence, const SBBidiType *bidiTypes, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *actualLength, SBUInteger *separatorLength) +{ + SBUInteger limit = paragraphOffset + suggestedLength; + SBUInteger index; + + if (separatorLength) { + *separatorLength = 0; + } + + for (index = paragraphOffset; index < limit; index++) { + SBBidiType currentType = bidiTypes[index]; + + if (currentType == SBBidiTypeB) { + SBUInteger codeUnitCount = SBCodepointSequenceGetSeparatorLength(sequence, index); + + index += codeUnitCount; + + if (separatorLength) { + *separatorLength = codeUnitCount; + } + break; + } + } + + if (actualLength) { + *actualLength = index - paragraphOffset; + } +} + +SBCodepoint SBCodepointSequenceGetCodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + switch (codepointSequence->stringEncoding) { + case SBStringEncodingUTF8: + codepoint = SBCodepointDecodePreviousFromUTF8(codepointSequence->stringBuffer, codepointSequence->stringLength, stringIndex); + break; + + case SBStringEncodingUTF16: + codepoint = SBCodepointDecodePreviousFromUTF16(codepointSequence->stringBuffer, codepointSequence->stringLength, stringIndex); + break; + + case SBStringEncodingUTF32: + if ((*stringIndex - 1) < codepointSequence->stringLength) { + const SBUInt32 *buffer = codepointSequence->stringBuffer; + + *stringIndex -= 1; + codepoint = buffer[*stringIndex]; + + if (!SBCodepointIsValid(codepoint)) { + codepoint = SBCodepointFaulty; + } + } + break; + } + + return codepoint; +} + +SBCodepoint SBCodepointSequenceGetCodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex) +{ + SBCodepoint codepoint = SBCodepointInvalid; + + switch (codepointSequence->stringEncoding) { + case SBStringEncodingUTF8: + codepoint = SBCodepointDecodeNextFromUTF8(codepointSequence->stringBuffer, codepointSequence->stringLength, stringIndex); + break; + + case SBStringEncodingUTF16: + codepoint = SBCodepointDecodeNextFromUTF16(codepointSequence->stringBuffer, codepointSequence->stringLength, stringIndex); + break; + + case SBStringEncodingUTF32: + if (*stringIndex < codepointSequence->stringLength) { + const SBUInt32 *buffer = codepointSequence->stringBuffer; + + codepoint = buffer[*stringIndex]; + *stringIndex += 1; + + if (!SBCodepointIsValid(codepoint)) { + codepoint = SBCodepointFaulty; + } + } + break; + } + + return codepoint; +} diff --git a/src/thirdparty/SheenBidi/Source/SBCodepointSequence.h b/src/thirdparty/SheenBidi/Source/SBCodepointSequence.h new file mode 100644 index 000000000..cdb8b586b --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBCodepointSequence.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_CODEPOINT_SEQUENCE_H +#define _SB_INTERNAL_CODEPOINT_SEQUENCE_H + +#include +#include +#include + +SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *sequence); + +SB_INTERNAL SBUInteger SBCodepointSequenceGetSeparatorLength( + const SBCodepointSequence *sequence, SBUInteger separatorIndex); + +SB_INTERNAL void SBCodepointSequenceDetermineBidiTypes( + const SBCodepointSequence *sequence, SBBidiType *bidiTypes); + +SB_INTERNAL void SBCodepointSequenceGetParagraphBoundary( + const SBCodepointSequence *sequence, const SBBidiType *bidiTypes, + SBUInteger paragraphOffset, SBUInteger suggestedLength, + SBUInteger *actualLength, SBUInteger *separatorLength); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBLine.c b/src/thirdparty/SheenBidi/Source/SBLine.c new file mode 100644 index 000000000..7d8743252 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBLine.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include "Memory.h" +#include "Object.h" +#include "SBAlgorithm.h" +#include "SBAllocator.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBParagraph.h" +#include "SBLine.h" + +typedef SBLine *SBMutableLineRef; + +typedef struct _LineContext { + const SBBidiType *refTypes; + SBLevel *fixedLevels; + SBUInteger runCount; + SBLevel maxLevel; +} LineContext, *LineContextRef; + +static SBLevel CopyLevels(SBLevel *destination, + const SBLevel *source, SBUInteger length, SBUInteger *runCount); +static void ResetLevels(LineContextRef context, SBLevel baseLevel, SBUInteger charCount); + +#define LEVELS 0 +#define COUNT 1 + +static SBBoolean InitializeLineContext(LineContextRef context, MemoryRef memory, + const SBBidiType *types, const SBLevel *levels, SBUInteger length, SBLevel baseLevel) +{ + SBBoolean isInitialized = SBFalse; + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT]; + + sizes[LEVELS] = sizeof(SBLevel) * length; + + if (MemoryAllocateChunks(memory, MemoryTypeScratch, sizes, COUNT, pointers)) { + SBLevel *fixedLevels = pointers[LEVELS]; + + context->refTypes = types; + context->fixedLevels = fixedLevels; + context->maxLevel = CopyLevels(fixedLevels, levels, length, &context->runCount); + + ResetLevels(context, baseLevel, length); + + isInitialized = SBTrue; + } + + return isInitialized; +} + +#undef LEVELS +#undef COUNT + +#define LINE 0 +#define RUNS 1 +#define COUNT 2 + +static SBMutableLineRef AllocateLine(SBUInteger runCount) +{ + SBMutableLineRef line = NULL; + + if (runCount > 0) { + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT] = { 0 }; + + sizes[LINE] = sizeof(SBLine); + sizes[RUNS] = sizeof(SBRun) * runCount; + + line = ObjectCreate(sizes, COUNT, pointers, NULL); + + if (line) { + line->fixedRuns = pointers[RUNS]; + } + } + + return line; +} + +#undef LINE +#undef RUNS +#undef COUNT + +static SBLevel CopyLevels(SBLevel *destination, + const SBLevel *source, SBUInteger length, SBUInteger *runCount) +{ + SBLevel lastLevel = SBLevelInvalid; + SBLevel maxLevel = 0; + SBUInteger totalRuns = 0; + SBUInteger index; + + for (index = 0; index < length; index++) { + SBLevel level = source[index]; + destination[index] = level; + + if (level != lastLevel) { + totalRuns += 1; + + if (level > maxLevel) { + maxLevel = level; + } + } + } + + *runCount = totalRuns; + + return maxLevel; +} + +static void SetNewLevel(SBLevel *levels, SBUInteger length, SBLevel newLevel) +{ + SBUInteger index; + + for (index = 0; index < length; index++) { + levels[index] = newLevel; + } +} + +static void ResetLevels(LineContextRef context, SBLevel baseLevel, SBUInteger charCount) +{ + const SBBidiType *types = context->refTypes; + SBLevel *levels = context->fixedLevels; + SBUInteger index; + SBUInteger length; + SBBoolean reset; + + index = charCount; + length = 0; + reset = SBTrue; + + while (index--) { + SBBidiType type = types[index]; + + switch (type) { + case SBBidiTypeB: + case SBBidiTypeS: + SetNewLevel(levels + index, length + 1, baseLevel); + length = 0; + reset = SBTrue; + context->runCount += 1; + break; + + case SBBidiTypeLRE: + case SBBidiTypeRLE: + case SBBidiTypeLRO: + case SBBidiTypeRLO: + case SBBidiTypePDF: + case SBBidiTypeBN: + length += 1; + break; + + case SBBidiTypeWS: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + if (reset) { + SetNewLevel(levels + index, length + 1, baseLevel); + length = 0; + + context->runCount += 1; + } + break; + + default: + length = 0; + reset = SBFalse; + break; + } + } +} + +static SBUInteger InitializeRuns(SBRun *runs, + const SBLevel *levels, SBUInteger length, SBUInteger lineOffset) +{ + SBUInteger runIndex = 0; + SBUInteger index; + + runs[runIndex].offset = lineOffset; + runs[runIndex].level = levels[0]; + + for (index = 0; index < length; index++) { + SBLevel level = levels[index]; + + if (level != runs[runIndex].level) { + runs[runIndex].length = index + lineOffset - runs[runIndex].offset; + + runIndex += 1; + runs[runIndex].offset = lineOffset + index; + runs[runIndex].level = level; + } + } + + runs[runIndex].length = index + lineOffset - runs[runIndex].offset; + + return runIndex + 1; +} + +static void ReverseRunSequence(SBRun *runs, SBUInteger runCount) +{ + SBUInteger halfCount = runCount / 2; + SBUInteger finalIndex = runCount - 1; + SBUInteger index; + + for (index = 0; index < halfCount; index++) { + SBUInteger tieIndex; + SBRun tempRun; + + tieIndex = finalIndex - index; + + tempRun = runs[index]; + runs[index] = runs[tieIndex]; + runs[tieIndex] = tempRun; + } +} + +static void ReorderRuns(SBRun *runs, SBUInteger runCount, SBLevel maxLevel) +{ + SBLevel newLevel; + + for (newLevel = maxLevel; newLevel; newLevel--) { + SBUInteger start = runCount; + + while (start--) { + if (runs[start].level >= newLevel) { + SBUInteger count = 1; + + for (; start && runs[start - 1].level >= newLevel; start--) { + count += 1; + } + + ReverseRunSequence(runs + start, count); + } + } + } +} + +SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph, + SBUInteger lineOffset, SBUInteger lineLength) +{ + SBUInteger innerOffset = lineOffset - paragraph->offset; + const SBBidiType *refTypes = paragraph->refTypes + innerOffset; + const SBLevel *refLevels = paragraph->fixedLevels + innerOffset; + SBMutableLineRef line = NULL; + Memory memory; + LineContext context; + + /* Line range MUST be valid. */ + SBAssert(lineOffset < (lineOffset + lineLength) + && lineOffset >= paragraph->offset + && (lineOffset + lineLength) <= (paragraph->offset + paragraph->length)); + + MemoryInitialize(&memory); + + if (InitializeLineContext(&context, &memory, refTypes, refLevels, lineLength, paragraph->baseLevel)) { + line = AllocateLine(context.runCount); + + if (line) { + line->runCount = InitializeRuns(line->fixedRuns, context.fixedLevels, lineLength, lineOffset); + ReorderRuns(line->fixedRuns, line->runCount, context.maxLevel); + + line->codepointSequence = paragraph->codepointSequence; + line->offset = lineOffset; + line->length = lineLength; + } + } + + MemoryFinalize(&memory); + SBAllocatorResetScratch(NULL); + + return line; +} + +SBUInteger SBLineGetOffset(SBLineRef line) +{ + return line->offset; +} + +SBUInteger SBLineGetLength(SBLineRef line) +{ + return line->length; +} + +SBUInteger SBLineGetRunCount(SBLineRef line) +{ + return line->runCount; +} + +const SBRun *SBLineGetRunsPtr(SBLineRef line) +{ + return line->fixedRuns; +} + +SBLineRef SBLineRetain(SBLineRef line) +{ + return ObjectRetain((ObjectRef)line); +} + +void SBLineRelease(SBLineRef line) +{ + ObjectRelease((ObjectRef)line); +} diff --git a/src/thirdparty/SheenBidi/Source/SBLine.h b/src/thirdparty/SheenBidi/Source/SBLine.h new file mode 100644 index 000000000..2eb96775e --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBLine.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_LINE_H +#define _SB_INTERNAL_LINE_H + +#include +#include +#include +#include +#include +#include + +#include "Object.h" + +typedef struct _SBLine { + ObjectBase _base; + SBCodepointSequence codepointSequence; + SBRun *fixedRuns; + SBUInteger runCount; + SBUInteger offset; + SBUInteger length; +} SBLine; + +SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph, + SBUInteger lineOffset, SBUInteger lineLength); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBLog.c b/src/thirdparty/SheenBidi/Source/SBLog.c new file mode 100644 index 000000000..f3b645901 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBLog.c @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifdef SB_CONFIG_LOG + +#include "BidiChain.h" +#include "IsolatingRun.h" +#include "LevelRun.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBCodepointSequence.h" +#include "SBLog.h" + +int _SBLogPosition = 0; + +SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel) +{ + switch (baseLevel) { + case SBLevelDefaultLTR: + SB_LOG_STRING("Auto-LTR"); + break; + + case SBLevelDefaultRTL: + SB_LOG_STRING("Auto-RTL"); + break; + + case 0: + SB_LOG_STRING("LTR"); + break; + + case 1: + SB_LOG_STRING("RTL"); + break; + + default: + SB_LOG(("Level - %d", baseLevel)); + break; + } +} + +SB_INTERNAL void PrintBidiType(SBBidiType type) +{ + switch (type) { + case SBBidiTypeNil: + SB_LOG_STRING("Nil"); + break; + + case SBBidiTypeL: + SB_LOG_STRING("L"); + break; + + case SBBidiTypeR: + SB_LOG_STRING("R"); + break; + + case SBBidiTypeAL: + SB_LOG_STRING("AL"); + break; + + case SBBidiTypeEN: + SB_LOG_STRING("EN"); + break; + + case SBBidiTypeES: + SB_LOG_STRING("ES"); + break; + + case SBBidiTypeET: + SB_LOG_STRING("EN"); + break; + + case SBBidiTypeAN: + SB_LOG_STRING("AN"); + break; + + case SBBidiTypeCS: + SB_LOG_STRING("CS"); + break; + + case SBBidiTypeNSM: + SB_LOG_STRING("NSM"); + break; + + case SBBidiTypeBN: + SB_LOG_STRING("BN"); + break; + + case SBBidiTypeB: + SB_LOG_STRING("B"); + break; + + case SBBidiTypeS: + SB_LOG_STRING("S"); + break; + + case SBBidiTypeWS: + SB_LOG_STRING("WS"); + break; + + case SBBidiTypeON: + SB_LOG_STRING("ON"); + break; + + case SBBidiTypeLRE: + SB_LOG_STRING("LRE"); + break; + + case SBBidiTypeRLE: + SB_LOG_STRING("RLE"); + break; + + case SBBidiTypeLRO: + SB_LOG_STRING("LRO"); + break; + + case SBBidiTypeRLO: + SB_LOG_STRING("RLO"); + break; + + case SBBidiTypePDF: + SB_LOG_STRING("PDF"); + break; + + case SBBidiTypeLRI: + SB_LOG_STRING("LRI"); + break; + + case SBBidiTypeRLI: + SB_LOG_STRING("RLI"); + break; + + case SBBidiTypeFSI: + SB_LOG_STRING("FSI"); + break; + + case SBBidiTypePDI: + SB_LOG_STRING("PDI"); + break; + } +} + +SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence) +{ + SBUInteger stringIndex = 0; + SBCodepoint codepoint; + + while ((codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex)) != SBCodepointInvalid) { + SB_LOG(("%04X ", codepoint)); + } +} + +SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length) +{ + SBUInteger index; + + for (index = 0; index < length; ++index) { + SB_LOG_BIDI_TYPE(types[index]); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length) +{ + SBUInteger index; + + for (index = 0; index < length; ++index) { + SB_LOG_LEVEL(levels[index]); + SB_LOG_DIVIDER(1); + } +} + +typedef struct { + void *object; + BidiLink link; + SBUInteger length; +} IsolatingContext; + +typedef void (*IsolatingConsumer)(IsolatingRunRef isolatingRun, IsolatingContext *context); + +SB_INTERNAL void IsolatingRunForEach(IsolatingRunRef isolatingRun, + IsolatingContext *context, IsolatingConsumer consumer) +{ + BidiChainRef bidiChain = isolatingRun->bidiChain; + LevelRunRef levelRun; + + /* Iterate over individual level runs of the isolating run. */ + for (levelRun = isolatingRun->baseLevelRun; levelRun; levelRun = levelRun->next) { + BidiLink breakLink = BidiChainGetNext(bidiChain, levelRun->lastLink); + BidiLink currentLink = levelRun->firstLink; + BidiLink subsequentLink = levelRun->subsequentLink; + + /* Iterate over each link of the level run. */ + while (currentLink != breakLink) { + BidiLink nextLink = BidiChainGetNext(bidiChain, currentLink); + SBUInteger linkOffset = BidiChainGetOffset(bidiChain, currentLink); + SBUInteger linkLength; + SBUInteger index; + + if (nextLink != breakLink) { + linkLength = BidiChainGetOffset(bidiChain, nextLink) - linkOffset; + } else { + linkLength = BidiChainGetOffset(bidiChain, subsequentLink) - linkOffset; + } + + /* Skip any sequence of BN character types. */ + for (index = 1; index < linkLength; index++) { + SBBidiType bidiType = BidiChainGetType(bidiChain, currentLink + index); + if (bidiType == SBBidiTypeBN) { + linkLength = index; + break; + } + } + + context->link = currentLink; + context->length = linkLength; + consumer(isolatingRun, context); + + currentLink = nextLink; + } + } +} + +static void PrintTypesOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + SBBidiType bidiType = BidiChainGetType(isolatingRun->bidiChain, context->link); + + while (context->length--) { + SB_LOG_BIDI_TYPE(bidiType); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun) +{ + IsolatingContext context; + IsolatingRunForEach(isolatingRun, &context, PrintTypesOperation); +} + +static void PrintLevelsOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + SBLevel charLevel = BidiChainGetLevel(isolatingRun->bidiChain, context->link); + + while (context->length--) { + SB_LOG_LEVEL(charLevel); + SB_LOG_DIVIDER(1); + } +} + +SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun) +{ + IsolatingContext context; + IsolatingRunForEach(isolatingRun, &context, PrintLevelsOperation); +} + +typedef struct { + SBUInteger offset; + SBUInteger length; +} IsolatingRange; + +static void PrintRangeOperation(IsolatingRunRef isolatingRun, IsolatingContext *context) +{ + IsolatingRange *range = context->object; + SBUInteger offset = BidiChainGetOffset(isolatingRun->bidiChain, context->link); + + if (range->length == 0) { + range->offset = offset; + range->length = context->length; + } else if (offset == (range->offset + range->length)) { + range->length += context->length; + } else { + SB_LOG_RANGE(range->offset, range->length); + SB_LOG_DIVIDER(1); + + range->offset = offset; + range->length = context->length; + } +} + +SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun) +{ + IsolatingRange range = { 0, 0 }; + IsolatingContext context; + context.object = ⦥ + + IsolatingRunForEach(isolatingRun, &context, PrintRangeOperation); + SB_LOG_RANGE(range.offset, range.length); + SB_LOG_DIVIDER(1); +} + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBLog.h b/src/thirdparty/SheenBidi/Source/SBLog.h new file mode 100644 index 000000000..fc373bbe5 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBLog.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_LOG_H +#define _SB_INTERNAL_LOG_H + +#include + +#ifdef SB_CONFIG_LOG + +#include + +#include "IsolatingRun.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" + +SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel); +SB_INTERNAL void PrintBidiType(SBBidiType type); + +SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence); +SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length); +SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length); + +SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun); +SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun); +SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun); + +extern int _SBLogPosition; + +#define SB_LOG_BEGIN() (++_SBLogPosition) +#define SB_LOG_END() (--_SBLogPosition) + +#define SB_LOG(s) printf s + +#define SB_LOG_NUMBER(n) \ +SB_LOG(("%ld", (long)n)) + +#define SB_LOG_RANGE(o, l) \ +SB_LOG(("[%ld, %ld]", (long)o, (long)(o + l - 1))) + +#define SB_LOG_CHAR(c) \ +SBLOG(("%c", c)) + +#define SB_LOG_STRING(s) \ +SB_LOG(("%s", s)) + +#define SB_LOG_LEVEL(l) \ +SB_LOG_NUMBER(l) + +#define SB_LOG_BREAKER() \ +SB_LOG(("\n")) + +#define SB_LOG_DIVIDER(n) \ +SB_LOG(("%.*s", n, "\t\t\t\t\t\t\t\t\t\t")) + +#define SB_LOG_INITIATOR() \ +SB_LOG_DIVIDER(_SBLogPosition) + +#define SB_LOG_CAPTION(c) \ +SB_LOG((c":")) + +#define SB_LOG_STATEMENT_TEXT(t) \ +(t) + +#define SB_LOG_LINE(s) \ +do { \ + SB_LOG(s); \ + SB_LOG_BREAKER(); \ +} while (0) + +#define SB_LOG_STATEMENT(c, d, t) \ +do { \ + SB_LOG_INITIATOR(); \ + SB_LOG_CAPTION(c); \ + SB_LOG_DIVIDER(d); \ + SB_LOG_STATEMENT_TEXT(t); \ + SB_LOG_BREAKER(); \ +} while (0) + +#define SB_LOG_BLOCK_OPENER(c) \ +do { \ + SB_LOG_INITIATOR(); \ + SB_LOG_CAPTION(c); \ + SB_LOG_BREAKER(); \ + SB_LOG_BEGIN(); \ +} while (0) + +#define SB_LOG_BLOCK_CLOSER() SB_LOG_END() + +#define SB_LOG_BASE_LEVEL(l) PrintBaseLevel(l) +#define SB_LOG_BIDI_TYPE(t) PrintBidiType(t) + +#define SB_LOG_CODEPOINT_SEQUENCE(s) PrintCodepointSequence(s) +#define SB_LOG_BIDI_TYPES_ARRAY(a, l) PrintBidiTypesArray(a, l) +#define SB_LOG_LEVELS_ARRAY(a, l) PrintLevelsArray(a, l) + +#define SB_LOG_RUN_TYPES(r) PrintRunTypes(r) +#define SB_LOG_RUN_LEVELS(r) PrintRunLevels(r) +#define SB_LOG_RUN_RANGE(r) PrintRunRange(r) + +#else + +#define SB_LOG_NONE() + +#define SB_LOG(s) SB_LOG_NONE() + +#define SB_LOG_NUMBER(n) SB_LOG_NONE() +#define SB_LOG_RANGE(o, l) SB_LOG_NONE() +#define SB_LOG_CHAR(c) SB_LOG_NONE() +#define SB_LOG_STRING(s) SB_LOG_NONE() +#define SB_LOG_LEVEL(l) SB_LOG_NONE() + +#define SB_LOG_BREAKER() SB_LOG_NONE() +#define SB_LOG_DIVIDER(n) SB_LOG_NONE() +#define SB_LOG_INITIATOR() SB_LOG_NONE() +#define SB_LOG_CAPTION(c) SB_LOG_NONE() +#define SB_LOG_STATEMENT_TEXT(t) SB_LOG_NONE() + +#define SB_LOG_LINE(s) SB_LOG_NONE() +#define SB_LOG_STATEMENT(c, d, t) SB_LOG_NONE() + +#define SB_LOG_BLOCK_OPENER(c) SB_LOG_NONE() +#define SB_LOG_BLOCK_CLOSER() SB_LOG_NONE() + +#define SB_LOG_BASE_LEVEL(l) SB_LOG_NONE() +#define SB_LOG_BIDI_TYPE(t) SB_LOG_NONE() + +#define SB_LOG_CODEPOINT_SEQUENCE(s) SB_LOG_NONE() +#define SB_LOG_BIDI_TYPES_ARRAY(a, l) SB_LOG_NONE() +#define SB_LOG_LEVELS_ARRAY(a, l) SB_LOG_NONE() + +#define SB_LOG_RUN_TYPES(r) SB_LOG_NONE() +#define SB_LOG_RUN_LEVELS(r) SB_LOG_NONE() + +#define SB_LOG_RUN_RANGE(r) SB_LOG_NONE() + +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBMirrorLocator.c b/src/thirdparty/SheenBidi/Source/SBMirrorLocator.c new file mode 100644 index 000000000..076ddb306 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBMirrorLocator.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Object.h" +#include "PairingLookup.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBLine.h" +#include "SBMirrorLocator.h" + +static void FinalizeMirrorLocator(ObjectRef object) +{ + SBMirrorLocatorRef locator = object; + SBLineRelease(locator->_line); +} + +SBMirrorLocatorRef SBMirrorLocatorCreate(void) +{ + const SBUInteger size = sizeof(SBMirrorLocator); + void *pointer = NULL; + SBMirrorLocatorRef locator; + + locator = ObjectCreate(&size, 1, &pointer, &FinalizeMirrorLocator); + + if (locator) { + locator->_line = NULL; + SBMirrorLocatorReset(locator); + } + + return locator; +} + +void SBMirrorLocatorLoadLine(SBMirrorLocatorRef locator, SBLineRef line, const void *stringBuffer) +{ + if (locator->_line) { + SBLineRelease(locator->_line); + locator->_line = NULL; + } + + if (line && stringBuffer == line->codepointSequence.stringBuffer) { + locator->_line = SBLineRetain(line); + } + + SBMirrorLocatorReset(locator); +} + +const SBMirrorAgent *SBMirrorLocatorGetAgent(SBMirrorLocatorRef locator) +{ + return &locator->agent; +} + +SBBoolean SBMirrorLocatorMoveNext(SBMirrorLocatorRef locator) +{ + SBLineRef line = locator->_line; + + if (line) { + const SBCodepointSequence *sequence = &line->codepointSequence; + + do { + const SBRun *run = &line->fixedRuns[locator->_runIndex]; + + if (run->level & 1) { + SBUInteger stringIndex; + SBUInteger stringLimit; + + stringIndex = locator->_stringIndex; + if (stringIndex == SBInvalidIndex) { + stringIndex = run->offset; + } + stringLimit = run->offset + run->length; + + while (stringIndex < stringLimit) { + SBUInteger initialIndex = stringIndex; + SBCodepoint codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex); + SBCodepoint mirror = LookupMirror(codepoint); + + if (mirror) { + locator->_stringIndex = stringIndex; + locator->agent.index = initialIndex; + locator->agent.mirror = mirror; + locator->agent.codepoint = codepoint; + + return SBTrue; + } + } + } + + locator->_stringIndex = SBInvalidIndex; + } while (++locator->_runIndex < line->runCount); + + SBMirrorLocatorReset(locator); + } + + return SBFalse; +} + +void SBMirrorLocatorReset(SBMirrorLocatorRef locator) +{ + locator->_runIndex = 0; + locator->_stringIndex = SBInvalidIndex; + locator->agent.index = SBInvalidIndex; + locator->agent.mirror = 0; +} + +SBMirrorLocatorRef SBMirrorLocatorRetain(SBMirrorLocatorRef locator) +{ + return ObjectRetain((ObjectRef)locator); +} + +void SBMirrorLocatorRelease(SBMirrorLocatorRef locator) +{ + ObjectRelease((ObjectRef)locator); +} diff --git a/src/thirdparty/SheenBidi/Source/SBMirrorLocator.h b/src/thirdparty/SheenBidi/Source/SBMirrorLocator.h new file mode 100644 index 000000000..148985698 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBMirrorLocator.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_MIRROR_LOCATOR_H +#define _SB_INTERNAL_MIRROR_LOCATOR_H + +#include +#include +#include + +#include "Object.h" + +typedef struct _SBMirrorLocator { + ObjectBase _base; + SBLineRef _line; + SBUInteger _runIndex; + SBUInteger _stringIndex; + SBMirrorAgent agent; +} SBMirrorLocator; + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBParagraph.c b/src/thirdparty/SheenBidi/Source/SBParagraph.c new file mode 100644 index 000000000..f281ae143 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBParagraph.c @@ -0,0 +1,740 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include + +#include + +#include "BidiChain.h" +#include "BidiTypeLookup.h" +#include "IsolatingRun.h" +#include "LevelRun.h" +#include "Memory.h" +#include "Object.h" +#include "RunQueue.h" +#include "SBAlgorithm.h" +#include "SBAllocator.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepointSequence.h" +#include "SBLine.h" +#include "SBLog.h" +#include "StatusStack.h" +#include "SBParagraph.h" + +typedef SBParagraph *SBMutableParagraphRef; + +typedef struct _ParagraphContext { + BidiChain bidiChain; + StatusStack statusStack; + RunQueue runQueue; + IsolatingRun isolatingRun; +} ParagraphContext, *ParagraphContextRef; + +static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length); +static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRun *levelRun, SBBoolean resolveIsolatingRuns); +static void FinalizeParagraph(ObjectRef object); + +#define BIDI_LINKS 0 +#define BIDI_TYPES 1 +#define BIDI_FLAGS 2 +#define COUNT 3 + +static SBBoolean InitializeParagraphContext(ParagraphContextRef context, MemoryRef memory, + const SBBidiType *types, SBLevel *levels, SBUInteger length) +{ + SBBoolean isInitialized = SBFalse; + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT]; + + sizes[BIDI_LINKS] = sizeof(BidiLink) * (length + 2); + sizes[BIDI_TYPES] = sizeof(SBBidiType) * (length + 2); + sizes[BIDI_FLAGS] = sizeof(BidiFlag) * (length + 2); + + if (MemoryAllocateChunks(memory, MemoryTypeScratch, sizes, COUNT, pointers)) { + BidiLink *fixedLinks = pointers[BIDI_LINKS]; + SBBidiType *fixedTypes = pointers[BIDI_TYPES]; + BidiFlag *fixedFlags = pointers[BIDI_FLAGS]; + + BidiChainInitialize(&context->bidiChain, fixedTypes, levels, fixedFlags, fixedLinks); + StatusStackInitialize(&context->statusStack, memory); + RunQueueInitialize(&context->runQueue, memory); + IsolatingRunInitialize(&context->isolatingRun, memory); + + PopulateBidiChain(&context->bidiChain, types, length); + + isInitialized = SBTrue; + } + + return isInitialized; +} + +#undef BIDI_LINKS +#undef BIDI_TYPES +#undef BIDI_FLAGS +#undef COUNT + +#define PARAGRAPH 0 +#define LEVELS 1 +#define COUNT 2 + +static SBMutableParagraphRef AllocateParagraph(SBUInteger length) +{ + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT] = { 0 }; + SBMutableParagraphRef paragraph; + + sizes[PARAGRAPH] = sizeof(SBParagraph); + sizes[LEVELS] = sizeof(SBLevel) * (length + 2); + + paragraph = ObjectCreate(sizes, COUNT, pointers, FinalizeParagraph); + + if (paragraph) { + paragraph->fixedLevels = pointers[LEVELS]; + } + + return paragraph; +} + +#undef PARAGRAPH +#undef LEVELS +#undef COUNT + +static void FinalizeParagraph(ObjectRef object) +{ + SBParagraphRef paragraph = object; + SBAlgorithmRef algorithm; + + algorithm = paragraph->_algorithm; + + if (algorithm) { + SBAlgorithmRelease(algorithm); + } +} + +static SBUInteger DetermineBoundary(const SBCodepointSequence *codepointSequence, + const SBBidiType *bidiTypes, SBUInteger paragraphOffset, SBUInteger suggestedLength) +{ + SBUInteger suggestedLimit = paragraphOffset + suggestedLength; + SBUInteger stringIndex; + + for (stringIndex = paragraphOffset; stringIndex < suggestedLimit; stringIndex++) { + if (bidiTypes[stringIndex] == SBBidiTypeB) { + stringIndex += SBCodepointSequenceGetSeparatorLength(codepointSequence, stringIndex); + goto Return; + } + } + +Return: + return (stringIndex - paragraphOffset); +} + +static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length) +{ + SBBidiType type = SBBidiTypeNil; + SBUInteger priorIndex = SBInvalidIndex; + SBUInteger index; + + for (index = 0; index < length; index++) { + SBBidiType priorType = type; + type = types[index]; + + switch (type) { + case SBBidiTypeB: + case SBBidiTypeON: + case SBBidiTypeLRE: + case SBBidiTypeRLE: + case SBBidiTypeLRO: + case SBBidiTypeRLO: + case SBBidiTypePDF: + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + case SBBidiTypePDI: + BidiChainAdd(chain, type, index - priorIndex); + priorIndex = index; + + if (type == SBBidiTypeB) { + index = length; + goto AddLast; + } + break; + + default: + if (type != priorType) { + BidiChainAdd(chain, type, index - priorIndex); + priorIndex = index; + } + break; + } + } + +AddLast: + BidiChainAdd(chain, SBBidiTypeNil, index - priorIndex); +} + +static BidiLink SkipIsolatingRun(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink) +{ + BidiLink link = skipLink; + SBUInteger depth = 1; + + while ((link = BidiChainGetNext(chain, link)) != breakLink) { + SBBidiType type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + depth += 1; + break; + + case SBBidiTypePDI: + if (--depth == 0) { + return link; + } + break; + } + } + + return BidiLinkNone; +} + +static SBLevel DetermineBaseLevel(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink, SBLevel defaultLevel, SBBoolean isIsolate) +{ + BidiLink link = skipLink; + + /* Rules P2, P3 */ + while ((link = BidiChainGetNext(chain, link)) != breakLink) { + SBBidiType type = BidiChainGetType(chain, link); + + switch (type) { + case SBBidiTypeL: + return 0; + + case SBBidiTypeAL: + case SBBidiTypeR: + return 1; + + case SBBidiTypeLRI: + case SBBidiTypeRLI: + case SBBidiTypeFSI: + link = SkipIsolatingRun(chain, link, breakLink); + if (link == BidiLinkNone) { + goto Default; + } + break; + + case SBBidiTypePDI: + if (isIsolate) { + /* + * In case of isolating run, the PDI will be the last code point. + * NOTE: + * The inner isolating runs will be skipped by the case above this one. + */ + goto Default; + } + break; + } + } + +Default: + return defaultLevel; +} + +static SBLevel DetermineParagraphLevel(BidiChainRef chain, SBLevel baseLevel) +{ + if (baseLevel >= SBLevelMax) { + return DetermineBaseLevel(chain, chain->roller, chain->roller, + (baseLevel != SBLevelDefaultRTL ? 0 : 1), + SBFalse); + } + + return baseLevel; +} + +static SBBoolean DetermineLevels(ParagraphContextRef context, SBLevel baseLevel) +{ + BidiChainRef chain = &context->bidiChain; + StatusStackRef stack = &context->statusStack; + BidiLink roller = chain->roller; + BidiLink link; + + BidiLink priorLink; + BidiLink firstLink; + BidiLink lastLink; + + SBLevel priorLevel; + SBBidiType sor; + SBBidiType eor; + + SBUInteger overIsolate; + SBUInteger overEmbedding; + SBUInteger validIsolate; + + priorLink = chain->roller; + firstLink = BidiLinkNone; + lastLink = BidiLinkNone; + + priorLevel = baseLevel; + sor = SBBidiTypeNil; + + /* Rule X1 */ + overIsolate = 0; + overEmbedding = 0; + validIsolate = 0; + + StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse); + + BidiChainForEach(chain, roller, link) { + SBBoolean forceFinish = SBFalse; + SBBoolean bnEquivalent = SBFalse; + SBBidiType type; + + type = BidiChainGetType(chain, link); + +#define LeastGreaterOddLevel() \ +( \ + (StatusStackGetEmbeddingLevel(stack) + 1) | 1 \ +) + +#define LeastGreaterEvenLevel() \ +( \ + (StatusStackGetEmbeddingLevel(stack) + 2) & ~1 \ +) + +#define MergeLinkIfNeeded() \ +{ \ + if (BidiChainMergeNext(chain, priorLink)) { \ + continue; \ + } \ +} + +#define PushEmbedding(l, o) \ +{ \ + SBLevel newLevel = l; \ + \ + bnEquivalent = SBTrue; \ + \ + if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \ + if (!StatusStackPush(stack, newLevel, o, SBFalse)) { \ + return SBFalse; \ + } \ + } else { \ + if (!overIsolate) { \ + overEmbedding += 1; \ + } \ + } \ +} + +#define PushIsolate(l, o) \ +{ \ + SBBidiType priorStatus = StatusStackGetOverrideStatus(stack); \ + SBLevel newLevel = l; \ + \ + BidiChainSetLevel(chain, link, \ + StatusStackGetEmbeddingLevel(stack)); \ + \ + if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \ + validIsolate += 1; \ + \ + if (!StatusStackPush(stack, newLevel, o, SBTrue)) { \ + return SBFalse; \ + } \ + } else { \ + overIsolate += 1; \ + } \ + \ + if (priorStatus != SBBidiTypeON) { \ + BidiChainSetType(chain, link, priorStatus); \ + MergeLinkIfNeeded(); \ + } \ +} + + switch (type) { + /* Rule X2 */ + case SBBidiTypeRLE: + PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeON); + break; + + /* Rule X3 */ + case SBBidiTypeLRE: + PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeON); + break; + + /* Rule X4 */ + case SBBidiTypeRLO: + PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeR); + break; + + /* Rule X5 */ + case SBBidiTypeLRO: + PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeL); + break; + + /* Rule X5a */ + case SBBidiTypeRLI: + PushIsolate(LeastGreaterOddLevel(), SBBidiTypeON); + break; + + /* Rule X5b */ + case SBBidiTypeLRI: + PushIsolate(LeastGreaterEvenLevel(), SBBidiTypeON); + break; + + /* Rule X5c */ + case SBBidiTypeFSI: + { + SBBoolean isRTL = (DetermineBaseLevel(chain, link, roller, 0, SBTrue) == 1); + PushIsolate(isRTL ? LeastGreaterOddLevel() : LeastGreaterEvenLevel(), SBBidiTypeON); + break; + } + + /* Rule X6 */ + default: + BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack)); + + if (StatusStackGetOverrideStatus(stack) != SBBidiTypeON) { + BidiChainSetType(chain, link, StatusStackGetOverrideStatus(stack)); + MergeLinkIfNeeded(); + } + break; + + /* Rule X6a */ + case SBBidiTypePDI: + { + SBBidiType overrideStatus; + + if (overIsolate != 0) { + overIsolate -= 1; + } else if (validIsolate == 0) { + /* Do nothing */ + } else { + overEmbedding = 0; + + while (!StatusStackGetIsolateStatus(stack)) { + StatusStackPop(stack); + } + StatusStackPop(stack); + + validIsolate -= 1; + } + + BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack)); + overrideStatus = StatusStackGetOverrideStatus(stack); + + if (overrideStatus != SBBidiTypeON) { + BidiChainSetType(chain, link, overrideStatus); + MergeLinkIfNeeded(); + } + break; + } + + /* Rule X7 */ + case SBBidiTypePDF: + bnEquivalent = SBTrue; + + if (overIsolate != 0) { + /* Do nothing */ + } else if (overEmbedding != 0) { + overEmbedding -= 1; + } else if (!StatusStackGetIsolateStatus(stack) && stack->count >= 2) { + StatusStackPop(stack); + } + break; + + /* Rule X8 */ + case SBBidiTypeB: + /* + * These values are reset for clarity, in this implementation B can only occur as the + * last code in the array. + */ + StatusStackSetEmpty(stack); + StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse); + + overIsolate = 0; + overEmbedding = 0; + validIsolate = 0; + + BidiChainSetLevel(chain, link, baseLevel); + break; + + case SBBidiTypeBN: + bnEquivalent = SBTrue; + break; + + case SBBidiTypeNil: + forceFinish = SBTrue; + BidiChainSetLevel(chain, link, baseLevel); + break; + } + + /* Rule X9 */ + if (bnEquivalent) { + /* The type of this link is BN equivalent, so abandon it and continue the loop. */ + BidiChainAbandonNext(chain, priorLink); + continue; + } + + if (sor == SBBidiTypeNil) { + sor = SBLevelAsNormalBidiType(SBNumberGetMax(baseLevel, BidiChainGetLevel(chain, link))); + firstLink = link; + priorLevel = BidiChainGetLevel(chain, link); + } else if (priorLevel != BidiChainGetLevel(chain, link) || forceFinish) { + LevelRun levelRun; + SBLevel currentLevel; + + /* Since the level has changed at this link, therefore the run must end at prior link. */ + lastLink = priorLink; + + /* Save the current level i.e. level of the next run. */ + currentLevel = BidiChainGetLevel(chain, link); + /* + * Now we have both the prior level and the current level i.e. unchanged levels of both + * the current run and the next run. So, identify eor of the current run. + * NOTE: + * sor of the run has been already determined at this stage. + */ + eor = SBLevelAsNormalBidiType(SBNumberGetMax(priorLevel, currentLevel)); + + LevelRunInitialize(&levelRun, chain, firstLink, lastLink, sor, eor); + + if (!ProcessRun(context, &levelRun, forceFinish)) { + return SBFalse; + } + + /* The sor of next run (if any) should be technically equal to eor of this run. */ + sor = eor; + /* The next run (if any) will start from this index. */ + firstLink = link; + + priorLevel = currentLevel; + } + + priorLink = link; + } + + return SBTrue; +} + +static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRun *levelRun, SBBoolean resolveIsolatingRuns) +{ + RunQueueRef queue = &context->runQueue; + + if (!RunQueueEnqueue(queue, levelRun)) { + return SBFalse; + } + + if (resolveIsolatingRuns) { + IsolatingRunRef isolatingRun = &context->isolatingRun; + + /* Rule X10 */ + for (; queue->count > 0; RunQueueDequeue(queue)) { + const LevelRun *front = RunQueueGetFront(queue); + + if (RunKindIsAttachedTerminating(front->kind)) { + continue; + } + + isolatingRun->baseLevelRun = front; + + if (!IsolatingRunResolve(isolatingRun)) { + return SBFalse; + } + } + } + + return SBTrue; +} + +static void SaveLevels(BidiChainRef chain, SBLevel *levels, SBLevel baseLevel) +{ + BidiLink roller = chain->roller; + BidiLink link; + + SBUInteger index = 0; + SBLevel level = baseLevel; + + BidiChainForEach(chain, roller, link) { + SBUInteger offset = BidiChainGetOffset(chain, link); + + for (; index < offset; index++) { + levels[index] = level; + } + + level = BidiChainGetLevel(chain, link); + } +} + +static SBBoolean ResolveParagraph(SBMutableParagraphRef paragraph, MemoryRef memory, + const SBCodepointSequence *codepointSequence, const SBBidiType *refBidiTypes, + SBUInteger offset, SBUInteger length, SBLevel baseLevel) +{ + const SBBidiType *bidiTypes = &refBidiTypes[offset]; + SBBoolean isSucceeded = SBFalse; + ParagraphContext context; + + if (InitializeParagraphContext(&context, memory, bidiTypes, paragraph->fixedLevels, length)) { + SBLevel resolvedLevel = DetermineParagraphLevel(&context.bidiChain, baseLevel); + + SB_LOG_BLOCK_OPENER("Determined Paragraph Level"); + SB_LOG_STATEMENT("Base Level", 1, SB_LOG_LEVEL(resolvedLevel)); + SB_LOG_BLOCK_CLOSER(); + + context.isolatingRun.codepointSequence = codepointSequence; + context.isolatingRun.bidiTypes = bidiTypes; + context.isolatingRun.bidiChain = &context.bidiChain; + context.isolatingRun.paragraphOffset = offset; + context.isolatingRun.paragraphLevel = resolvedLevel; + + if (DetermineLevels(&context, resolvedLevel)) { + SaveLevels(&context.bidiChain, paragraph->fixedLevels, resolvedLevel); + + SB_LOG_BLOCK_OPENER("Determined Embedding Levels"); + SB_LOG_STATEMENT("Levels", 1, SB_LOG_LEVELS_ARRAY(paragraph->fixedLevels, length)); + SB_LOG_BLOCK_CLOSER(); + + paragraph->codepointSequence = *codepointSequence; + paragraph->refTypes = bidiTypes; + paragraph->offset = offset; + paragraph->length = length; + paragraph->baseLevel = resolvedLevel; + + isSucceeded = SBTrue; + } + } + + return isSucceeded; +} + +static SBParagraphRef CreateParagraph(SBAlgorithmRef algorithm, + const SBCodepointSequence *codepointSequence, const SBBidiType *refBidiTypes, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + SBUInteger actualLength; + SBMutableParagraphRef paragraph; + + if (algorithm) { + codepointSequence = &algorithm->codepointSequence; + refBidiTypes = algorithm->fixedTypes; + } + + SB_LOG_BLOCK_OPENER("Paragraph Input"); + SB_LOG_STATEMENT("Paragraph Offset", 1, SB_LOG_NUMBER(paragraphOffset)); + SB_LOG_STATEMENT("Suggested Length", 1, SB_LOG_NUMBER(suggestedLength)); + SB_LOG_STATEMENT("Base Direction", 1, SB_LOG_BASE_LEVEL(baseLevel)); + SB_LOG_BLOCK_CLOSER(); + + actualLength = DetermineBoundary(codepointSequence, refBidiTypes, paragraphOffset, suggestedLength); + + SB_LOG_BLOCK_OPENER("Determined Paragraph Boundary"); + SB_LOG_STATEMENT("Actual Length", 1, SB_LOG_NUMBER(actualLength)); + SB_LOG_BLOCK_CLOSER(); + + paragraph = AllocateParagraph(actualLength); + + if (paragraph) { + SBBoolean isResolved; + Memory memory; + + MemoryInitialize(&memory); + isResolved = ResolveParagraph( + paragraph, &memory, codepointSequence, refBidiTypes, + paragraphOffset, actualLength, baseLevel + ); + + if (isResolved) { + paragraph->_algorithm = (algorithm ? SBAlgorithmRetain(algorithm) : NULL); + } else { + ObjectRelease(paragraph); + paragraph = NULL; + } + + MemoryFinalize(&memory); + SBAllocatorResetScratch(NULL); + } + + SB_LOG_BREAKER(); + + return paragraph; +} + +SB_INTERNAL SBParagraphRef SBParagraphCreateWithAlgorithm(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + SBUInteger stringLength = algorithm->codepointSequence.stringLength; + + /* The specified range MUST be valid */ + SBAssert(SBUIntegerVerifyRange(stringLength, paragraphOffset, suggestedLength) && suggestedLength > 0); + + return CreateParagraph(algorithm, NULL, NULL, paragraphOffset, suggestedLength, baseLevel); +} + +SB_INTERNAL SBParagraphRef SBParagraphCreateWithCodepointSequence( + const SBCodepointSequence *codepointSequence, const SBBidiType *refBidiTypes, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel) +{ + SBUInteger stringLength = codepointSequence->stringLength; + + /* The specified range MUST be valid */ + SBAssert(SBUIntegerVerifyRange(stringLength, paragraphOffset, suggestedLength) && suggestedLength > 0); + + return CreateParagraph(NULL, codepointSequence, refBidiTypes, paragraphOffset, suggestedLength, baseLevel); +} + +SBUInteger SBParagraphGetOffset(SBParagraphRef paragraph) +{ + return paragraph->offset; +} + +SBUInteger SBParagraphGetLength(SBParagraphRef paragraph) +{ + return paragraph->length; +} + +SBLevel SBParagraphGetBaseLevel(SBParagraphRef paragraph) +{ + return paragraph->baseLevel; +} + +const SBLevel *SBParagraphGetLevelsPtr(SBParagraphRef paragraph) +{ + return paragraph->fixedLevels; +} + +SBLineRef SBParagraphCreateLine(SBParagraphRef paragraph, SBUInteger lineOffset, SBUInteger lineLength) +{ + SBUInteger paragraphOffset = paragraph->offset; + SBUInteger paragraphLength = paragraph->length; + SBUInteger paragraphLimit = paragraphOffset + paragraphLength; + SBUInteger lineLimit = lineOffset + lineLength; + + if (lineOffset < lineLimit && lineOffset >= paragraphOffset && lineLimit <= paragraphLimit) { + return SBLineCreate(paragraph, lineOffset, lineLength); + } + + return NULL; +} + +SBParagraphRef SBParagraphRetain(SBParagraphRef paragraph) +{ + return ObjectRetain((ObjectRef)paragraph); +} + +void SBParagraphRelease(SBParagraphRef paragraph) +{ + ObjectRelease((ObjectRef)paragraph); +} diff --git a/src/thirdparty/SheenBidi/Source/SBParagraph.h b/src/thirdparty/SheenBidi/Source/SBParagraph.h new file mode 100644 index 000000000..a63f1cf02 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBParagraph.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_PARAGRAPH_H +#define _SB_INTERNAL_PARAGRAPH_H + +#include +#include +#include +#include + +#include "Object.h" + +typedef struct _SBParagraph { + ObjectBase _base; + SBAlgorithmRef _algorithm; + SBCodepointSequence codepointSequence; + const SBBidiType *refTypes; + SBLevel *fixedLevels; + SBUInteger offset; + SBUInteger length; + SBLevel baseLevel; +} SBParagraph; + +SB_INTERNAL SBParagraphRef SBParagraphCreateWithAlgorithm(SBAlgorithmRef algorithm, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel); + +SB_INTERNAL SBParagraphRef SBParagraphCreateWithCodepointSequence( + const SBCodepointSequence *codepointSequence, const SBBidiType *refBidiTypes, + SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SBScriptLocator.c b/src/thirdparty/SheenBidi/Source/SBScriptLocator.c new file mode 100644 index 000000000..bf215063c --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBScriptLocator.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "GeneralCategoryLookup.h" +#include "Object.h" +#include "PairingLookup.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "SBCodepointSequence.h" +#include "ScriptLookup.h" +#include "ScriptStack.h" +#include "SBScriptLocator.h" + +static SBBoolean IsSimilarScript(SBScript lhs, SBScript rhs) +{ + return SBScriptIsCommonOrInherited(lhs) + || SBScriptIsCommonOrInherited(rhs) + || lhs == rhs; +} + +SBScriptLocatorRef SBScriptLocatorCreate(void) +{ + const SBUInteger size = sizeof(SBScriptLocator); + void *pointer = NULL; + SBScriptLocatorRef locator; + + locator = ObjectCreate(&size, 1, &pointer, NULL); + + if (locator) { + locator->_codepointSequence.stringEncoding = SBStringEncodingUTF8; + locator->_codepointSequence.stringBuffer = NULL; + locator->_codepointSequence.stringLength = 0; + + SBScriptLocatorReset(locator); + } + + return locator; +} + +void SBScriptLocatorLoadCodepoints(SBScriptLocatorRef locator, const SBCodepointSequence *codepointSequence) +{ + locator->_codepointSequence = *codepointSequence; + SBScriptLocatorReset(locator); +} + +const SBScriptAgent *SBScriptLocatorGetAgent(SBScriptLocatorRef locator) +{ + return &locator->agent; +} + +static void ResolveScriptRun(SBScriptLocatorRef locator, SBUInteger offset) +{ + const SBCodepointSequence *sequence = &locator->_codepointSequence; + ScriptStackRef stack = &locator->_scriptStack; + SBScript result = SBScriptZYYY; + SBUInteger current = offset; + SBUInteger next = offset; + SBCodepoint codepoint; + + /* Iterate over the code points of specified string buffer. */ + while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &next)) != SBCodepointInvalid) { + SBBoolean isStacked = SBFalse; + SBScript script; + + script = LookupScript(codepoint); + + /* Handle paired punctuations in case of a common script. */ + if (script == SBScriptZYYY) { + SBGeneralCategory generalCategory = LookupGeneralCategory(codepoint); + + /* Check if current code point is an open punctuation. */ + if (generalCategory == SBGeneralCategoryPS) { + SBCodepoint mirror = LookupMirror(codepoint); + if (mirror) { + /* A closing pair exists for this punctuation, so push it onto the stack. */ + ScriptStackPush(stack, result, mirror); + } + } + /* Check if current code point is a close punctuation. */ + else if (generalCategory == SBGeneralCategoryPE) { + SBBoolean isMirrored = (LookupMirror(codepoint) != 0); + if (isMirrored) { + /* Find the matching entry in the stack, while popping the unmatched ones. */ + while (!ScriptStackIsEmpty(stack)) { + SBCodepoint mirror = ScriptStackGetMirror(stack); + if (mirror != codepoint) { + ScriptStackPop(stack); + } else { + break; + } + } + + if (!ScriptStackIsEmpty(stack)) { + isStacked = SBTrue; + /* Paired punctuation match the script of enclosing text. */ + script = ScriptStackGetScript(stack); + } + } + } + } + + if (IsSimilarScript(result, script)) { + if (SBScriptIsCommonOrInherited(result) && !SBScriptIsCommonOrInherited(script)) { + /* Set the concrete script of this code point as the result. */ + result = script; + /* Seal the pending punctuations with the result. */ + ScriptStackSealPairs(stack, result); + } + + if (isStacked) { + /* Pop the paired punctuation from the stack. */ + ScriptStackPop(stack); + } + } else { + /* The current code point has a different script, so finish the run. */ + break; + } + + current = next; + } + + ScriptStackLeavePairs(stack); + + /* Set the run info in agent. */ + locator->agent.offset = offset; + locator->agent.length = current - offset; + locator->agent.script = result; +} + +SBBoolean SBScriptLocatorMoveNext(SBScriptLocatorRef locator) +{ + SBUInteger offset = locator->agent.offset + locator->agent.length; + + if (offset < locator->_codepointSequence.stringLength) { + ResolveScriptRun(locator, offset); + return SBTrue; + } + + SBScriptLocatorReset(locator); + return SBFalse; +} + +void SBScriptLocatorReset(SBScriptLocatorRef locator) +{ + ScriptStackReset(&locator->_scriptStack); + locator->agent.offset = 0; + locator->agent.length = 0; + locator->agent.script = SBScriptNil; +} + +SBScriptLocatorRef SBScriptLocatorRetain(SBScriptLocatorRef locator) +{ + return ObjectRetain((ObjectRef)locator); +} + +void SBScriptLocatorRelease(SBScriptLocatorRef locator) +{ + ObjectRelease((ObjectRef)locator); +} diff --git a/src/thirdparty/SheenBidi/Source/SBScriptLocator.h b/src/thirdparty/SheenBidi/Source/SBScriptLocator.h new file mode 100644 index 000000000..b23bf7daa --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SBScriptLocator.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_SCRIPT_LOCATOR_H +#define _SB_INTERNAL_SCRIPT_LOCATOR_H + +#include +#include + +#include "Object.h" +#include "ScriptStack.h" + +typedef struct _SBScriptLocator { + ObjectBase _base; + SBCodepointSequence _codepointSequence; + ScriptStack _scriptStack; + SBScriptAgent agent; +} SBScriptLocator; + +#endif diff --git a/src/thirdparty/SheenBidi/Source/ScriptLookup.c b/src/thirdparty/SheenBidi/Source/ScriptLookup.c new file mode 100644 index 000000000..c0aafa454 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ScriptLookup.c @@ -0,0 +1,2374 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + * + * REQUIRED MEMORY: 11328+(3391*2)+(1793*2) = 21696 Bytes + */ + +#include "ScriptLookup.h" + +#define Adlm SBScriptADLM +#define Aghb SBScriptAGHB +#define Ahom SBScriptAHOM +#define Arab SBScriptARAB +#define Armi SBScriptARMI +#define Armn SBScriptARMN +#define Avst SBScriptAVST +#define Bali SBScriptBALI +#define Bamu SBScriptBAMU +#define Bass SBScriptBASS +#define Batk SBScriptBATK +#define Beng SBScriptBENG +#define Berf SBScriptBERF +#define Bhks SBScriptBHKS +#define Bopo SBScriptBOPO +#define Brah SBScriptBRAH +#define Brai SBScriptBRAI +#define Bugi SBScriptBUGI +#define Buhd SBScriptBUHD +#define Cakm SBScriptCAKM +#define Cans SBScriptCANS +#define Cari SBScriptCARI +#define Cham SBScriptCHAM +#define Cher SBScriptCHER +#define Chrs SBScriptCHRS +#define Copt SBScriptCOPT +#define Cpmn SBScriptCPMN +#define Cprt SBScriptCPRT +#define Cyrl SBScriptCYRL +#define Deva SBScriptDEVA +#define Diak SBScriptDIAK +#define Dogr SBScriptDOGR +#define Dsrt SBScriptDSRT +#define Dupl SBScriptDUPL +#define Egyp SBScriptEGYP +#define Elba SBScriptELBA +#define Elym SBScriptELYM +#define Ethi SBScriptETHI +#define Gara SBScriptGARA +#define Geor SBScriptGEOR +#define Glag SBScriptGLAG +#define Gong SBScriptGONG +#define Gonm SBScriptGONM +#define Goth SBScriptGOTH +#define Gran SBScriptGRAN +#define Grek SBScriptGREK +#define Gujr SBScriptGUJR +#define Gukh SBScriptGUKH +#define Guru SBScriptGURU +#define Hang SBScriptHANG +#define Hani SBScriptHANI +#define Hano SBScriptHANO +#define Hatr SBScriptHATR +#define Hebr SBScriptHEBR +#define Hira SBScriptHIRA +#define Hluw SBScriptHLUW +#define Hmng SBScriptHMNG +#define Hmnp SBScriptHMNP +#define Hung SBScriptHUNG +#define Ital SBScriptITAL +#define Java SBScriptJAVA +#define Kali SBScriptKALI +#define Kana SBScriptKANA +#define Kawi SBScriptKAWI +#define Khar SBScriptKHAR +#define Khmr SBScriptKHMR +#define Khoj SBScriptKHOJ +#define Kits SBScriptKITS +#define Knda SBScriptKNDA +#define Krai SBScriptKRAI +#define Kthi SBScriptKTHI +#define Lana SBScriptLANA +#define Laoo SBScriptLAOO +#define Latn SBScriptLATN +#define Lepc SBScriptLEPC +#define Limb SBScriptLIMB +#define Lina SBScriptLINA +#define Linb SBScriptLINB +#define Lisu SBScriptLISU +#define Lyci SBScriptLYCI +#define Lydi SBScriptLYDI +#define Mahj SBScriptMAHJ +#define Maka SBScriptMAKA +#define Mand SBScriptMAND +#define Mani SBScriptMANI +#define Marc SBScriptMARC +#define Medf SBScriptMEDF +#define Mend SBScriptMEND +#define Merc SBScriptMERC +#define Mero SBScriptMERO +#define Mlym SBScriptMLYM +#define Modi SBScriptMODI +#define Mong SBScriptMONG +#define Mroo SBScriptMROO +#define Mtei SBScriptMTEI +#define Mult SBScriptMULT +#define Mymr SBScriptMYMR +#define Nagm SBScriptNAGM +#define Nand SBScriptNAND +#define Narb SBScriptNARB +#define Nbat SBScriptNBAT +#define Newa SBScriptNEWA +#define Nkoo SBScriptNKOO +#define Nshu SBScriptNSHU +#define Ogam SBScriptOGAM +#define Olck SBScriptOLCK +#define Onao SBScriptONAO +#define Orkh SBScriptORKH +#define Orya SBScriptORYA +#define Osge SBScriptOSGE +#define Osma SBScriptOSMA +#define Ougr SBScriptOUGR +#define Palm SBScriptPALM +#define Pauc SBScriptPAUC +#define Perm SBScriptPERM +#define Phag SBScriptPHAG +#define Phli SBScriptPHLI +#define Phlp SBScriptPHLP +#define Phnx SBScriptPHNX +#define Plrd SBScriptPLRD +#define Prti SBScriptPRTI +#define Rjng SBScriptRJNG +#define Rohg SBScriptROHG +#define Runr SBScriptRUNR +#define Samr SBScriptSAMR +#define Sarb SBScriptSARB +#define Saur SBScriptSAUR +#define Sgnw SBScriptSGNW +#define Shaw SBScriptSHAW +#define Shrd SBScriptSHRD +#define Sidd SBScriptSIDD +#define Sidt SBScriptSIDT +#define Sind SBScriptSIND +#define Sinh SBScriptSINH +#define Sogd SBScriptSOGD +#define Sogo SBScriptSOGO +#define Sora SBScriptSORA +#define Soyo SBScriptSOYO +#define Sund SBScriptSUND +#define Sunu SBScriptSUNU +#define Sylo SBScriptSYLO +#define Syrc SBScriptSYRC +#define Tagb SBScriptTAGB +#define Takr SBScriptTAKR +#define Tale SBScriptTALE +#define Talu SBScriptTALU +#define Taml SBScriptTAML +#define Tang SBScriptTANG +#define Tavt SBScriptTAVT +#define Tayo SBScriptTAYO +#define Telu SBScriptTELU +#define Tfng SBScriptTFNG +#define Tglg SBScriptTGLG +#define Thaa SBScriptTHAA +#define Thai SBScriptTHAI +#define Tibt SBScriptTIBT +#define Tirh SBScriptTIRH +#define Tnsa SBScriptTNSA +#define Todr SBScriptTODR +#define Tols SBScriptTOLS +#define Toto SBScriptTOTO +#define Tutg SBScriptTUTG +#define Ugar SBScriptUGAR +#define Vaii SBScriptVAII +#define Vith SBScriptVITH +#define Wara SBScriptWARA +#define Wcho SBScriptWCHO +#define Xpeo SBScriptXPEO +#define Xsux SBScriptXSUX +#define Yezi SBScriptYEZI +#define Yiii SBScriptYIII +#define Zanb SBScriptZANB +#define Zinh SBScriptZINH +#define Zyyy SBScriptZYYY +#define Zzzz SBScriptZZZZ + +static const SBUInt8 PrimaryScriptData[11328] = { +/* DATA_BLOCK: -- 0x0000..0x000F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0010..0x001F -- */ + Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0020..0x002F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0030..0x003F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0040..0x004F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0050..0x005F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0060..0x006F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0070..0x007F -- */ + Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Bopo, Bopo, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0080..0x008F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x0090..0x009F -- */ + Grek, Grek, Grek, Grek, Zyyy, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Zyyy, Grek, +/* DATA_BLOCK: -- 0x00A0..0x00AF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Grek, Zyyy, Grek, Zyyy, Grek, Grek, Grek, Zzzz, Grek, Zzzz, Grek, Grek, +/* DATA_BLOCK: -- 0x00B0..0x00BF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x00C0..0x00CF -- */ + Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x00D0..0x00DF -- */ + Grek, Grek, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x00E0..0x00EF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x00F0..0x00FF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Zinh, Zinh, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x0100..0x010F -- */ + Zzzz, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0110..0x011F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0120..0x012F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Armn, Armn, Armn, Armn, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0130..0x013F -- */ + Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Armn, Armn, Armn, +/* DATA_BLOCK: -- 0x0140..0x014F -- */ + Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x0150..0x015F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x0160..0x016F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0170..0x017F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Hebr, +/* DATA_BLOCK: -- 0x0180..0x018F -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0190..0x019F -- */ + Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01A0..0x01AF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, Arab, Zyyy, +/* DATA_BLOCK: -- 0x01B0..0x01BF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01C0..0x01CF -- */ + Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x01D0..0x01DF -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01E0..0x01EF -- */ + Zinh, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x01F0..0x01FF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Arab, Arab, +/* DATA_BLOCK: -- 0x0200..0x020F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Syrc, +/* DATA_BLOCK: -- 0x0210..0x021F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, +/* DATA_BLOCK: -- 0x0220..0x022F -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Zzzz, Syrc, Syrc, Syrc, +/* DATA_BLOCK: -- 0x0230..0x023F -- */ + Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, Thaa, +/* DATA_BLOCK: -- 0x0240..0x024F -- */ + Thaa, Thaa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0250..0x025F -- */ + Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, +/* DATA_BLOCK: -- 0x0260..0x026F -- */ + Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Nkoo, Zzzz, Zzzz, Nkoo, Nkoo, Nkoo, +/* DATA_BLOCK: -- 0x0270..0x027F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, +/* DATA_BLOCK: -- 0x0280..0x028F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0290..0x029F -- */ + Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Samr, Zzzz, +/* DATA_BLOCK: -- 0x02A0..0x02AF -- */ + Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, +/* DATA_BLOCK: -- 0x02B0..0x02BF -- */ + Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Mand, Zzzz, Zzzz, Mand, Zzzz, +/* DATA_BLOCK: -- 0x02C0..0x02CF -- */ + Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Syrc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x02D0..0x02DF -- */ + Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x02E0..0x02EF -- */ + Arab, Arab, Zyyy, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x02F0..0x02FF -- */ + Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0300..0x030F -- */ + Deva, Zinh, Zinh, Zinh, Zinh, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0310..0x031F -- */ + Deva, Deva, Deva, Deva, Zyyy, Zyyy, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, +/* DATA_BLOCK: -- 0x0320..0x032F -- */ + Beng, Beng, Beng, Beng, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, +/* DATA_BLOCK: -- 0x0330..0x033F -- */ + Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0340..0x034F -- */ + Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0350..0x035F -- */ + Beng, Zzzz, Beng, Zzzz, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0360..0x036F -- */ + Beng, Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Zzzz, +/* DATA_BLOCK: -- 0x0370..0x037F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Beng, Zzzz, Zzzz, Zzzz, Zzzz, Beng, Beng, Zzzz, Beng, +/* DATA_BLOCK: -- 0x0380..0x038F -- */ + Beng, Beng, Beng, Beng, Zzzz, Zzzz, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, +/* DATA_BLOCK: -- 0x0390..0x039F -- */ + Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Beng, Zzzz, +/* DATA_BLOCK: -- 0x03A0..0x03AF -- */ + Zzzz, Guru, Guru, Guru, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Guru, +/* DATA_BLOCK: -- 0x03B0..0x03BF -- */ + Guru, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x03C0..0x03CF -- */ + Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x03D0..0x03DF -- */ + Guru, Zzzz, Guru, Guru, Zzzz, Guru, Guru, Zzzz, Guru, Guru, Zzzz, Zzzz, Guru, Zzzz, Guru, Guru, +/* DATA_BLOCK: -- 0x03E0..0x03EF -- */ + Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Zzzz, Zzzz, Guru, Guru, Guru, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x03F0..0x03FF -- */ + Zzzz, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Zzzz, Guru, Zzzz, +/* DATA_BLOCK: -- 0x0400..0x040F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, Guru, +/* DATA_BLOCK: -- 0x0410..0x041F -- */ + Guru, Guru, Guru, Guru, Guru, Guru, Guru, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0420..0x042F -- */ + Zzzz, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, +/* DATA_BLOCK: -- 0x0430..0x043F -- */ + Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0440..0x044F -- */ + Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0450..0x045F -- */ + Gujr, Zzzz, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0460..0x046F -- */ + Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Zzzz, Gujr, Gujr, Gujr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0470..0x047F -- */ + Gujr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0480..0x048F -- */ + Gujr, Gujr, Gujr, Gujr, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x0490..0x049F -- */ + Gujr, Gujr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, Gujr, +/* DATA_BLOCK: -- 0x04A0..0x04AF -- */ + Zzzz, Orya, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, +/* DATA_BLOCK: -- 0x04B0..0x04BF -- */ + Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04C0..0x04CF -- */ + Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04D0..0x04DF -- */ + Orya, Zzzz, Orya, Orya, Zzzz, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x04E0..0x04EF -- */ + Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x04F0..0x04FF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Orya, Orya, Orya, Zzzz, Zzzz, Zzzz, Zzzz, Orya, Orya, Zzzz, Orya, +/* DATA_BLOCK: -- 0x0500..0x050F -- */ + Orya, Orya, Orya, Orya, Zzzz, Zzzz, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, +/* DATA_BLOCK: -- 0x0510..0x051F -- */ + Orya, Orya, Orya, Orya, Orya, Orya, Orya, Orya, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0520..0x052F -- */ + Zzzz, Zzzz, Taml, Taml, Zzzz, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0530..0x053F -- */ + Taml, Zzzz, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Zzzz, Taml, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0540..0x054F -- */ + Zzzz, Zzzz, Zzzz, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0550..0x055F -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Taml, +/* DATA_BLOCK: -- 0x0560..0x056F -- */ + Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Zzzz, Taml, Taml, Taml, Taml, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0570..0x057F -- */ + Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0580..0x058F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, +/* DATA_BLOCK: -- 0x0590..0x059F -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x05A0..0x05AF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, +/* DATA_BLOCK: -- 0x05B0..0x05BF -- */ + Telu, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05C0..0x05CF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05D0..0x05DF -- */ + Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Zzzz, Zzzz, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x05E0..0x05EF -- */ + Telu, Telu, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Zzzz, Telu, Telu, Telu, Telu, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x05F0..0x05FF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Telu, Telu, Zzzz, Telu, Telu, Telu, Zzzz, Telu, Telu, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0600..0x060F -- */ + Telu, Telu, Telu, Telu, Zzzz, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x0610..0x061F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, Telu, +/* DATA_BLOCK: -- 0x0620..0x062F -- */ + Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, +/* DATA_BLOCK: -- 0x0630..0x063F -- */ + Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0640..0x064F -- */ + Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0650..0x065F -- */ + Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Knda, Zzzz, Zzzz, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0660..0x066F -- */ + Knda, Knda, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Zzzz, Knda, Knda, Knda, Knda, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0670..0x067F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Knda, Knda, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Knda, Knda, Knda, Zzzz, +/* DATA_BLOCK: -- 0x0680..0x068F -- */ + Knda, Knda, Knda, Knda, Zzzz, Zzzz, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, Knda, +/* DATA_BLOCK: -- 0x0690..0x069F -- */ + Zzzz, Knda, Knda, Knda, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x06A0..0x06AF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06B0..0x06BF -- */ + Mlym, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06C0..0x06CF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06D0..0x06DF -- */ + Mlym, Mlym, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, Mlym, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06E0..0x06EF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x06F0..0x06FF -- */ + Mlym, Mlym, Mlym, Mlym, Zzzz, Zzzz, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, Mlym, +/* DATA_BLOCK: -- 0x0700..0x070F -- */ + Zzzz, Sinh, Sinh, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0710..0x071F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0720..0x072F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0730..0x073F -- */ + Sinh, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Sinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0740..0x074F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Sinh, +/* DATA_BLOCK: -- 0x0750..0x075F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Sinh, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0760..0x076F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x0770..0x077F -- */ + Zzzz, Zzzz, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0780..0x078F -- */ + Zzzz, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, +/* DATA_BLOCK: -- 0x0790..0x079F -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, +/* DATA_BLOCK: -- 0x07A0..0x07AF -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x07B0..0x07BF -- */ + Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Thai, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x07C0..0x07CF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x07D0..0x07DF -- */ + Zzzz, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x07E0..0x07EF -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x07F0..0x07FF -- */ + Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x0800..0x080F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0810..0x081F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Laoo, Zzzz, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, +/* DATA_BLOCK: -- 0x0820..0x082F -- */ + Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Laoo, Zzzz, Zzzz, Laoo, Laoo, Laoo, Laoo, +/* DATA_BLOCK: -- 0x0830..0x083F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0840..0x084F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0850..0x085F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0860..0x086F -- */ + Zzzz, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0870..0x087F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Tibt, Zzzz, Tibt, Tibt, +/* DATA_BLOCK: -- 0x0880..0x088F -- */ + Tibt, Tibt, Tibt, Tibt, Tibt, Zyyy, Zyyy, Zyyy, Zyyy, Tibt, Tibt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0890..0x089F -- */ + Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, +/* DATA_BLOCK: -- 0x08A0..0x08AF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x08B0..0x08BF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Zzzz, Geor, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Geor, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x08C0..0x08CF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Zyyy, Geor, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x08D0..0x08DF -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x08E0..0x08EF -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x08F0..0x08FF -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0900..0x090F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0910..0x091F -- */ + Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x0920..0x092F -- */ + Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0930..0x093F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0940..0x094F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, +/* DATA_BLOCK: -- 0x0950..0x095F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0960..0x096F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0970..0x097F -- */ + Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, Cher, +/* DATA_BLOCK: -- 0x0980..0x098F -- */ + Cher, Cher, Cher, Cher, Cher, Cher, Zzzz, Zzzz, Cher, Cher, Cher, Cher, Cher, Cher, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0990..0x099F -- */ + Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, Cans, +/* DATA_BLOCK: -- 0x09A0..0x09AF -- */ + Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, +/* DATA_BLOCK: -- 0x09B0..0x09BF -- */ + Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Ogam, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x09C0..0x09CF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, +/* DATA_BLOCK: -- 0x09D0..0x09DF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Zyyy, Zyyy, Zyyy, Runr, Runr, +/* DATA_BLOCK: -- 0x09E0..0x09EF -- */ + Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Runr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x09F0..0x09FF -- */ + Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, +/* DATA_BLOCK: -- 0x0A00..0x0A0F -- */ + Tglg, Tglg, Tglg, Tglg, Tglg, Tglg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tglg, +/* DATA_BLOCK: -- 0x0A10..0x0A1F -- */ + Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, Hano, +/* DATA_BLOCK: -- 0x0A20..0x0A2F -- */ + Hano, Hano, Hano, Hano, Hano, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A30..0x0A3F -- */ + Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, Buhd, +/* DATA_BLOCK: -- 0x0A40..0x0A4F -- */ + Buhd, Buhd, Buhd, Buhd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A50..0x0A5F -- */ + Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Tagb, Zzzz, Tagb, Tagb, +/* DATA_BLOCK: -- 0x0A60..0x0A6F -- */ + Tagb, Zzzz, Tagb, Tagb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A70..0x0A7F -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, +/* DATA_BLOCK: -- 0x0A80..0x0A8F -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0A90..0x0A9F -- */ + Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Khmr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AA0..0x0AAF -- */ + Mong, Mong, Zyyy, Zyyy, Mong, Zyyy, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, +/* DATA_BLOCK: -- 0x0AB0..0x0ABF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AC0..0x0ACF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, +/* DATA_BLOCK: -- 0x0AD0..0x0ADF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AE0..0x0AEF -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0AF0..0x0AFF -- */ + Cans, Cans, Cans, Cans, Cans, Cans, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B00..0x0B0F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, +/* DATA_BLOCK: -- 0x0B10..0x0B1F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Zzzz, +/* DATA_BLOCK: -- 0x0B20..0x0B2F -- */ + Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B30..0x0B3F -- */ + Limb, Zzzz, Zzzz, Zzzz, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, Limb, +/* DATA_BLOCK: -- 0x0B40..0x0B4F -- */ + Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, +/* DATA_BLOCK: -- 0x0B50..0x0B5F -- */ + Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Tale, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B60..0x0B6F -- */ + Tale, Tale, Tale, Tale, Tale, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B70..0x0B7F -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, +/* DATA_BLOCK: -- 0x0B80..0x0B8F -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0B90..0x0B9F -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0BA0..0x0BAF -- */ + Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Talu, Zzzz, Zzzz, Zzzz, Talu, Talu, +/* DATA_BLOCK: -- 0x0BB0..0x0BBF -- */ + Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, +/* DATA_BLOCK: -- 0x0BC0..0x0BCF -- */ + Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Bugi, Zzzz, Zzzz, Bugi, Bugi, +/* DATA_BLOCK: -- 0x0BD0..0x0BDF -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, +/* DATA_BLOCK: -- 0x0BE0..0x0BEF -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, +/* DATA_BLOCK: -- 0x0BF0..0x0BFF -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, Lana, +/* DATA_BLOCK: -- 0x0C00..0x0C0F -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C10..0x0C1F -- */ + Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Lana, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C20..0x0C2F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C30..0x0C3F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0C40..0x0C4F -- */ + Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, +/* DATA_BLOCK: -- 0x0C50..0x0C5F -- */ + Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Bali, Zzzz, Bali, Bali, +/* DATA_BLOCK: -- 0x0C60..0x0C6F -- */ + Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, +/* DATA_BLOCK: -- 0x0C70..0x0C7F -- */ + Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, Batk, +/* DATA_BLOCK: -- 0x0C80..0x0C8F -- */ + Batk, Batk, Batk, Batk, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Batk, Batk, Batk, Batk, +/* DATA_BLOCK: -- 0x0C90..0x0C9F -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CA0..0x0CAF -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Zzzz, Zzzz, Zzzz, Lepc, Lepc, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CB0..0x0CBF -- */ + Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Lepc, Zzzz, Zzzz, Zzzz, Lepc, Lepc, Lepc, +/* DATA_BLOCK: -- 0x0CC0..0x0CCF -- */ + Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, Olck, +/* DATA_BLOCK: -- 0x0CD0..0x0CDF -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0CE0..0x0CEF -- */ + Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Geor, Zzzz, Zzzz, Geor, Geor, Geor, +/* DATA_BLOCK: -- 0x0CF0..0x0CFF -- */ + Sund, Sund, Sund, Sund, Sund, Sund, Sund, Sund, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0D00..0x0D0F -- */ + Zinh, Zinh, Zinh, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x0D10..0x0D1F -- */ + Zinh, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0D20..0x0D2F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0D30..0x0D3F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Grek, Grek, Grek, Grek, Grek, Cyrl, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D40..0x0D4F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0D50..0x0D5F -- */ + Grek, Grek, Latn, Latn, Latn, Latn, Grek, Grek, Grek, Grek, Grek, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D60..0x0D6F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Cyrl, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x0D70..0x0D7F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Grek, +/* DATA_BLOCK: -- 0x0D80..0x0D8F -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0D90..0x0D9F -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Zzzz, Grek, Zzzz, Grek, Zzzz, Grek, +/* DATA_BLOCK: -- 0x0DA0..0x0DAF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0DB0..0x0DBF -- */ + Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0DC0..0x0DCF -- */ + Grek, Grek, Grek, Grek, Zzzz, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, +/* DATA_BLOCK: -- 0x0DD0..0x0DDF -- */ + Zzzz, Zzzz, Grek, Grek, Grek, Zzzz, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, +/* DATA_BLOCK: -- 0x0DE0..0x0DEF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0DF0..0x0DFF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E00..0x0E0F -- */ + Zyyy, Latn, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, +/* DATA_BLOCK: -- 0x0E10..0x0E1F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x0E20..0x0E2F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E30..0x0E3F -- */ + Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E40..0x0E4F -- */ + Zinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E50..0x0E5F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Grek, Zyyy, Zyyy, Zyyy, Latn, Latn, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E60..0x0E6F -- */ + Zyyy, Zyyy, Latn, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0E70..0x0E7F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Latn, Zyyy, +/* DATA_BLOCK: -- 0x0E80..0x0E8F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0E90..0x0E9F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0EA0..0x0EAF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0EB0..0x0EBF -- */ + Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, Brai, +/* DATA_BLOCK: -- 0x0EC0..0x0ECF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0ED0..0x0EDF -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x0EE0..0x0EEF -- */ + Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x0EF0..0x0EFF -- */ + Copt, Copt, Copt, Copt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Copt, Copt, Copt, Copt, Copt, Copt, Copt, +/* DATA_BLOCK: -- 0x0F00..0x0F0F -- */ + Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, +/* DATA_BLOCK: -- 0x0F10..0x0F1F -- */ + Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Tfng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tfng, +/* DATA_BLOCK: -- 0x0F20..0x0F2F -- */ + Tfng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tfng, +/* DATA_BLOCK: -- 0x0F30..0x0F3F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0F40..0x0F4F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x0F50..0x0F5F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0F60..0x0F6F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, +/* DATA_BLOCK: -- 0x0F70..0x0F7F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Hani, Hani, Hani, Hani, Hani, +/* DATA_BLOCK: -- 0x0F80..0x0F8F -- */ + Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0F90..0x0F9F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x0FA0..0x0FAF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Hani, Zyyy, Hani, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0FB0..0x0FBF -- */ + Zyyy, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zinh, Zinh, Zinh, Zinh, Hang, Hang, +/* DATA_BLOCK: -- 0x0FC0..0x0FCF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Hani, Hani, Hani, Hani, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x0FD0..0x0FDF -- */ + Zzzz, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x0FE0..0x0FEF -- */ + Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x0FF0..0x0FFF -- */ + Hira, Hira, Hira, Hira, Hira, Hira, Hira, Zzzz, Zzzz, Zinh, Zinh, Zyyy, Zyyy, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x1000..0x100F -- */ + Zyyy, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1010..0x101F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1020..0x102F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1030..0x103F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, +/* DATA_BLOCK: -- 0x1040..0x104F -- */ + Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, Bopo, +/* DATA_BLOCK: -- 0x1050..0x105F -- */ + Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x1060..0x106F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, +/* DATA_BLOCK: -- 0x1070..0x107F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x1080..0x108F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zyyy, +/* DATA_BLOCK: -- 0x1090..0x109F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, +/* DATA_BLOCK: -- 0x10A0..0x10AF -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x10B0..0x10BF -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, +/* DATA_BLOCK: -- 0x10C0..0x10CF -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x10D0..0x10DF -- */ + Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Yiii, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x10E0..0x10EF -- */ + Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, Lisu, +/* DATA_BLOCK: -- 0x10F0..0x10FF -- */ + Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, +/* DATA_BLOCK: -- 0x1100..0x110F -- */ + Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Vaii, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1110..0x111F -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, +/* DATA_BLOCK: -- 0x1120..0x112F -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1130..0x113F -- */ + Zyyy, Zyyy, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1140..0x114F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zyyy, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1150..0x115F -- */ + Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1160..0x116F -- */ + Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, +/* DATA_BLOCK: -- 0x1170..0x117F -- */ + Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Sylo, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1180..0x118F -- */ + Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, +/* DATA_BLOCK: -- 0x1190..0x119F -- */ + Phag, Phag, Phag, Phag, Phag, Phag, Phag, Phag, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x11A0..0x11AF -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, +/* DATA_BLOCK: -- 0x11B0..0x11BF -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Saur, Saur, +/* DATA_BLOCK: -- 0x11C0..0x11CF -- */ + Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Saur, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x11D0..0x11DF -- */ + Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, +/* DATA_BLOCK: -- 0x11E0..0x11EF -- */ + Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Kali, Zyyy, Kali, +/* DATA_BLOCK: -- 0x11F0..0x11FF -- */ + Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, Rjng, +/* DATA_BLOCK: -- 0x1200..0x120F -- */ + Rjng, Rjng, Rjng, Rjng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Rjng, +/* DATA_BLOCK: -- 0x1210..0x121F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1220..0x122F -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, +/* DATA_BLOCK: -- 0x1230..0x123F -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x1240..0x124F -- */ + Java, Java, Java, Java, Java, Java, Java, Java, Java, Java, Zzzz, Zzzz, Zzzz, Zzzz, Java, Java, +/* DATA_BLOCK: -- 0x1250..0x125F -- */ + Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Mymr, Zzzz, +/* DATA_BLOCK: -- 0x1260..0x126F -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, +/* DATA_BLOCK: -- 0x1270..0x127F -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1280..0x128F -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1290..0x129F -- */ + Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Cham, Zzzz, Zzzz, Cham, Cham, Cham, Cham, +/* DATA_BLOCK: -- 0x12A0..0x12AF -- */ + Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, Tavt, +/* DATA_BLOCK: -- 0x12B0..0x12BF -- */ + Tavt, Tavt, Tavt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x12C0..0x12CF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tavt, Tavt, Tavt, Tavt, Tavt, +/* DATA_BLOCK: -- 0x12D0..0x12DF -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, +/* DATA_BLOCK: -- 0x12E0..0x12EF -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x12F0..0x12FF -- */ + Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x1300..0x130F -- */ + Zzzz, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1310..0x131F -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zyyy, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x1320..0x132F -- */ + Latn, Latn, Latn, Latn, Latn, Grek, Latn, Latn, Latn, Latn, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1330..0x133F -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1340..0x134F -- */ + Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Mtei, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1350..0x135F -- */ + Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1360..0x136F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x1370..0x137F -- */ + Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1380..0x138F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1390..0x139F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13A0..0x13AF -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x13B0..0x13BF -- */ + Zzzz, Zzzz, Zzzz, Armn, Armn, Armn, Armn, Armn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x13C0..0x13CF -- */ + Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Zzzz, Hebr, Zzzz, +/* DATA_BLOCK: -- 0x13D0..0x13DF -- */ + Hebr, Hebr, Zzzz, Hebr, Hebr, Zzzz, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, Hebr, +/* DATA_BLOCK: -- 0x13E0..0x13EF -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x13F0..0x13FF -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Cyrl, Cyrl, +/* DATA_BLOCK: -- 0x1400..0x140F -- */ + Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1410..0x141F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1420..0x142F -- */ + Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x1430..0x143F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x1440..0x144F -- */ + Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1450..0x145F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, +/* DATA_BLOCK: -- 0x1460..0x146F -- */ + Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1470..0x147F -- */ + Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, +/* DATA_BLOCK: -- 0x1480..0x148F -- */ + Zzzz, Zzzz, Hang, Hang, Hang, Hang, Hang, Hang, Zzzz, Zzzz, Hang, Hang, Hang, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1490..0x149F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x14A0..0x14AF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x14B0..0x14BF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x14C0..0x14CF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x14D0..0x14DF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, +/* DATA_BLOCK: -- 0x14E0..0x14EF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Linb, Linb, Zzzz, Linb, +/* DATA_BLOCK: -- 0x14F0..0x14FF -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1500..0x150F -- */ + Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Linb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1510..0x151F -- */ + Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1520..0x152F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x1530..0x153F -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, +/* DATA_BLOCK: -- 0x1540..0x154F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1550..0x155F -- */ + Grek, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1560..0x156F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1570..0x157F -- */ + Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, +/* DATA_BLOCK: -- 0x1580..0x158F -- */ + Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Lyci, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1590..0x159F -- */ + Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, Cari, +/* DATA_BLOCK: -- 0x15A0..0x15AF -- */ + Cari, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x15B0..0x15BF -- */ + Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x15C0..0x15CF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x15D0..0x15DF -- */ + Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, Ital, +/* DATA_BLOCK: -- 0x15E0..0x15EF -- */ + Ital, Ital, Ital, Ital, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Ital, Ital, Ital, +/* DATA_BLOCK: -- 0x15F0..0x15FF -- */ + Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, +/* DATA_BLOCK: -- 0x1600..0x160F -- */ + Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Goth, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1610..0x161F -- */ + Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, +/* DATA_BLOCK: -- 0x1620..0x162F -- */ + Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Perm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1630..0x163F -- */ + Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, +/* DATA_BLOCK: -- 0x1640..0x164F -- */ + Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Ugar, Zzzz, Ugar, +/* DATA_BLOCK: -- 0x1650..0x165F -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, +/* DATA_BLOCK: -- 0x1660..0x166F -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Zzzz, Zzzz, Zzzz, Zzzz, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, +/* DATA_BLOCK: -- 0x1670..0x167F -- */ + Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Xpeo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1680..0x168F -- */ + Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, Dsrt, +/* DATA_BLOCK: -- 0x1690..0x169F -- */ + Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, Shaw, +/* DATA_BLOCK: -- 0x16A0..0x16AF -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, +/* DATA_BLOCK: -- 0x16B0..0x16BF -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x16C0..0x16CF -- */ + Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Osma, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x16D0..0x16DF -- */ + Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, +/* DATA_BLOCK: -- 0x16E0..0x16EF -- */ + Osge, Osge, Osge, Osge, Zzzz, Zzzz, Zzzz, Zzzz, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, +/* DATA_BLOCK: -- 0x16F0..0x16FF -- */ + Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Osge, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1700..0x170F -- */ + Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, +/* DATA_BLOCK: -- 0x1710..0x171F -- */ + Elba, Elba, Elba, Elba, Elba, Elba, Elba, Elba, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1720..0x172F -- */ + Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, Aghb, +/* DATA_BLOCK: -- 0x1730..0x173F -- */ + Aghb, Aghb, Aghb, Aghb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Aghb, +/* DATA_BLOCK: -- 0x1740..0x174F -- */ + Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x1750..0x175F -- */ + Vith, Vith, Vith, Zzzz, Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x1760..0x176F -- */ + Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Vith, +/* DATA_BLOCK: -- 0x1770..0x177F -- */ + Vith, Vith, Zzzz, Vith, Vith, Vith, Vith, Vith, Vith, Vith, Zzzz, Vith, Vith, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1780..0x178F -- */ + Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, Todr, +/* DATA_BLOCK: -- 0x1790..0x179F -- */ + Todr, Todr, Todr, Todr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x17A0..0x17AF -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, +/* DATA_BLOCK: -- 0x17B0..0x17BF -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x17C0..0x17CF -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x17D0..0x17DF -- */ + Lina, Lina, Lina, Lina, Lina, Lina, Lina, Lina, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x17E0..0x17EF -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, +/* DATA_BLOCK: -- 0x17F0..0x17FF -- */ + Latn, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1800..0x180F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Zzzz, Zzzz, Cprt, Zzzz, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, +/* DATA_BLOCK: -- 0x1810..0x181F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, +/* DATA_BLOCK: -- 0x1820..0x182F -- */ + Cprt, Cprt, Cprt, Cprt, Cprt, Cprt, Zzzz, Cprt, Cprt, Zzzz, Zzzz, Zzzz, Cprt, Zzzz, Zzzz, Cprt, +/* DATA_BLOCK: -- 0x1830..0x183F -- */ + Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, +/* DATA_BLOCK: -- 0x1840..0x184F -- */ + Armi, Armi, Armi, Armi, Armi, Armi, Zzzz, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, Armi, +/* DATA_BLOCK: -- 0x1850..0x185F -- */ + Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, Palm, +/* DATA_BLOCK: -- 0x1860..0x186F -- */ + Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, +/* DATA_BLOCK: -- 0x1870..0x187F -- */ + Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Zzzz, +/* DATA_BLOCK: -- 0x1880..0x188F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, Nbat, +/* DATA_BLOCK: -- 0x1890..0x189F -- */ + Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, Hatr, +/* DATA_BLOCK: -- 0x18A0..0x18AF -- */ + Hatr, Hatr, Hatr, Zzzz, Hatr, Hatr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hatr, Hatr, Hatr, Hatr, Hatr, +/* DATA_BLOCK: -- 0x18B0..0x18BF -- */ + Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, +/* DATA_BLOCK: -- 0x18C0..0x18CF -- */ + Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Phnx, Zzzz, Zzzz, Zzzz, Phnx, +/* DATA_BLOCK: -- 0x18D0..0x18DF -- */ + Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, +/* DATA_BLOCK: -- 0x18E0..0x18EF -- */ + Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Lydi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Lydi, +/* DATA_BLOCK: -- 0x18F0..0x18FF -- */ + Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, +/* DATA_BLOCK: -- 0x1900..0x190F -- */ + Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Sidt, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1910..0x191F -- */ + Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, Mero, +/* DATA_BLOCK: -- 0x1920..0x192F -- */ + Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x1930..0x193F -- */ + Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Zzzz, Zzzz, Zzzz, Zzzz, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x1940..0x194F -- */ + Zzzz, Zzzz, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, Merc, +/* DATA_BLOCK: -- 0x1950..0x195F -- */ + Khar, Khar, Khar, Khar, Zzzz, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x1960..0x196F -- */ + Khar, Khar, Khar, Khar, Zzzz, Khar, Khar, Khar, Zzzz, Khar, Khar, Khar, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x1970..0x197F -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, +/* DATA_BLOCK: -- 0x1980..0x198F -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Zzzz, Zzzz, Khar, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Khar, +/* DATA_BLOCK: -- 0x1990..0x199F -- */ + Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Khar, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x19A0..0x19AF -- */ + Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, Sarb, +/* DATA_BLOCK: -- 0x19B0..0x19BF -- */ + Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, Narb, +/* DATA_BLOCK: -- 0x19C0..0x19CF -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, Mani, +/* DATA_BLOCK: -- 0x19D0..0x19DF -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Zzzz, Zzzz, Zzzz, Zzzz, Mani, Mani, Mani, Mani, Mani, +/* DATA_BLOCK: -- 0x19E0..0x19EF -- */ + Mani, Mani, Mani, Mani, Mani, Mani, Mani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x19F0..0x19FF -- */ + Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, Avst, +/* DATA_BLOCK: -- 0x1A00..0x1A0F -- */ + Avst, Avst, Avst, Avst, Avst, Avst, Zzzz, Zzzz, Zzzz, Avst, Avst, Avst, Avst, Avst, Avst, Avst, +/* DATA_BLOCK: -- 0x1A10..0x1A1F -- */ + Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, +/* DATA_BLOCK: -- 0x1A20..0x1A2F -- */ + Prti, Prti, Prti, Prti, Prti, Prti, Zzzz, Zzzz, Prti, Prti, Prti, Prti, Prti, Prti, Prti, Prti, +/* DATA_BLOCK: -- 0x1A30..0x1A3F -- */ + Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, +/* DATA_BLOCK: -- 0x1A40..0x1A4F -- */ + Phli, Phli, Phli, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phli, Phli, Phli, Phli, Phli, Phli, Phli, Phli, +/* DATA_BLOCK: -- 0x1A50..0x1A5F -- */ + Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, +/* DATA_BLOCK: -- 0x1A60..0x1A6F -- */ + Phlp, Phlp, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phlp, Phlp, Phlp, Phlp, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1A70..0x1A7F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, Phlp, +/* DATA_BLOCK: -- 0x1A80..0x1A8F -- */ + Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, +/* DATA_BLOCK: -- 0x1A90..0x1A9F -- */ + Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Orkh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1AA0..0x1AAF -- */ + Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, Hung, +/* DATA_BLOCK: -- 0x1AB0..0x1ABF -- */ + Hung, Hung, Hung, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1AC0..0x1ACF -- */ + Hung, Hung, Hung, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hung, Hung, Hung, Hung, Hung, Hung, +/* DATA_BLOCK: -- 0x1AD0..0x1ADF -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, +/* DATA_BLOCK: -- 0x1AE0..0x1AEF -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1AF0..0x1AFF -- */ + Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Rohg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B00..0x1B0F -- */ + Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, Gara, +/* DATA_BLOCK: -- 0x1B10..0x1B1F -- */ + Gara, Gara, Gara, Gara, Gara, Gara, Zzzz, Zzzz, Zzzz, Gara, Gara, Gara, Gara, Gara, Gara, Gara, +/* DATA_BLOCK: -- 0x1B20..0x1B2F -- */ + Gara, Gara, Gara, Gara, Gara, Gara, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gara, Gara, +/* DATA_BLOCK: -- 0x1B30..0x1B3F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, +/* DATA_BLOCK: -- 0x1B40..0x1B4F -- */ + Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, +/* DATA_BLOCK: -- 0x1B50..0x1B5F -- */ + Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Yezi, Zzzz, Yezi, Yezi, Yezi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B60..0x1B6F -- */ + Yezi, Yezi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B70..0x1B7F -- */ + Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B80..0x1B8F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1B90..0x1B9F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x1BA0..0x1BAF -- */ + Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, +/* DATA_BLOCK: -- 0x1BB0..0x1BBF -- */ + Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Sogo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1BC0..0x1BCF -- */ + Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, +/* DATA_BLOCK: -- 0x1BD0..0x1BDF -- */ + Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Sogd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1BE0..0x1BEF -- */ + Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, +/* DATA_BLOCK: -- 0x1BF0..0x1BFF -- */ + Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Ougr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C00..0x1C0F -- */ + Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, +/* DATA_BLOCK: -- 0x1C10..0x1C1F -- */ + Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Chrs, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C20..0x1C2F -- */ + Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, Elym, +/* DATA_BLOCK: -- 0x1C30..0x1C3F -- */ + Elym, Elym, Elym, Elym, Elym, Elym, Elym, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C40..0x1C4F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, +/* DATA_BLOCK: -- 0x1C50..0x1C5F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1C60..0x1C6F -- */ + Zzzz, Zzzz, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, Brah, +/* DATA_BLOCK: -- 0x1C70..0x1C7F -- */ + Brah, Brah, Brah, Brah, Brah, Brah, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Brah, +/* DATA_BLOCK: -- 0x1C80..0x1C8F -- */ + Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, Kthi, +/* DATA_BLOCK: -- 0x1C90..0x1C9F -- */ + Kthi, Kthi, Kthi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Kthi, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CA0..0x1CAF -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, +/* DATA_BLOCK: -- 0x1CB0..0x1CBF -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CC0..0x1CCF -- */ + Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Sora, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1CD0..0x1CDF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, +/* DATA_BLOCK: -- 0x1CE0..0x1CEF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Zzzz, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, +/* DATA_BLOCK: -- 0x1CF0..0x1CFF -- */ + Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Cakm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D00..0x1D0F -- */ + Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, +/* DATA_BLOCK: -- 0x1D10..0x1D1F -- */ + Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Mahj, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D20..0x1D2F -- */ + Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, +/* DATA_BLOCK: -- 0x1D30..0x1D3F -- */ + Zzzz, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, Sinh, +/* DATA_BLOCK: -- 0x1D40..0x1D4F -- */ + Sinh, Sinh, Sinh, Sinh, Sinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D50..0x1D5F -- */ + Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, +/* DATA_BLOCK: -- 0x1D60..0x1D6F -- */ + Khoj, Khoj, Zzzz, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, Khoj, +/* DATA_BLOCK: -- 0x1D70..0x1D7F -- */ + Khoj, Khoj, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1D80..0x1D8F -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Mult, Zzzz, Mult, Mult, Mult, Mult, Zzzz, Mult, +/* DATA_BLOCK: -- 0x1D90..0x1D9F -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Mult, +/* DATA_BLOCK: -- 0x1DA0..0x1DAF -- */ + Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Mult, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1DB0..0x1DBF -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, +/* DATA_BLOCK: -- 0x1DC0..0x1DCF -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1DD0..0x1DDF -- */ + Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Sind, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1DE0..0x1DEF -- */ + Gran, Gran, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, +/* DATA_BLOCK: -- 0x1DF0..0x1DFF -- */ + Gran, Zzzz, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E00..0x1E0F -- */ + Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E10..0x1E1F -- */ + Gran, Zzzz, Gran, Gran, Zzzz, Gran, Gran, Gran, Gran, Gran, Zzzz, Zinh, Gran, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E20..0x1E2F -- */ + Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Gran, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E30..0x1E3F -- */ + Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Gran, Gran, Gran, +/* DATA_BLOCK: -- 0x1E40..0x1E4F -- */ + Gran, Gran, Gran, Gran, Zzzz, Zzzz, Gran, Gran, Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E50..0x1E5F -- */ + Gran, Gran, Gran, Gran, Gran, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1E60..0x1E6F -- */ + Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Zzzz, Tutg, Zzzz, Zzzz, Tutg, Zzzz, +/* DATA_BLOCK: -- 0x1E70..0x1E7F -- */ + Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, +/* DATA_BLOCK: -- 0x1E80..0x1E8F -- */ + Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Zzzz, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, +/* DATA_BLOCK: -- 0x1E90..0x1E9F -- */ + Tutg, Zzzz, Tutg, Zzzz, Zzzz, Tutg, Zzzz, Tutg, Tutg, Tutg, Tutg, Zzzz, Tutg, Tutg, Tutg, Tutg, +/* DATA_BLOCK: -- 0x1EA0..0x1EAF -- */ + Tutg, Tutg, Tutg, Tutg, Tutg, Tutg, Zzzz, Tutg, Tutg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1EB0..0x1EBF -- */ + Zzzz, Tutg, Tutg, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1EC0..0x1ECF -- */ + Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, +/* DATA_BLOCK: -- 0x1ED0..0x1EDF -- */ + Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Newa, Zzzz, Newa, Newa, Newa, +/* DATA_BLOCK: -- 0x1EE0..0x1EEF -- */ + Newa, Newa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1EF0..0x1EFF -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, +/* DATA_BLOCK: -- 0x1F00..0x1F0F -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F10..0x1F1F -- */ + Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Tirh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F20..0x1F2F -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, +/* DATA_BLOCK: -- 0x1F30..0x1F3F -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Zzzz, Zzzz, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, +/* DATA_BLOCK: -- 0x1F40..0x1F4F -- */ + Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Sidd, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F50..0x1F5F -- */ + Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, +/* DATA_BLOCK: -- 0x1F60..0x1F6F -- */ + Modi, Modi, Modi, Modi, Modi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F70..0x1F7F -- */ + Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Modi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F80..0x1F8F -- */ + Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Mong, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1F90..0x1F9F -- */ + Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, +/* DATA_BLOCK: -- 0x1FA0..0x1FAF -- */ + Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Takr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1FB0..0x1FBF -- */ + Mymr, Mymr, Mymr, Mymr, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1FC0..0x1FCF -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, +/* DATA_BLOCK: -- 0x1FD0..0x1FDF -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Ahom, Ahom, Ahom, +/* DATA_BLOCK: -- 0x1FE0..0x1FEF -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x1FF0..0x1FFF -- */ + Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Ahom, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2000..0x200F -- */ + Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, +/* DATA_BLOCK: -- 0x2010..0x201F -- */ + Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Dogr, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2020..0x202F -- */ + Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, Wara, +/* DATA_BLOCK: -- 0x2030..0x203F -- */ + Wara, Wara, Wara, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Wara, +/* DATA_BLOCK: -- 0x2040..0x204F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Diak, Zzzz, Zzzz, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x2050..0x205F -- */ + Diak, Diak, Diak, Diak, Zzzz, Diak, Diak, Zzzz, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x2060..0x206F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x2070..0x207F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Diak, Diak, Zzzz, Zzzz, Diak, Diak, Diak, Diak, Diak, +/* DATA_BLOCK: -- 0x2080..0x208F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2090..0x209F -- */ + Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Diak, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20A0..0x20AF -- */ + Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Zzzz, Zzzz, Nand, Nand, Nand, Nand, Nand, Nand, +/* DATA_BLOCK: -- 0x20B0..0x20BF -- */ + Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, Nand, +/* DATA_BLOCK: -- 0x20C0..0x20CF -- */ + Nand, Nand, Nand, Nand, Nand, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20D0..0x20DF -- */ + Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, +/* DATA_BLOCK: -- 0x20E0..0x20EF -- */ + Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zanb, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x20F0..0x20FF -- */ + Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, Soyo, +/* DATA_BLOCK: -- 0x2100..0x210F -- */ + Soyo, Soyo, Soyo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2110..0x211F -- */ + Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, +/* DATA_BLOCK: -- 0x2120..0x212F -- */ + Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Pauc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2130..0x213F -- */ + Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Deva, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2140..0x214F -- */ + Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Shrd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2150..0x215F -- */ + Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, +/* DATA_BLOCK: -- 0x2160..0x216F -- */ + Sunu, Sunu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2170..0x217F -- */ + Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Sunu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2180..0x218F -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x2190..0x219F -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x21A0..0x21AF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, +/* DATA_BLOCK: -- 0x21B0..0x21BF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x21C0..0x21CF -- */ + Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Bhks, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x21D0..0x21DF -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x21E0..0x21EF -- */ + Zzzz, Zzzz, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x21F0..0x21FF -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Marc, Zzzz, Marc, Marc, Marc, Marc, Marc, Marc, Marc, +/* DATA_BLOCK: -- 0x2200..0x220F -- */ + Marc, Marc, Marc, Marc, Marc, Marc, Marc, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2210..0x221F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Gonm, Gonm, Zzzz, Gonm, Gonm, Gonm, Gonm, Gonm, +/* DATA_BLOCK: -- 0x2220..0x222F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, +/* DATA_BLOCK: -- 0x2230..0x223F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Gonm, Zzzz, Gonm, Gonm, Zzzz, Gonm, +/* DATA_BLOCK: -- 0x2240..0x224F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2250..0x225F -- */ + Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Gonm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2260..0x226F -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Gong, Gong, Zzzz, Gong, Gong, Gong, Gong, Gong, Gong, +/* DATA_BLOCK: -- 0x2270..0x227F -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, +/* DATA_BLOCK: -- 0x2280..0x228F -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, +/* DATA_BLOCK: -- 0x2290..0x229F -- */ + Gong, Gong, Zzzz, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22A0..0x22AF -- */ + Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Gong, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22B0..0x22BF -- */ + Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, +/* DATA_BLOCK: -- 0x22C0..0x22CF -- */ + Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22D0..0x22DF -- */ + Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Tols, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x22E0..0x22EF -- */ + Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, +/* DATA_BLOCK: -- 0x22F0..0x22FF -- */ + Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Maka, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2300..0x230F -- */ + Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, +/* DATA_BLOCK: -- 0x2310..0x231F -- */ + Kawi, Zzzz, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, +/* DATA_BLOCK: -- 0x2320..0x232F -- */ + Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Zzzz, Zzzz, Zzzz, Kawi, Kawi, +/* DATA_BLOCK: -- 0x2330..0x233F -- */ + Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Kawi, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2340..0x234F -- */ + Lisu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2350..0x235F -- */ + Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, Taml, +/* DATA_BLOCK: -- 0x2360..0x236F -- */ + Taml, Taml, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Taml, +/* DATA_BLOCK: -- 0x2370..0x237F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, +/* DATA_BLOCK: -- 0x2380..0x238F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2390..0x239F -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, +/* DATA_BLOCK: -- 0x23A0..0x23AF -- */ + Xsux, Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x23B0..0x23BF -- */ + Xsux, Xsux, Xsux, Xsux, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x23C0..0x23CF -- */ + Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, Cpmn, +/* DATA_BLOCK: -- 0x23D0..0x23DF -- */ + Cpmn, Cpmn, Cpmn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x23E0..0x23EF -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, +/* DATA_BLOCK: -- 0x23F0..0x23FF -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2400..0x240F -- */ + Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Egyp, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2410..0x241F -- */ + Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, +/* DATA_BLOCK: -- 0x2420..0x242F -- */ + Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Hluw, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2430..0x243F -- */ + Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, +/* DATA_BLOCK: -- 0x2440..0x244F -- */ + Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Gukh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2450..0x245F -- */ + Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Bamu, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2460..0x246F -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, +/* DATA_BLOCK: -- 0x2470..0x247F -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Zzzz, +/* DATA_BLOCK: -- 0x2480..0x248F -- */ + Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Mroo, Zzzz, Zzzz, Zzzz, Zzzz, Mroo, Mroo, +/* DATA_BLOCK: -- 0x2490..0x249F -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, +/* DATA_BLOCK: -- 0x24A0..0x24AF -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Zzzz, +/* DATA_BLOCK: -- 0x24B0..0x24BF -- */ + Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Tnsa, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24C0..0x24CF -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, +/* DATA_BLOCK: -- 0x24D0..0x24DF -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Bass, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24E0..0x24EF -- */ + Bass, Bass, Bass, Bass, Bass, Bass, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x24F0..0x24FF -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x2500..0x250F -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2510..0x251F -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x2520..0x252F -- */ + Hmng, Hmng, Zzzz, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x2530..0x253F -- */ + Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Hmng, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Hmng, Hmng, Hmng, +/* DATA_BLOCK: -- 0x2540..0x254F -- */ + Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, +/* DATA_BLOCK: -- 0x2550..0x255F -- */ + Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Krai, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2560..0x256F -- */ + Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, +/* DATA_BLOCK: -- 0x2570..0x257F -- */ + Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Medf, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2580..0x258F -- */ + Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, +/* DATA_BLOCK: -- 0x2590..0x259F -- */ + Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Berf, Zzzz, Zzzz, Berf, Berf, Berf, Berf, Berf, +/* DATA_BLOCK: -- 0x25A0..0x25AF -- */ + Berf, Berf, Berf, Berf, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x25B0..0x25BF -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, +/* DATA_BLOCK: -- 0x25C0..0x25CF -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Zzzz, Zzzz, Zzzz, Zzzz, Plrd, +/* DATA_BLOCK: -- 0x25D0..0x25DF -- */ + Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Plrd, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Plrd, +/* DATA_BLOCK: -- 0x25E0..0x25EF -- */ + Tang, Nshu, Hani, Hani, Kits, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x25F0..0x25FF -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2600..0x260F -- */ + Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, +/* DATA_BLOCK: -- 0x2610..0x261F -- */ + Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, Kits, +/* DATA_BLOCK: -- 0x2620..0x262F -- */ + Kits, Kits, Kits, Kits, Kits, Kits, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2630..0x263F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Kits, +/* DATA_BLOCK: -- 0x2640..0x264F -- */ + Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Tang, Zzzz, +/* DATA_BLOCK: -- 0x2650..0x265F -- */ + Tang, Tang, Tang, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2660..0x266F -- */ + Kana, Kana, Kana, Kana, Zzzz, Kana, Kana, Kana, Kana, Kana, Kana, Kana, Zzzz, Kana, Kana, Zzzz, +/* DATA_BLOCK: -- 0x2670..0x267F -- */ + Kana, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, Hira, +/* DATA_BLOCK: -- 0x2680..0x268F -- */ + Kana, Kana, Kana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2690..0x269F -- */ + Zzzz, Zzzz, Hira, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x26A0..0x26AF -- */ + Hira, Hira, Hira, Zzzz, Zzzz, Kana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x26B0..0x26BF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Kana, Kana, Kana, Kana, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x26C0..0x26CF -- */ + Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, +/* DATA_BLOCK: -- 0x26D0..0x26DF -- */ + Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Nshu, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x26E0..0x26EF -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, +/* DATA_BLOCK: -- 0x26F0..0x26FF -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2700..0x270F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2710..0x271F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2720..0x272F -- */ + Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Dupl, Zzzz, Zzzz, Dupl, Dupl, Dupl, Dupl, +/* DATA_BLOCK: -- 0x2730..0x273F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2740..0x274F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2750..0x275F -- */ + Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2760..0x276F -- */ + Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2770..0x277F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2780..0x278F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2790..0x279F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x27A0..0x27AF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, +/* DATA_BLOCK: -- 0x27B0..0x27BF -- */ + Zinh, Zinh, Zinh, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x27C0..0x27CF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zinh, Zinh, Zinh, Zinh, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x27D0..0x27DF -- */ + Grek, Grek, Grek, Grek, Grek, Grek, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x27E0..0x27EF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x27F0..0x27FF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2800..0x280F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2810..0x281F -- */ + Zzzz, Zzzz, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2820..0x282F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2830..0x283F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2840..0x284F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2850..0x285F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2860..0x286F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, +/* DATA_BLOCK: -- 0x2870..0x287F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2880..0x288F -- */ + Zyyy, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2890..0x289F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x28A0..0x28AF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x28B0..0x28BF -- */ + Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x28C0..0x28CF -- */ + Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x28D0..0x28DF -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x28E0..0x28EF -- */ + Zzzz, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, Sgnw, +/* DATA_BLOCK: -- 0x28F0..0x28FF -- */ + Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, +/* DATA_BLOCK: -- 0x2900..0x290F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Latn, Latn, Latn, Latn, Latn, Latn, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2910..0x291F -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Zzzz, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x2920..0x292F -- */ + Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Glag, Zzzz, Zzzz, Glag, Glag, Glag, Glag, Glag, +/* DATA_BLOCK: -- 0x2930..0x293F -- */ + Glag, Glag, Zzzz, Glag, Glag, Zzzz, Glag, Glag, Glag, Glag, Glag, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2940..0x294F -- */ + Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Cyrl, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2950..0x295F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Cyrl, +/* DATA_BLOCK: -- 0x2960..0x296F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, +/* DATA_BLOCK: -- 0x2970..0x297F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2980..0x298F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2990..0x299F -- */ + Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Hmnp, Zzzz, Zzzz, Zzzz, Zzzz, Hmnp, Hmnp, +/* DATA_BLOCK: -- 0x29A0..0x29AF -- */ + Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, +/* DATA_BLOCK: -- 0x29B0..0x29BF -- */ + Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Toto, Zzzz, +/* DATA_BLOCK: -- 0x29C0..0x29CF -- */ + Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, +/* DATA_BLOCK: -- 0x29D0..0x29DF -- */ + Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Wcho, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Wcho, +/* DATA_BLOCK: -- 0x29E0..0x29EF -- */ + Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, +/* DATA_BLOCK: -- 0x29F0..0x29FF -- */ + Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Nagm, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2A00..0x2A0F -- */ + Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, +/* DATA_BLOCK: -- 0x2A10..0x2A1F -- */ + Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Onao, Zzzz, Zzzz, Zzzz, Zzzz, Onao, +/* DATA_BLOCK: -- 0x2A20..0x2A2F -- */ + Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, +/* DATA_BLOCK: -- 0x2A30..0x2A3F -- */ + Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Zzzz, +/* DATA_BLOCK: -- 0x2A40..0x2A4F -- */ + Tayo, Tayo, Tayo, Tayo, Tayo, Tayo, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Tayo, Tayo, +/* DATA_BLOCK: -- 0x2A50..0x2A5F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Ethi, Ethi, Zzzz, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x2A60..0x2A6F -- */ + Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Ethi, Zzzz, +/* DATA_BLOCK: -- 0x2A70..0x2A7F -- */ + Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, +/* DATA_BLOCK: -- 0x2A80..0x2A8F -- */ + Mend, Mend, Mend, Mend, Mend, Zzzz, Zzzz, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, Mend, +/* DATA_BLOCK: -- 0x2A90..0x2A9F -- */ + Mend, Mend, Mend, Mend, Mend, Mend, Mend, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2AA0..0x2AAF -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, +/* DATA_BLOCK: -- 0x2AB0..0x2ABF -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2AC0..0x2ACF -- */ + Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Adlm, Zzzz, Zzzz, Zzzz, Zzzz, Adlm, Adlm, +/* DATA_BLOCK: -- 0x2AD0..0x2ADF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2AE0..0x2AEF -- */ + Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2AF0..0x2AFF -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2B00..0x2B0F -- */ + Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2B10..0x2B1F -- */ + Zzzz, Zzzz, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2B20..0x2B2F -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, Zzzz, Arab, +/* DATA_BLOCK: -- 0x2B30..0x2B3F -- */ + Zzzz, Arab, Arab, Zzzz, Arab, Zzzz, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2B40..0x2B4F -- */ + Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Zzzz, Arab, Zzzz, +/* DATA_BLOCK: -- 0x2B50..0x2B5F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2B60..0x2B6F -- */ + Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2B70..0x2B7F -- */ + Zzzz, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, Zzzz, Arab, Arab, Arab, Arab, Arab, +/* DATA_BLOCK: -- 0x2B80..0x2B8F -- */ + Arab, Arab, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2B90..0x2B9F -- */ + Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2BA0..0x2BAF -- */ + Hira, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2BB0..0x2BBF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2BC0..0x2BCF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2BD0..0x2BDF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2BE0..0x2BEF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, Zyyy, Zyyy, +/* DATA_BLOCK: -- 0x2BF0..0x2BFF -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x2C00..0x2C0F -- */ + Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zyyy, +/* DATA_BLOCK: -- 0x2C10..0x2C1F -- */ + Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2C20..0x2C2F -- */ + Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Hani, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, +/* DATA_BLOCK: -- 0x2C30..0x2C3F -- */ + Zzzz, Zyyy, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz, Zzzz +}; + +static const SBUInt16 MainScriptIndexes[3391] = { +/* INDEX_BLOCK: -- 0x0000..0x001F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0020, 0x0010, 0x0020, 0x0000, 0x0000, 0x0030, 0x0030, + 0x0040, 0x0050, 0x0040, 0x0050, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, +/* INDEX_BLOCK: -- 0x0020..0x003F -- */ + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0060, + 0x0000, 0x0000, 0x0070, 0x0000, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0090, + 0x00A0, 0x00B0, 0x00C0, 0x00B0, 0x00B0, 0x00B0, 0x00D0, 0x00B0, +/* INDEX_BLOCK: -- 0x0040..0x005F -- */ + 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00F0, 0x00E0, 0x00E0, 0x00E0, + 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x0100, 0x0110, 0x0120, 0x0110, 0x0110, + 0x0130, 0x0140, 0x0150, 0x0150, 0x0160, 0x0150, 0x0170, 0x0180, +/* INDEX_BLOCK: -- 0x0060..0x007F -- */ + 0x0190, 0x01A0, 0x01B0, 0x01B0, 0x01C0, 0x01D0, 0x01B0, 0x01E0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01F0, 0x01B0, 0x01B0, 0x0200, 0x0210, 0x0210, 0x0210, 0x0220, 0x01B0, 0x01B0, 0x01B0, + 0x0230, 0x0230, 0x0230, 0x0240, 0x0250, 0x0250, 0x0250, 0x0260, +/* INDEX_BLOCK: -- 0x0080..0x009F -- */ + 0x0270, 0x0270, 0x0280, 0x0290, 0x02A0, 0x02B0, 0x02C0, 0x01B0, 0x01B0, 0x02D0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x02E0, 0x01B0, 0x02F0, 0x02F0, 0x02F0, 0x02F0, 0x02F0, 0x0300, 0x0310, 0x02F0, + 0x0320, 0x0330, 0x0340, 0x0350, 0x0360, 0x0370, 0x0380, 0x0390, +/* INDEX_BLOCK: -- 0x00A0..0x00BF -- */ + 0x03A0, 0x03B0, 0x03C0, 0x03D0, 0x03E0, 0x03F0, 0x0400, 0x0410, 0x0420, 0x0430, 0x0440, 0x0450, + 0x0460, 0x0470, 0x0480, 0x0490, 0x04A0, 0x04B0, 0x04C0, 0x04D0, 0x04E0, 0x04F0, 0x0500, 0x0510, + 0x0520, 0x0530, 0x0540, 0x0550, 0x0560, 0x0570, 0x0580, 0x0590, +/* INDEX_BLOCK: -- 0x00C0..0x00DF -- */ + 0x05A0, 0x05B0, 0x05C0, 0x05D0, 0x05E0, 0x05F0, 0x0600, 0x0610, 0x0620, 0x0630, 0x0640, 0x0650, + 0x0660, 0x0670, 0x0680, 0x0690, 0x06A0, 0x06B0, 0x06C0, 0x06C0, 0x06D0, 0x06E0, 0x06F0, 0x06C0, + 0x0700, 0x0710, 0x0720, 0x0730, 0x0740, 0x0750, 0x0760, 0x0770, +/* INDEX_BLOCK: -- 0x00E0..0x00FF -- */ + 0x0780, 0x0790, 0x0790, 0x07A0, 0x0790, 0x07B0, 0x07C0, 0x07C0, 0x07D0, 0x07E0, 0x07F0, 0x0800, + 0x0810, 0x0820, 0x07C0, 0x07C0, 0x0830, 0x0830, 0x0830, 0x0830, 0x0840, 0x0830, 0x0850, 0x0860, + 0x0830, 0x0840, 0x0830, 0x0870, 0x0870, 0x0880, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0100..0x011F -- */ + 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x0890, 0x08A0, 0x08A0, + 0x08B0, 0x08A0, 0x08A0, 0x08C0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, +/* INDEX_BLOCK: -- 0x0120..0x013F -- */ + 0x08E0, 0x08E0, 0x08E0, 0x08E0, 0x08F0, 0x0900, 0x08E0, 0x08E0, 0x08F0, 0x08E0, 0x08E0, 0x0910, + 0x0920, 0x0930, 0x08E0, 0x08E0, 0x08E0, 0x0920, 0x08E0, 0x08E0, 0x08E0, 0x0940, 0x08E0, 0x0950, + 0x08E0, 0x0960, 0x0970, 0x0970, 0x0970, 0x0970, 0x0970, 0x0980, +/* INDEX_BLOCK: -- 0x0140..0x015F -- */ + 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, + 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, + 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, +/* INDEX_BLOCK: -- 0x0160..0x017F -- */ + 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x0990, 0x09A0, 0x09B0, 0x09C0, 0x09C0, + 0x09C0, 0x09C0, 0x09D0, 0x09E0, 0x09F0, 0x0A00, 0x0A10, 0x0A20, 0x0A30, 0x0A40, 0x0A50, 0x0A60, + 0x0A70, 0x0A70, 0x0A70, 0x0A70, 0x0A70, 0x0A80, 0x0A90, 0x0A90, +/* INDEX_BLOCK: -- 0x0180..0x019F -- */ + 0x0AA0, 0x0AB0, 0x0AC0, 0x0AC0, 0x0AC0, 0x0AC0, 0x0AC0, 0x0AD0, 0x0AC0, 0x0AC0, 0x0AE0, 0x0990, + 0x0990, 0x0990, 0x0990, 0x0AF0, 0x0B00, 0x0B10, 0x0B20, 0x0B20, 0x0B30, 0x0B40, 0x0B50, 0x0B60, + 0x0B70, 0x0B70, 0x0B80, 0x0B70, 0x0B90, 0x0BA0, 0x0A70, 0x0A70, +/* INDEX_BLOCK: -- 0x01A0..0x01BF -- */ + 0x0BB0, 0x0BC0, 0x0BD0, 0x0BD0, 0x0BD0, 0x0BE0, 0x0BD0, 0x0BF0, 0x0C00, 0x0C00, 0x0C10, 0x0080, + 0x0080, 0x0C20, 0x0C30, 0x07C0, 0x0C40, 0x0C40, 0x0C40, 0x0C40, 0x0C50, 0x0C40, 0x0C40, 0x0C40, + 0x0C60, 0x0C60, 0x0C60, 0x0C60, 0x0C70, 0x0C70, 0x0C70, 0x0C80, +/* INDEX_BLOCK: -- 0x01C0..0x01DF -- */ + 0x0C90, 0x0C90, 0x0C90, 0x0CA0, 0x0CB0, 0x0CC0, 0x0CC0, 0x0CC0, 0x0CD0, 0x08A0, 0x08A0, 0x0CE0, + 0x0CF0, 0x0D00, 0x0D10, 0x0D20, 0x0040, 0x0040, 0x0D30, 0x0040, 0x0040, 0x0D40, 0x0D50, 0x0D60, + 0x0040, 0x0040, 0x0040, 0x0D70, 0x0080, 0x0080, 0x0080, 0x0080, +/* INDEX_BLOCK: -- 0x01E0..0x01FF -- */ + 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x0040, 0x0040, 0x0040, 0x0040, 0x00B0, 0x0D80, 0x00B0, 0x00B0, 0x0D80, 0x0D90, 0x00B0, 0x0DA0, + 0x00B0, 0x00B0, 0x00B0, 0x0DB0, 0x0DB0, 0x0DC0, 0x00B0, 0x0DD0, +/* INDEX_BLOCK: -- 0x0200..0x021F -- */ + 0x0DE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0DF0, 0x0E00, 0x0E10, 0x0E20, 0x0000, 0x0000, + 0x0E30, 0x0080, 0x0080, 0x0E40, 0x0000, 0x0000, 0x0E50, 0x0E60, 0x0E70, 0x0000, 0x0040, 0x0040, + 0x0E80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0220..0x023F -- */ + 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, +/* INDEX_BLOCK: -- 0x0240..0x025F -- */ + 0x0000, 0x0000, 0x0E90, 0x07C0, 0x0EA0, 0x07C0, 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, +/* INDEX_BLOCK: -- 0x0260..0x027F -- */ + 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, + 0x0EB0, 0x0EB0, 0x0EB0, 0x0EB0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0280..0x029F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0EC0, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x02A0..0x02BF -- */ + 0x0ED0, 0x0ED0, 0x0ED0, 0x0ED0, 0x0ED0, 0x0ED0, 0x0040, 0x0040, 0x0EE0, 0x0EE0, 0x0EE0, 0x0EE0, + 0x0EE0, 0x0EE0, 0x0EE0, 0x0EF0, 0x08A0, 0x08A0, 0x08B0, 0x0F00, 0x0F00, 0x0F00, 0x0F10, 0x0F20, + 0x08E0, 0x0F30, 0x0F40, 0x0F40, 0x0F40, 0x0F40, 0x00E0, 0x00E0, +/* INDEX_BLOCK: -- 0x02C0..0x02DF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0F50, 0x07C0, 0x07C0, 0x0F60, 0x0F70, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F80, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F90, 0x07C0, 0x0000, +/* INDEX_BLOCK: -- 0x02E0..0x02FF -- */ + 0x0FA0, 0x0000, 0x0FB0, 0x0FC0, 0x0FD0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FF0, 0x1000, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1020, 0x1030, 0x1040, 0x1040, 0x1050, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x1060, 0x0000, 0x1040, 0x1040, 0x0000, 0x0000, 0x1070, 0x1010, +/* INDEX_BLOCK: -- 0x0300..0x031F -- */ + 0x08D0, 0x1060, 0x0000, 0x0000, 0x0000, 0x0000, 0x08D0, 0x1080, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1010, 0x1010, 0x1090, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x10A0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0320..0x033F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0340..0x035F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0360..0x037F -- */ + 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, + 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, + 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, +/* INDEX_BLOCK: -- 0x0380..0x039F -- */ + 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10B0, 0x10C0, 0x10B0, 0x10B0, 0x10B0, + 0x10D0, 0x10E0, 0x10E0, 0x10E0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, + 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, 0x10F0, +/* INDEX_BLOCK: -- 0x03A0..0x03BF -- */ + 0x10F0, 0x10F0, 0x1100, 0x07C0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x00E0, 0x1110, 0x1110, + 0x1110, 0x1110, 0x1110, 0x1120, 0x0000, 0x0000, 0x1130, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040, + 0x1140, 0x0040, 0x0040, 0x0040, 0x0040, 0x0E20, 0x07C0, 0x1150, +/* INDEX_BLOCK: -- 0x03C0..0x03DF -- */ + 0x1160, 0x1160, 0x1170, 0x0E90, 0x1180, 0x1180, 0x1180, 0x1190, 0x11A0, 0x11A0, 0x11A0, 0x11A0, + 0x11B0, 0x11C0, 0x02F0, 0x02F0, 0x11D0, 0x11D0, 0x11E0, 0x11F0, 0x11F0, 0x1200, 0x08D0, 0x1210, + 0x1220, 0x1220, 0x1220, 0x1220, 0x1230, 0x1240, 0x0890, 0x1250, +/* INDEX_BLOCK: -- 0x03E0..0x03FF -- */ + 0x1260, 0x1260, 0x1260, 0x1270, 0x1280, 0x1290, 0x0890, 0x0890, 0x12A0, 0x12A0, 0x12A0, 0x12A0, + 0x12B0, 0x12C0, 0x12D0, 0x12E0, 0x12F0, 0x1300, 0x0F40, 0x0040, 0x0040, 0x1310, 0x1320, 0x0970, + 0x0970, 0x0970, 0x0970, 0x0970, 0x12D0, 0x12D0, 0x1330, 0x1340, +/* INDEX_BLOCK: -- 0x0400..0x041F -- */ + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, +/* INDEX_BLOCK: -- 0x0420..0x043F -- */ + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, 0x08D0, + 0x08D0, 0x08D0, 0x1350, 0x08D0, 0x1360, 0x08D0, 0x08D0, 0x1370, +/* INDEX_BLOCK: -- 0x0440..0x045F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0460..0x047F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0480..0x049F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x1380, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x1390, 0x07C0, 0x07C0, 0x13A0, 0x13B0, 0x0150, 0x13C0, 0x13D0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, +/* INDEX_BLOCK: -- 0x04A0..0x04BF -- */ + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x13E0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x01B0, 0x07C0, 0x07C0, 0x01B0, +/* INDEX_BLOCK: -- 0x04C0..0x04DF -- */ + 0x0080, 0x0E90, 0x13F0, 0x0000, 0x0000, 0x1400, 0x1410, 0x1420, 0x01B0, 0x01B0, 0x01B0, 0x01B0, + 0x01B0, 0x01B0, 0x01B0, 0x1430, 0x1440, 0x0000, 0x0010, 0x0020, 0x0010, 0x0020, 0x1450, 0x1000, + 0x1010, 0x1460, 0x08D0, 0x1060, 0x1470, 0x1480, 0x1490, 0x14A0, +/* INDEX_BLOCK: -- 0x04E0..0x04FF -- */ + 0x14B0, 0x14C0, 0x14D0, 0x14E0, 0x14F0, 0x14F0, 0x07C0, 0x07C0, 0x14C0, 0x14C0, 0x14C0, 0x14C0, + 0x14C0, 0x14C0, 0x14C0, 0x1500, 0x1510, 0x0000, 0x0000, 0x1520, 0x00B0, 0x00B0, 0x00B0, 0x00B0, + 0x1530, 0x1540, 0x1550, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x1560, +/* INDEX_BLOCK: -- 0x0500..0x051F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x1570, 0x1580, 0x1590, 0x1590, + 0x1590, 0x15A0, 0x15B0, 0x15C0, 0x15D0, 0x15D0, 0x15E0, 0x15F0, 0x1600, 0x1610, 0x1610, 0x1620, + 0x1630, 0x1640, 0x1650, 0x1650, 0x1660, 0x1670, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0520..0x053F -- */ + 0x1680, 0x1680, 0x1680, 0x1680, 0x1680, 0x1690, 0x1690, 0x1690, 0x16A0, 0x16B0, 0x16C0, 0x16D0, + 0x16D0, 0x16E0, 0x16D0, 0x16F0, 0x1700, 0x1700, 0x1710, 0x1720, 0x1720, 0x1720, 0x1730, 0x1740, + 0x1740, 0x1750, 0x1760, 0x1770, 0x1780, 0x1780, 0x1780, 0x1790, +/* INDEX_BLOCK: -- 0x0540..0x055F -- */ + 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, + 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17A0, 0x17B0, 0x17A0, 0x17C0, 0x17D0, 0x07C0, + 0x17E0, 0x0040, 0x0040, 0x17F0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0560..0x057F -- */ + 0x1800, 0x1810, 0x1810, 0x1820, 0x1830, 0x1840, 0x1850, 0x1850, 0x1860, 0x1870, 0x1880, 0x07C0, + 0x07C0, 0x07C0, 0x1890, 0x18A0, 0x18B0, 0x18C0, 0x18D0, 0x18E0, 0x18F0, 0x1900, 0x07C0, 0x07C0, + 0x1910, 0x1910, 0x1920, 0x1930, 0x1920, 0x1940, 0x1920, 0x1920, +/* INDEX_BLOCK: -- 0x0580..0x059F -- */ + 0x1950, 0x1960, 0x1970, 0x1980, 0x1990, 0x1990, 0x19A0, 0x19A0, 0x19B0, 0x19B0, 0x07C0, 0x07C0, + 0x19C0, 0x19C0, 0x19D0, 0x19E0, 0x19F0, 0x19F0, 0x19F0, 0x1A00, 0x1A10, 0x1A20, 0x1A30, 0x1A40, + 0x1A50, 0x1A60, 0x1A70, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x05A0..0x05BF -- */ + 0x1A80, 0x1A80, 0x1A80, 0x1A80, 0x1A90, 0x07C0, 0x07C0, 0x07C0, 0x1AA0, 0x1AA0, 0x1AA0, 0x1AB0, + 0x1AA0, 0x1AA0, 0x1AA0, 0x1AC0, 0x1AD0, 0x1AD0, 0x1AE0, 0x1AF0, 0x1B00, 0x1B00, 0x1B10, 0x1B00, + 0x1B20, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x05C0..0x05DF -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x01B0, 0x1B30, 0x1B40, 0x1B40, 0x1B50, 0x1B60, + 0x1B70, 0x1B80, 0x07C0, 0x1B90, 0x1BA0, 0x1BA0, 0x1BB0, 0x1BC0, 0x1BC0, 0x1BD0, 0x07C0, 0x1BE0, + 0x1BF0, 0x07C0, 0x07C0, 0x1C00, 0x1C10, 0x07C0, 0x1C20, 0x1C30, +/* INDEX_BLOCK: -- 0x05E0..0x05FF -- */ + 0x1C40, 0x1C40, 0x1C40, 0x1C40, 0x1C50, 0x1C60, 0x1C40, 0x1C70, 0x1C80, 0x1C80, 0x1C80, 0x1C80, + 0x1C90, 0x1CA0, 0x1CB0, 0x1CC0, 0x1CD0, 0x1CD0, 0x1CD0, 0x1CE0, 0x1CF0, 0x1D00, 0x1D00, 0x1D10, + 0x1D20, 0x1D20, 0x1D20, 0x1D20, 0x1D20, 0x1D20, 0x1D30, 0x1D40, +/* INDEX_BLOCK: -- 0x0600..0x061F -- */ + 0x1D50, 0x1D60, 0x1D50, 0x1D50, 0x1D70, 0x07C0, 0x07C0, 0x07C0, 0x1D80, 0x1D90, 0x1DA0, 0x1DB0, + 0x1DB0, 0x1DB0, 0x1DC0, 0x1DD0, 0x1DE0, 0x1DF0, 0x1E00, 0x1E10, 0x1E20, 0x1E30, 0x1E40, 0x1E50, + 0x1E60, 0x1E70, 0x1E70, 0x1E80, 0x1E90, 0x1EA0, 0x1EB0, 0x07C0, +/* INDEX_BLOCK: -- 0x0620..0x063F -- */ + 0x1EC0, 0x1EC0, 0x1EC0, 0x1EC0, 0x1EC0, 0x1ED0, 0x1EE0, 0x07C0, 0x1EF0, 0x1EF0, 0x1EF0, 0x1EF0, + 0x1F00, 0x1F10, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x1F20, 0x1F20, 0x1F20, 0x1F30, 0x1F20, 0x1F40, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0640..0x065F -- */ + 0x1F50, 0x1F50, 0x1F50, 0x1F50, 0x1F60, 0x1F70, 0x1F80, 0x07C0, 0x1F90, 0x1F90, 0x1F90, 0x1FA0, + 0x1FA0, 0x0890, 0x1FB0, 0x07C0, 0x1FC0, 0x1FD0, 0x1FE0, 0x1FC0, 0x1FF0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0660..0x067F -- */ + 0x2000, 0x2000, 0x2000, 0x2010, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2020, 0x2020, + 0x2020, 0x2020, 0x2020, 0x2030, 0x2040, 0x2050, 0x2060, 0x2070, 0x2080, 0x2090, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x20A0, 0x20B0, 0x20B0, 0x20A0, 0x20C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0680..0x069F -- */ + 0x20D0, 0x20D0, 0x20D0, 0x20D0, 0x20E0, 0x20F0, 0x20F0, 0x20F0, 0x20F0, 0x20F0, 0x2100, 0x0990, + 0x2110, 0x2110, 0x2110, 0x2120, 0x2130, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2140, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2150, 0x2150, 0x2160, 0x2170, +/* INDEX_BLOCK: -- 0x06A0..0x06BF -- */ + 0x2180, 0x2190, 0x2190, 0x21A0, 0x21B0, 0x2190, 0x21C0, 0x21D0, 0x21D0, 0x21E0, 0x21F0, 0x2200, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2210, 0x2220, 0x2220, 0x2230, 0x2240, 0x2250, 0x2260, 0x2270, + 0x2280, 0x2290, 0x22A0, 0x22B0, 0x22B0, 0x22C0, 0x22D0, 0x07C0, +/* INDEX_BLOCK: -- 0x06C0..0x06DF -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x22E0, 0x22F0, 0x2300, 0x2310, 0x2300, 0x2320, 0x2300, 0x2330, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x2340, 0x2350, 0x2350, 0x2350, 0x2360, +/* INDEX_BLOCK: -- 0x06E0..0x06FF -- */ + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, +/* INDEX_BLOCK: -- 0x0700..0x071F -- */ + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, + 0x2370, 0x2380, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0720..0x073F -- */ + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2390, 0x23A0, 0x2370, 0x2370, 0x2370, 0x2370, + 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x2370, 0x23B0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0740..0x075F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x23C0, 0x23C0, 0x23C0, 0x23C0, 0x23C0, 0x23C0, 0x23D0, +/* INDEX_BLOCK: -- 0x0760..0x077F -- */ + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, +/* INDEX_BLOCK: -- 0x0780..0x079F -- */ + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23F0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, +/* INDEX_BLOCK: -- 0x07A0..0x07BF -- */ + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, + 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x23E0, 0x2400, +/* INDEX_BLOCK: -- 0x07C0..0x07DF -- */ + 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, + 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, + 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, 0x2410, +/* INDEX_BLOCK: -- 0x07E0..0x07FF -- */ + 0x2410, 0x2410, 0x2410, 0x2410, 0x2420, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0800..0x081F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2430, 0x2430, 0x2430, 0x2440, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0820..0x083F -- */ + 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, + 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, + 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, +/* INDEX_BLOCK: -- 0x0840..0x085F -- */ + 0x1110, 0x1110, 0x1110, 0x2450, 0x2460, 0x2470, 0x2480, 0x2490, 0x2490, 0x2490, 0x2490, 0x24A0, + 0x24B0, 0x24C0, 0x24D0, 0x24E0, 0x24F0, 0x24F0, 0x24F0, 0x24F0, 0x2500, 0x2510, 0x2520, 0x2530, + 0x24F0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0860..0x087F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2540, 0x2540, 0x2540, 0x2550, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0880..0x089F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2560, 0x2560, 0x2560, 0x2560, 0x2560, 0x2570, 0x2580, 0x2590, + 0x2580, 0x25A0, 0x07C0, 0x07C0, 0x25B0, 0x25B0, 0x25B0, 0x25B0, 0x25C0, 0x25B0, 0x25B0, 0x25B0, + 0x25D0, 0x25B0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x25E0, 0x25F0, +/* INDEX_BLOCK: -- 0x08A0..0x08BF -- */ + 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, + 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, + 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, +/* INDEX_BLOCK: -- 0x08C0..0x08DF -- */ + 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, + 0x2600, 0x2600, 0x2600, 0x2600, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, + 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, +/* INDEX_BLOCK: -- 0x08E0..0x08FF -- */ + 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, + 0x2610, 0x2620, 0x07C0, 0x2630, 0x2600, 0x2640, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2600, 0x2650, +/* INDEX_BLOCK: -- 0x0900..0x091F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2660, +/* INDEX_BLOCK: -- 0x0920..0x093F -- */ + 0x2670, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, + 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x0FE0, 0x2680, 0x2690, 0x07C0, 0x26A0, 0x26B0, 0x26C0, + 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, +/* INDEX_BLOCK: -- 0x0940..0x095F -- */ + 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, 0x26C0, + 0x26C0, 0x26C0, 0x26C0, 0x26D0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0960..0x097F -- */ + 0x26E0, 0x26E0, 0x26E0, 0x26E0, 0x26E0, 0x26E0, 0x26F0, 0x2700, 0x2710, 0x2720, 0x2730, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0980..0x099F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x1540, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x09A0..0x09BF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2740, + 0x0000, 0x2750, 0x0000, 0x2750, 0x0080, 0x0080, 0x0C20, 0x0080, 0x2760, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x2730, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x09C0..0x09DF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2770, 0x0000, 0x0000, 0x2780, 0x0000, 0x0000, 0x0000, 0x2790, 0x27A0, + 0x27B0, 0x0000, 0x27C0, 0x0000, 0x0000, 0x0000, 0x0EA0, 0x07C0, +/* INDEX_BLOCK: -- 0x09E0..0x09FF -- */ + 0x00B0, 0x00B0, 0x00B0, 0x00B0, 0x27D0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x0000, 0x2730, 0x0000, 0x2730, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x27E0, 0x0000, 0x27F0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0A00..0x0A1F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0DF0, 0x0000, 0x0000, 0x0000, 0x2800, 0x2810, 0x2820, + 0x2830, 0x0000, 0x0000, 0x0000, 0x2840, 0x2850, 0x0000, 0x2860, 0x2870, 0x2880, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0A20..0x0A3F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2890, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x28A0, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0A40..0x0A5F -- */ + 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, + 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, + 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, +/* INDEX_BLOCK: -- 0x0A60..0x0A7F -- */ + 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28B0, 0x28C0, 0x28D0, 0x28E0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0A80..0x0A9F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x0040, 0x28F0, 0x2900, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0AA0..0x0ABF -- */ + 0x2910, 0x2920, 0x2930, 0x00E0, 0x00E0, 0x00E0, 0x2940, 0x07C0, 0x2950, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2960, 0x2960, 0x2970, 0x2980, 0x2990, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0AC0..0x0ADF -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x29A0, 0x29B0, 0x07C0, + 0x29C0, 0x29C0, 0x29C0, 0x29D0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0AE0..0x0AFF -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x29E0, 0x29E0, 0x29F0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2A00, 0x2A00, 0x2A10, +/* INDEX_BLOCK: -- 0x0B00..0x0B1F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x2A20, 0x2A30, 0x2A20, 0x2A40, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x2A50, 0x2A60, +/* INDEX_BLOCK: -- 0x0B20..0x0B3F -- */ + 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, 0x2A70, + 0x2A80, 0x2A90, 0x07C0, 0x07C0, 0x2AA0, 0x2AA0, 0x2AA0, 0x2AA0, 0x2AB0, 0x2AC0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0B40..0x0B5F -- */ + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x1440, 0x0000, 0x0000, 0x0000, 0x2AD0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x1440, 0x0000, 0x0000, 0x0F50, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0B60..0x0B7F -- */ + 0x2AE0, 0x01B0, 0x2AF0, 0x2B00, 0x2B10, 0x2B20, 0x2B30, 0x2B40, 0x2B50, 0x2B60, 0x2B70, 0x2B60, + 0x07C0, 0x07C0, 0x07C0, 0x2B80, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0B80..0x0B9F -- */ + 0x0000, 0x0000, 0x15C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2730, 0x0E10, 0x1440, + 0x1440, 0x1440, 0x0000, 0x2770, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0F50, 0x07C0, 0x07C0, 0x07C0, 0x2B90, 0x0000, +/* INDEX_BLOCK: -- 0x0BA0..0x0BBF -- */ + 0x2BA0, 0x0000, 0x0000, 0x15C0, 0x27F0, 0x0E30, 0x2770, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0BC0..0x0BDF -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2BB0, 0x1540, 0x1540, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E90, 0x15C0, 0x2750, +/* INDEX_BLOCK: -- 0x0BE0..0x0BFF -- */ + 0x15C0, 0x0000, 0x0000, 0x0000, 0x2BC0, 0x0E90, 0x0000, 0x0000, 0x2BC0, 0x0000, 0x0F50, 0x15C0, + 0x0E30, 0x27F0, 0x07C0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +/* INDEX_BLOCK: -- 0x0C00..0x0C1F -- */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2BC0, 0x0F50, 0x1540, 0x2BD0, 0x0000, 0x0000, 0x0000, + 0x2BE0, 0x2BF0, 0x2C00, 0x27F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x1400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0EA0, +/* INDEX_BLOCK: -- 0x0C20..0x0C3F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x07C0, 0x07C0, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0C40..0x0C5F -- */ + 0x0F60, 0x1380, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0C60..0x0C7F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x1380, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0C80..0x0C9F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x2C10, 0x0F60, +/* INDEX_BLOCK: -- 0x0CA0..0x0CBF -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x1380, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0CC0..0x0CDF -- */ + 0x0F60, 0x1380, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0CE0..0x0CFF -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x2C20, 0x0F60, 0x0F60, 0x0F60, + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, +/* INDEX_BLOCK: -- 0x0D00..0x0D1F -- */ + 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x0F60, 0x1390, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x07C0, +/* INDEX_BLOCK: -- 0x0D20..0x0D3E -- */ + 0x2C30, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07C0, 0x07C0, 0x07C0, 0x07C0, + 0x07C0, 0x07C0, 0x07C0, 0x07C0, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, + 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080, 0x0080 +}; + +static const SBUInt16 BranchScriptIndexes[1793] = { + 0x0000, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, 0x00C0, 0x00E0, 0x0100, 0x0120, 0x0140, 0x0160, + 0x0180, 0x01A0, 0x01C0, 0x01E0, 0x0200, 0x0220, 0x0240, 0x0220, 0x0260, 0x0280, 0x02A0, 0x02C0, + 0x02E0, 0x0300, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0340, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0360, 0x0360, 0x0380, 0x03A0, + 0x03C0, 0x03E0, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, + 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0420, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0460, 0x0480, 0x04A0, 0x04C0, 0x04E0, 0x0500, 0x0520, 0x0540, + 0x0560, 0x0580, 0x05A0, 0x05C0, 0x05E0, 0x0600, 0x0620, 0x0640, 0x0660, 0x0680, 0x06A0, 0x06C0, + 0x06E0, 0x0700, 0x0720, 0x0440, 0x0440, 0x0440, 0x0440, 0x0740, 0x0760, 0x0760, 0x0780, 0x0760, + 0x0760, 0x0760, 0x0760, 0x0760, 0x0760, 0x07A0, 0x07C0, 0x07E0, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0800, 0x0440, 0x0440, 0x0440, + 0x0820, 0x0840, 0x0860, 0x0880, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, + 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08A0, 0x08C0, 0x08E0, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0900, + 0x0920, 0x0940, 0x0440, 0x0440, 0x0440, 0x0440, 0x0960, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0980, 0x09A0, 0x09C0, 0x09E0, 0x0A00, 0x0A20, 0x0A40, 0x0A60, 0x0440, 0x0A80, + 0x0AA0, 0x0AC0, 0x0AE0, 0x0B00, 0x0B20, 0x0440, 0x0B40, 0x0B60, 0x0B80, 0x0BA0, 0x0220, 0x0BC0, + 0x0BE0, 0x0C00, 0x0440, 0x0440, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0C20, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0C40, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0C60, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0C80, 0x0320, 0x0CA0, 0x0440, 0x0440, 0x0440, 0x0440, 0x0320, 0x0CC0, 0x0440, 0x0440, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0CE0, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, 0x0320, + 0x0320, 0x0320, 0x0D00, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, 0x0440, + 0x0440, 0x0440, 0x0440, 0x0440, 0x0D20 +}; + +SB_INTERNAL SBScript LookupScript(SBCodepoint codepoint) +{ + if (codepoint <= 0x0E01EF) { + return PrimaryScriptData[ + MainScriptIndexes[ + BranchScriptIndexes[ + codepoint / 0x0200 + ] + (codepoint % 0x0200) / 0x0010 + ] + codepoint % 0x0010 + ]; + } + + return Zzzz; +} + +#undef Adlm +#undef Aghb +#undef Ahom +#undef Arab +#undef Armi +#undef Armn +#undef Avst +#undef Bali +#undef Bamu +#undef Bass +#undef Batk +#undef Beng +#undef Berf +#undef Bhks +#undef Bopo +#undef Brah +#undef Brai +#undef Bugi +#undef Buhd +#undef Cakm +#undef Cans +#undef Cari +#undef Cham +#undef Cher +#undef Chrs +#undef Copt +#undef Cpmn +#undef Cprt +#undef Cyrl +#undef Deva +#undef Diak +#undef Dogr +#undef Dsrt +#undef Dupl +#undef Egyp +#undef Elba +#undef Elym +#undef Ethi +#undef Gara +#undef Geor +#undef Glag +#undef Gong +#undef Gonm +#undef Goth +#undef Gran +#undef Grek +#undef Gujr +#undef Gukh +#undef Guru +#undef Hang +#undef Hani +#undef Hano +#undef Hatr +#undef Hebr +#undef Hira +#undef Hluw +#undef Hmng +#undef Hmnp +#undef Hung +#undef Ital +#undef Java +#undef Kali +#undef Kana +#undef Kawi +#undef Khar +#undef Khmr +#undef Khoj +#undef Kits +#undef Knda +#undef Krai +#undef Kthi +#undef Lana +#undef Laoo +#undef Latn +#undef Lepc +#undef Limb +#undef Lina +#undef Linb +#undef Lisu +#undef Lyci +#undef Lydi +#undef Mahj +#undef Maka +#undef Mand +#undef Mani +#undef Marc +#undef Medf +#undef Mend +#undef Merc +#undef Mero +#undef Mlym +#undef Modi +#undef Mong +#undef Mroo +#undef Mtei +#undef Mult +#undef Mymr +#undef Nagm +#undef Nand +#undef Narb +#undef Nbat +#undef Newa +#undef Nkoo +#undef Nshu +#undef Ogam +#undef Olck +#undef Onao +#undef Orkh +#undef Orya +#undef Osge +#undef Osma +#undef Ougr +#undef Palm +#undef Pauc +#undef Perm +#undef Phag +#undef Phli +#undef Phlp +#undef Phnx +#undef Plrd +#undef Prti +#undef Rjng +#undef Rohg +#undef Runr +#undef Samr +#undef Sarb +#undef Saur +#undef Sgnw +#undef Shaw +#undef Shrd +#undef Sidd +#undef Sidt +#undef Sind +#undef Sinh +#undef Sogd +#undef Sogo +#undef Sora +#undef Soyo +#undef Sund +#undef Sunu +#undef Sylo +#undef Syrc +#undef Tagb +#undef Takr +#undef Tale +#undef Talu +#undef Taml +#undef Tang +#undef Tavt +#undef Tayo +#undef Telu +#undef Tfng +#undef Tglg +#undef Thaa +#undef Thai +#undef Tibt +#undef Tirh +#undef Tnsa +#undef Todr +#undef Tols +#undef Toto +#undef Tutg +#undef Ugar +#undef Vaii +#undef Vith +#undef Wara +#undef Wcho +#undef Xpeo +#undef Xsux +#undef Yezi +#undef Yiii +#undef Zanb +#undef Zinh +#undef Zyyy +#undef Zzzz diff --git a/src/thirdparty/SheenBidi/Source/ScriptLookup.h b/src/thirdparty/SheenBidi/Source/ScriptLookup.h new file mode 100644 index 000000000..517beec77 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ScriptLookup.h @@ -0,0 +1,16 @@ +/* + * Automatically generated by SheenBidiGenerator tool. + * DO NOT EDIT!! + */ + +#ifndef _SB_INTERNAL_SCRIPT_LOOKUP_H +#define _SB_INTERNAL_SCRIPT_LOOKUP_H + +#include +#include +#include +#include + +SB_INTERNAL SBScript LookupScript(SBCodepoint codepoint); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/ScriptStack.c b/src/thirdparty/SheenBidi/Source/ScriptStack.c new file mode 100644 index 000000000..6347e2a0f --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ScriptStack.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "SBAssert.h" +#include "SBBase.h" +#include "SBCodepoint.h" +#include "ScriptStack.h" + +SB_INTERNAL void ScriptStackReset(ScriptStackRef stack) +{ + stack->top = -1; + stack->count = 0; + stack->open = 0; +} + +SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror) +{ + stack->count = SBNumberLimitIncrement(stack->count, _SBScriptStackCapacity); + stack->open = SBNumberLimitIncrement(stack->open, _SBScriptStackCapacity); + + stack->top = SBNumberRingIncrement(stack->top, _SBScriptStackCapacity); + stack->_elements[stack->top].script = script; + stack->_elements[stack->top].mirror = mirror; +} + +SB_INTERNAL void ScriptStackPop(ScriptStackRef stack) +{ + /* There must be at least one entry in the stack. */ + SBAssert(stack->count > 0); + + stack->count -= 1; + stack->open = SBNumberLimitDecrement(stack->open, 0); + stack->top = SBNumberRingDecrement(stack->top, _SBScriptStackCapacity); + + if (ScriptStackIsEmpty(stack)) { + stack->top = -1; + } +} + +SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack) +{ + stack->open = 0; +} + +SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script) +{ + SBInteger index = SBNumberRingSubtract(stack->top, (SBInteger)stack->open, _SBScriptStackCapacity); + + while (stack->open) { + index = SBNumberRingIncrement(index, _SBScriptStackCapacity); + stack->_elements[index].script = script; + stack->open -= 1; + } +} + +SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack) +{ + return (stack->count == 0); +} + +SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack) +{ + return stack->_elements[stack->top].script; +} + +SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack) +{ + return stack->_elements[stack->top].mirror; +} diff --git a/src/thirdparty/SheenBidi/Source/ScriptStack.h b/src/thirdparty/SheenBidi/Source/ScriptStack.h new file mode 100644 index 000000000..15996bdcb --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ScriptStack.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_SCRIPT_STACK_H +#define _SB_INTERNAL_SCRIPT_STACK_H + +#include +#include +#include + +#define _SBScriptStackCapacity 63 + +typedef struct _SBScriptStackElement { + SBScript script; + SBCodepoint mirror; +} _SBScriptStackElement; + +typedef struct _SBScriptStack { + _SBScriptStackElement _elements[_SBScriptStackCapacity]; + SBInteger top; + SBUInteger count; + SBUInteger open; +} ScriptStack, *ScriptStackRef; + +SB_INTERNAL void ScriptStackReset(ScriptStackRef stack); + +SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror); +SB_INTERNAL void ScriptStackPop(ScriptStackRef stack); + +SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack); +SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script); + +SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack); +SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack); +SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/SheenBidi.c b/src/thirdparty/SheenBidi/Source/SheenBidi.c new file mode 100644 index 000000000..5e7a1220e --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/SheenBidi.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#ifdef SB_CONFIG_UNITY + +#include "BidiChain.c" +#include "BidiTypeLookup.c" +#include "BracketQueue.c" +#include "GeneralCategoryLookup.c" +#include "IsolatingRun.c" +#include "LevelRun.c" +#include "Memory.c" +#include "Object.c" +#include "Once.c" +#include "PairingLookup.c" +#include "RunQueue.c" +#include "SBAlgorithm.c" +#include "SBAllocator.c" +#include "SBBase.c" +#include "SBCodepoint.c" +#include "SBCodepointSequence.c" +#include "SBLine.c" +#include "SBLog.c" +#include "SBMirrorLocator.c" +#include "SBParagraph.c" +#include "SBScriptLocator.c" +#include "ScriptLookup.c" +#include "ScriptStack.c" +#include "StatusStack.c" + +#endif diff --git a/src/thirdparty/SheenBidi/Source/StatusStack.c b/src/thirdparty/SheenBidi/Source/StatusStack.c new file mode 100644 index 000000000..acd5eca9e --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/StatusStack.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "Memory.h" +#include "SBAssert.h" +#include "SBBase.h" +#include "StatusStack.h" + +#define LIST 0 +#define ELEMENTS 1 +#define COUNT 2 + +static StatusStackElementRef InsertStatusStackElement(StatusStackRef stack) +{ + StatusStackListRef peekList = stack->_peekList; + StatusStackElementRef element = NULL; + + if ((stack->_peekTop + 1) < peekList->capacity) { + stack->_peekTop += 1; + stack->count += 1; + + element = &peekList->elements[stack->_peekTop]; + } else { + StatusStackListRef previousList = peekList; + + peekList = previousList->next; + + if (!peekList) { + const SBUInteger capacity = stack->count; + void *pointers[COUNT] = { NULL }; + SBUInteger sizes[COUNT]; + + sizes[LIST] = sizeof(StatusStackList); + sizes[ELEMENTS] = sizeof(StatusStackElement) * capacity; + + if (MemoryAllocateChunks(stack->_memory, MemoryTypeScratch, sizes, COUNT, pointers)) { + peekList = pointers[LIST]; + peekList->elements = pointers[ELEMENTS]; + peekList->capacity = capacity; + peekList->previous = previousList; + peekList->next = NULL; + + previousList->next = peekList; + } + } + + if (peekList) { + stack->_peekList = peekList; + stack->_peekTop = 0; + stack->count += 1; + + element = &peekList->elements[0]; + } + } + + return element; +} + +#undef LIST +#undef ELEMENTS +#undef COUNT + +SB_INTERNAL void StatusStackInitialize(StatusStackRef stack, MemoryRef memory) +{ + stack->_memory = memory; + + stack->_firstList.elements = stack->_elements; + stack->_firstList.capacity = StatusStackEmbeddedElementCount; + stack->_firstList.previous = NULL; + stack->_firstList.next = NULL; + + StatusStackSetEmpty(stack); +} + +SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack, + SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus) +{ + SBBoolean isPushed = SBFalse; + StatusStackElementRef element; + + /* The stack can hold upto 127 elements. */ + SBAssert(stack->count <= 127); + + element = InsertStatusStackElement(stack); + + if (element) { + element->embeddingLevel = embeddingLevel; + element->overrideStatus = overrideStatus; + element->isolateStatus = isolateStatus; + + isPushed = SBTrue; + } + + return isPushed; +} + +SB_INTERNAL void StatusStackPop(StatusStackRef stack) +{ + /* The stack should not be empty. */ + SBAssert(stack->count > 0); + + if (stack->_peekTop != 0) { + stack->_peekTop -= 1; + } else { + stack->_peekList = stack->_peekList->previous; + stack->_peekTop = stack->_peekList->capacity - 1; + } + + stack->count -= 1; +} + +SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack) +{ + stack->_peekList = &stack->_firstList; + stack->_peekTop = SBInvalidIndex; + stack->count = 0; +} + +SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].embeddingLevel; +} + +SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].overrideStatus; +} + +SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack) +{ + return stack->_peekList->elements[stack->_peekTop].isolateStatus; +} diff --git a/src/thirdparty/SheenBidi/Source/StatusStack.h b/src/thirdparty/SheenBidi/Source/StatusStack.h new file mode 100644 index 000000000..99742713c --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/StatusStack.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014-2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_STATUS_STACK_H +#define _SB_INTERNAL_STATUS_STACK_H + +#include +#include + +#include "Memory.h" + +#define StatusStackEmbeddedElementCount 16 +#define StatusStackMaxCapacity 127 + +typedef struct _StatusStackElement { + SBBoolean isolateStatus; + SBBidiType overrideStatus; + SBLevel embeddingLevel; +} StatusStackElement, *StatusStackElementRef; + +typedef struct _StatusStackList { + StatusStackElement *elements; + SBUInteger capacity; + + struct _StatusStackList *previous; + struct _StatusStackList *next; +} StatusStackList, *StatusStackListRef; + +typedef struct _StatusStack { + MemoryRef _memory; + StatusStackElement _elements[StatusStackEmbeddedElementCount]; + StatusStackList _firstList; + StatusStackListRef _peekList; + SBUInteger _peekTop; + SBUInteger count; +} StatusStack, *StatusStackRef; + +SB_INTERNAL void StatusStackInitialize(StatusStackRef stack, MemoryRef memory); + +SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack, + SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus); +SB_INTERNAL void StatusStackPop(StatusStackRef stack); +SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack); + +SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack); +SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack); +SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack); + +#endif diff --git a/src/thirdparty/SheenBidi/Source/ThreadFence.h b/src/thirdparty/SheenBidi/Source/ThreadFence.h new file mode 100644 index 000000000..4d46823f1 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ThreadFence.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_THREAD_FENCE_H +#define _SB_INTERNAL_THREAD_FENCE_H + +#include "SBBase.h" + +#if defined(USE_C11_ATOMICS) + +#include +#define HAS_THREAD_FENCE_SUPPORT +#define ThreadFence() atomic_thread_fence(memory_order_seq_cst) + +#elif defined(USE_ATOMIC_BUILTINS) + +#define HAS_THREAD_FENCE_SUPPORT +#define ThreadFence() __atomic_thread_fence(__ATOMIC_SEQ_CST) + +#elif defined(USE_SYNC_BUILTINS) + +#define HAS_THREAD_FENCE_SUPPORT +#define ThreadFence() __sync_synchronize() + +#elif MSVC_VERSION >= 1400 + +#include +#define HAS_THREAD_FENCE_SUPPORT +#define ThreadFence() MemoryBarrier() + +#else /* Unsafe fallback — no barrier */ + +#define ThreadFence() + +#endif + +#endif diff --git a/src/thirdparty/SheenBidi/Source/ThreadLocalStorage.h b/src/thirdparty/SheenBidi/Source/ThreadLocalStorage.h new file mode 100644 index 000000000..c05ed9135 --- /dev/null +++ b/src/thirdparty/SheenBidi/Source/ThreadLocalStorage.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2025 Muhammad Tayyab Akram + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _SB_INTERNAL_THREAD_LOCAL_STORAGE_H +#define _SB_INTERNAL_THREAD_LOCAL_STORAGE_H + +#include + +#include "SBBase.h" + +/* Detect C11 support */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) +#define USE_C11_THREAD_LOCAL + +/* Detect GCC thread-local support (available since GCC 3.3) */ +#elif GCC_VERSION >= 303 +#define USE_GNUC_THREAD_LOCAL + +/* Detect Clang thread-local support (available since Clang 1.0) */ +#elif CLANG_VERSION >= 100 +#define USE_CLANG_THREAD_LOCAL + +/* Detect MSVC thread-local support (available since MSVC 2005) */ +#elif MSVC_VERSION >= 1400 +#define USE_MSVC_THREAD_LOCAL + +/* Check for pthread availability */ +#elif defined(_POSIX_THREADS) || defined(__unix__) || defined(__unix) || defined(unix) \ + || (defined(__APPLE__) && defined(__MACH__)) || defined(__linux__) +#define USE_PTHREAD_KEY + +/* Check for Windows availability */ +#elif defined(_WIN32) +#define USE_WIN_TLS + +#endif + +/* Define data type for thread local storage. */ +#ifdef USE_C11_THREAD_LOCAL + +#define HAS_TLS_SUPPORT +#define ThreadLocalStorage _Thread_local void * + +#elif defined(USE_GNUC_THREAD_LOCAL) || defined(USE_CLANG_THREAD_LOCAL) + +#define HAS_TLS_SUPPORT +#define ThreadLocalStorage __thread void * + +#elif defined(USE_MSVC_THREAD_LOCAL) + +#define HAS_TLS_SUPPORT +#define ThreadLocalStorage __declspec(thread) void * + +#elif defined(USE_PTHREAD_KEY) + +#include +#define HAS_TLS_SUPPORT +typedef pthread_key_t ThreadLocalStorage; + +#elif defined(USE_WIN_TLS) + +#include +#define HAS_TLS_SUPPORT +typedef DWORD ThreadLocalStorage; + +#else + +typedef void *ThreadLocalStorage; + +#endif + +/* Define functions for thread local storage. */ +#ifdef USE_PTHREAD_KEY + +#define ThreadLocalStorageInitialize(tls) pthread_key_create(&(tls), NULL) +#define ThreadLocalStorageGet(tls) pthread_getspecific(tls) +#define ThreadLocalStorageSet(tls, value) pthread_setspecific(tls, value) +#define ThreadLocalStorageFinalize(tls) pthread_key_delete(tls) + +#elif defined(USE_WIN_TLS) + +#define ThreadLocalStorageInitialize(tls) ((tls) = TlsAlloc()) +#define ThreadLocalStorageGet(tls) TlsGetValue(tls) +#define ThreadLocalStorageSet(tls, value) TlsSetValue(tls, value) +#define ThreadLocalStorageFinalize(tls) TlsFree(tls) + +#else + +#define ThreadLocalStorageInitialize(tls) ((tls) = NULL) +#define ThreadLocalStorageGet(tls) (tls) +#define ThreadLocalStorageSet(tls, value) ((tls) = (value)) +#define ThreadLocalStorageFinalize(tls) + +#endif + +#endif diff --git a/src/thirdparty/freetype2/FTL.TXT b/src/thirdparty/freetype2/FTL.TXT deleted file mode 100644 index c406d150f..000000000 --- a/src/thirdparty/freetype2/FTL.TXT +++ /dev/null @@ -1,169 +0,0 @@ - The FreeType Project LICENSE - ---------------------------- - - 2006-Jan-27 - - Copyright 1996-2002, 2006 by - David Turner, Robert Wilhelm, and Werner Lemberg - - - -Introduction -============ - - The FreeType Project is distributed in several archive packages; - some of them may contain, in addition to the FreeType font engine, - various tools and contributions which rely on, or relate to, the - FreeType Project. - - This license applies to all files found in such packages, and - which do not fall under their own explicit license. The license - affects thus the FreeType font engine, the test programs, - documentation and makefiles, at the very least. - - This license was inspired by the BSD, Artistic, and IJG - (Independent JPEG Group) licenses, which all encourage inclusion - and use of free software in commercial and freeware products - alike. As a consequence, its main points are that: - - o We don't promise that this software works. However, we will be - interested in any kind of bug reports. (`as is' distribution) - - o You can use this software for whatever you want, in parts or - full form, without having to pay us. (`royalty-free' usage) - - o You may not pretend that you wrote this software. If you use - it, or only parts of it, in a program, you must acknowledge - somewhere in your documentation that you have used the - FreeType code. (`credits') - - We specifically permit and encourage the inclusion of this - software, with or without modifications, in commercial products. - We disclaim all warranties covering The FreeType Project and - assume no liability related to The FreeType Project. - - - Finally, many people asked us for a preferred form for a - credit/disclaimer to use in compliance with this license. We thus - encourage you to use the following text: - - """ - Portions of this software are copyright © The FreeType - Project (www.freetype.org). All rights reserved. - """ - - Please replace with the value from the FreeType version you - actually use. - - -Legal Terms -=========== - -0. Definitions --------------- - - Throughout this license, the terms `package', `FreeType Project', - and `FreeType archive' refer to the set of files originally - distributed by the authors (David Turner, Robert Wilhelm, and - Werner Lemberg) as the `FreeType Project', be they named as alpha, - beta or final release. - - `You' refers to the licensee, or person using the project, where - `using' is a generic term including compiling the project's source - code as well as linking it to form a `program' or `executable'. - This program is referred to as `a program using the FreeType - engine'. - - This license applies to all files distributed in the original - FreeType Project, including all source code, binaries and - documentation, unless otherwise stated in the file in its - original, unmodified form as distributed in the original archive. - If you are unsure whether or not a particular file is covered by - this license, you must contact us to verify this. - - The FreeType Project is copyright (C) 1996-2000 by David Turner, - Robert Wilhelm, and Werner Lemberg. All rights reserved except as - specified below. - -1. No Warranty --------------- - - THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY - KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO - USE, OF THE FREETYPE PROJECT. - -2. Redistribution ------------------ - - This license grants a worldwide, royalty-free, perpetual and - irrevocable right and license to use, execute, perform, compile, - display, copy, create derivative works of, distribute and - sublicense the FreeType Project (in both source and object code - forms) and derivative works thereof for any purpose; and to - authorize others to exercise some or all of the rights granted - herein, subject to the following conditions: - - o Redistribution of source code must retain this license file - (`FTL.TXT') unaltered; any additions, deletions or changes to - the original files must be clearly indicated in accompanying - documentation. The copyright notices of the unaltered, - original files must be preserved in all copies of source - files. - - o Redistribution in binary form must provide a disclaimer that - states that the software is based in part of the work of the - FreeType Team, in the distribution documentation. We also - encourage you to put an URL to the FreeType web page in your - documentation, though this isn't mandatory. - - These conditions apply to any software derived from or based on - the FreeType Project, not just the unmodified files. If you use - our work, you must acknowledge us. However, no fee need be paid - to us. - -3. Advertising --------------- - - Neither the FreeType authors and contributors nor you shall use - the name of the other for commercial, advertising, or promotional - purposes without specific prior written permission. - - We suggest, but do not require, that you use one or more of the - following phrases to refer to this software in your documentation - or advertising materials: `FreeType Project', `FreeType Engine', - `FreeType library', or `FreeType Distribution'. - - As you have not signed this license, you are not required to - accept it. However, as the FreeType Project is copyrighted - material, only this license, or another one contracted with the - authors, grants you the right to use, distribute, and modify it. - Therefore, by using, distributing, or modifying the FreeType - Project, you indicate that you understand and accept all the terms - of this license. - -4. Contacts ------------ - - There are two mailing lists related to FreeType: - - o freetype@nongnu.org - - Discusses general use and applications of FreeType, as well as - future and wanted additions to the library and distribution. - If you are looking for support, start in this list if you - haven't found anything to help you in the documentation. - - o freetype-devel@nongnu.org - - Discusses bugs, as well as engine internals, design issues, - specific licenses, porting, etc. - - Our home page can be found at - - https://www.freetype.org - - ---- end of FTL.TXT --- diff --git a/src/thirdparty/freetype2/LICENSE.TXT b/src/thirdparty/freetype2/LICENSE.TXT index af5a1c50f..0f9df2177 100644 --- a/src/thirdparty/freetype2/LICENSE.TXT +++ b/src/thirdparty/freetype2/LICENSE.TXT @@ -1,39 +1,47 @@ +FREETYPE LICENSES +----------------- -The FreeType 2 font engine is copyrighted work and cannot be used -legally without a software license. In order to make this project -usable to a vast majority of developers, we distribute it under two +The FreeType 2 font engine is copyrighted work and cannot be used +legally without a software license. In order to make this project +usable to a vast majority of developers, we distribute it under two mutually exclusive open-source licenses. -This means that *you* must choose *one* of the two licenses described -below, then obey all its terms and conditions when using FreeType 2 in +This means that *you* must choose *one* of the two licenses described +below, then obey all its terms and conditions when using FreeType 2 in any of your projects or products. - - The FreeType License, found in the file `FTL.TXT', which is similar - to the original BSD license *with* an advertising clause that forces - you to explicitly cite the FreeType project in your product's - documentation. All details are in the license file. This license - is suited to products which don't use the GNU General Public - License. + - The FreeType License, found in the file `docs/FTL.TXT`, which is + similar to the original BSD license *with* an advertising clause + that forces you to explicitly cite the FreeType project in your + product's documentation. All details are in the license file. + This license is suited to products which don't use the GNU General + Public License. - Note that this license is compatible to the GNU General Public + Note that this license is compatible to the GNU General Public License version 3, but not version 2. - - The GNU General Public License version 2, found in `GPLv2.TXT' (any - later version can be used also), for programs which already use the - GPL. Note that the FTL is incompatible with GPLv2 due to its - advertisement clause. + - The GNU General Public License version 2, found in + `docs/GPLv2.TXT` (any later version can be used also), for + programs which already use the GPL. Note that the FTL is + incompatible with GPLv2 due to its advertisement clause. -The contributed BDF and PCF drivers come with a license similar to that -of the X Window System. It is compatible to the above two licenses (see -file src/bdf/README and src/pcf/README). The same holds for the files -`fthash.c' and `fthash.h'; their code was part of the BDF driver in -earlier FreeType versions. +The contributed BDF and PCF drivers come with a license similar to +that of the X Window System. It is compatible to the above two +licenses (see files `src/bdf/README` and `src/pcf/README`). The same +holds for the source code files `src/base/fthash.c` and +`include/freetype/internal/fthash.h`; they were part of the BDF driver +in earlier FreeType versions. -The gzip module uses the zlib license (see src/gzip/zlib.h) which too is -compatible to the above two licenses. +The gzip module uses the zlib license (see `src/gzip/zlib.h`) which +too is compatible to the above two licenses. -The MD5 checksum support (only used for debugging in development builds) -is in the public domain. +The files `src/autofit/ft-hb-ft.c`, `src/autofit/ft-hb-decls.h`, +`src/autofit/ft-hb-types.h`, and `src/autofit/hb-script-list.h` +contain code taken (almost) verbatim from the HarfBuzz library, which +uses the 'Old MIT' license compatible to the above two licenses. + +The MD5 checksum support (only used for debugging in development +builds) is in the public domain. --- end of LICENSE.TXT --- diff --git a/src/thirdparty/freetype2/include/dlg/dlg.h b/src/thirdparty/freetype2/include/dlg/dlg.h new file mode 100644 index 000000000..fa10730e8 --- /dev/null +++ b/src/thirdparty/freetype2/include/dlg/dlg.h @@ -0,0 +1,290 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#ifndef INC_DLG_DLG_H_ +#define INC_DLG_DLG_H_ + +#include +#include +#include +#include +#include + +// Hosted at https://github.com/nyorain/dlg. +// There are examples and documentation. +// Issue reports and contributions appreciated. + +// - CONFIG - +// Define this macro to make all dlg macros have no effect at all +// #define DLG_DISABLE + +// the log/assertion levels below which logs/assertions are ignored +// defaulted depending on the NDEBUG macro +#ifndef DLG_LOG_LEVEL + #ifdef NDEBUG + #define DLG_LOG_LEVEL dlg_level_warn + #else + #define DLG_LOG_LEVEL dlg_level_trace + #endif +#endif + +#ifndef DLG_ASSERT_LEVEL + #ifdef NDEBUG + #define DLG_ASSERT_LEVEL dlg_level_warn + #else + #define DLG_ASSERT_LEVEL dlg_level_trace + #endif +#endif + +// the assert level of dlg_assert +#ifndef DLG_DEFAULT_ASSERT + #define DLG_DEFAULT_ASSERT dlg_level_error +#endif + +// evaluated to the 'file' member in dlg_origin +#ifndef DLG_FILE + #define DLG_FILE dlg__strip_root_path(__FILE__, DLG_BASE_PATH) + + // the base path stripped from __FILE__. If you don't override DLG_FILE set this to + // the project root to make 'main.c' from '/some/bullshit/main.c' + #ifndef DLG_BASE_PATH + #define DLG_BASE_PATH "" + #endif +#endif + +// Default tags applied to all logs/assertions (in the defining file). +// Must be in format ```#define DLG_DEFAULT_TAGS "tag1", "tag2"``` +// or just nothing (as defaulted here) +#ifndef DLG_DEFAULT_TAGS + #define DLG_DEFAULT_TAGS_TERM NULL +#else + #define DLG_DEFAULT_TAGS_TERM DLG_DEFAULT_TAGS, NULL +#endif + +// The function used for formatting. Can have any signature, but must be callable with +// the arguments the log/assertions macros are called with. Must return a const char* +// that will not be freed by dlg, the formatting function must keep track of it. +// The formatting function might use dlg_thread_buffer or a custom owned buffer. +// The returned const char* has to be valid until the dlg log/assertion ends. +// Usually a c function with ... (i.e. using va_list) or a variadic c++ template do +// allow formatting. +#ifndef DLG_FMT_FUNC + #define DLG_FMT_FUNC dlg__printf_format +#endif + +// Only overwrite (i.e. predefine) this if you know what you are doing. +// On windows this is used to add the dllimport specified. +// If you are using the static version of dlg (on windows) define +// DLG_STATIC before including dlg.h +#ifndef DLG_API + #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(DLG_STATIC) + #define DLG_API __declspec(dllimport) + #else + #define DLG_API + #endif +#endif + +// This macro is used when an assertion fails. It gets the source expression +// and can return an alternative (that must stay alive). +// Mainly useful to execute something on failed assertion. +#ifndef DLG_FAILED_ASSERTION_TEXT + #define DLG_FAILED_ASSERTION_TEXT(x) x +#endif + +// - utility - +// two methods needed since cplusplus does not support compound literals +// and c does not support uniform initialization/initializer lists +#ifdef __cplusplus + #include + #define DLG_CREATE_TAGS(...) std::initializer_list \ + {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}.begin() +#else + #define DLG_CREATE_TAGS(...) (const char* const[]) {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL} +#endif + +#ifdef __GNUC__ + #define DLG_PRINTF_ATTRIB(a, b) __attribute__ ((format (printf, a, b))) +#else + #define DLG_PRINTF_ATTRIB(a, b) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +// Represents the importance of a log/assertion call. +enum dlg_level { + dlg_level_trace = 0, // temporary used debug, e.g. to check if control reaches function + dlg_level_debug, // general debugging, prints e.g. all major events + dlg_level_info, // general useful information + dlg_level_warn, // warning, something went wrong but might have no (really bad) side effect + dlg_level_error, // something really went wrong; expect serious issues + dlg_level_fatal // critical error; application is likely to crash/exit +}; + +// Holds various information associated with a log/assertion call. +// Forwarded to the output handler. +struct dlg_origin { + const char* file; + unsigned int line; + const char* func; + enum dlg_level level; + const char** tags; // null-terminated + const char* expr; // assertion expression, otherwise null +}; + +// Type of the output handler, see dlg_set_handler. +typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string, void* data); + +#ifndef DLG_DISABLE + // Tagged/Untagged logging with variable level + // Tags must always be in the format `("tag1", "tag2")` (including brackets) + // Example usages: + // dlg_log(dlg_level_warning, "test 1") + // dlg_logt(("tag1, "tag2"), dlg_level_debug, "test %d", 2) + #define dlg_log(level, ...) if(level >= DLG_LOG_LEVEL) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), NULL) + #define dlg_logt(level, tags, ...) if(level >= DLG_LOG_LEVEL) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), NULL) + + // Dynamic level assert macros in various versions for additional arguments + // Example usages: + // dlg_assertl(dlg_level_warning, data != nullptr); + // dlg_assertlt(("tag1, "tag2"), dlg_level_trace, data != nullptr); + // dlg_asserttlm(("tag1), dlg_level_warning, data != nullptr, "Data must not be null"); + // dlg_assertlm(dlg_level_error, data != nullptr, "Data must not be null"); + #define dlg_assertl(level, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, \ + DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertlt(level, tags, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, \ + DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertlm(level, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \ + DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr)) + #define dlg_assertltm(level, tags, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \ + dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, \ + __func__, DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr)) + + #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) {\ + if(level >= DLG_ASSERT_LEVEL) \ + dlg__do_log(level, tags, DLG_FILE, __LINE__, __func__, msg, \ + DLG_FAILED_ASSERTION_TEXT(#expr)); \ + code; \ + } (void) NULL + + // - Private interface: not part of the abi/api but needed in macros - + // Formats the given format string and arguments as printf would, uses the thread buffer. + DLG_API const char* dlg__printf_format(const char* format, ...) DLG_PRINTF_ATTRIB(1, 2); + DLG_API void dlg__do_log(enum dlg_level lvl, const char* const*, const char*, int, + const char*, const char*, const char*); + DLG_API const char* dlg__strip_root_path(const char* file, const char* base); + +#else // DLG_DISABLE + + #define dlg_log(level, ...) + #define dlg_logt(level, tags, ...) + + #define dlg_assertl(level, expr) // assert without tags/message + #define dlg_assertlt(level, tags, expr) // assert with tags + #define dlg_assertlm(level, expr, ...) // assert with message + #define dlg_assertltm(level, tags, expr, ...) // assert with tags & message + + #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) { code; } (void) NULL +#endif // DLG_DISABLE + +// The API below is independent from DLG_DISABLE + +// Sets the handler that is responsible for formatting and outputting log calls. +// This function is not thread safe and the handler is set globally. +// The handler itself must not change dlg tags or call a dlg macro (if it +// does so, the provided string or tags array in 'origin' might get invalid). +// The handler can also be used for various other things such as dealing +// with failed assertions or filtering calls based on the passed tags. +// The default handler is dlg_default_output (see its doc for more info). +// If using c++ make sure the registered handler cannot throw e.g. by +// wrapping everything into a try-catch blog. +DLG_API void dlg_set_handler(dlg_handler handler, void* data); + +// The default output handler. +// Only use this to reset the output handler, prefer to use +// dlg_generic_output (from output.h) which this function simply calls. +// It also flushes the stream used and correctly outputs even from multiple threads. +DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*); + +// Returns the currently active dlg handler and sets `data` to +// its user data pointer. `data` must not be NULL. +// Useful to create handler chains. +// This function is not threadsafe, i.e. retrieving the handler while +// changing it from another thread is unsafe. +// See `dlg_set_handler`. +DLG_API dlg_handler dlg_get_handler(void** data); + +// Adds the given tag associated with the given function to the thread specific list. +// If func is not NULL the tag will only applied to calls from the same function. +// Remove the tag again calling dlg_remove_tag (with exactly the same pointers!). +// Does not check if the tag is already present. +DLG_API void dlg_add_tag(const char* tag, const char* func); + +// Removes a tag added with dlg_add_tag (has no effect for tags no present). +// The pointers must be exactly the same pointers that were supplied to dlg_add_tag, +// this function will not check using strcmp. When the same tag/func combination +// is added multiple times, this function remove exactly one candidate, it is +// undefined which. Returns whether a tag was found (and removed). +DLG_API bool dlg_remove_tag(const char* tag, const char* func); + +// Returns the thread-specific buffer and its size for dlg. +// The buffer should only be used by formatting functions. +// The buffer can be reallocated and the size changed, just make sure +// to update both values correctly. +DLG_API char** dlg_thread_buffer(size_t** size); + +// Untagged leveled logging +#define dlg_trace(...) dlg_log(dlg_level_trace, __VA_ARGS__) +#define dlg_debug(...) dlg_log(dlg_level_debug, __VA_ARGS__) +#define dlg_info(...) dlg_log(dlg_level_info, __VA_ARGS__) +#define dlg_warn(...) dlg_log(dlg_level_warn, __VA_ARGS__) +#define dlg_error(...) dlg_log(dlg_level_error, __VA_ARGS__) +#define dlg_fatal(...) dlg_log(dlg_level_fatal, __VA_ARGS__) + +// Tagged leveled logging +#define dlg_tracet(tags, ...) dlg_logt(dlg_level_trace, tags, __VA_ARGS__) +#define dlg_debugt(tags, ...) dlg_logt(dlg_level_debug, tags, __VA_ARGS__) +#define dlg_infot(tags, ...) dlg_logt(dlg_level_info, tags, __VA_ARGS__) +#define dlg_warnt(tags, ...) dlg_logt(dlg_level_warn, tags, __VA_ARGS__) +#define dlg_errort(tags, ...) dlg_logt(dlg_level_error, tags, __VA_ARGS__) +#define dlg_fatalt(tags, ...) dlg_logt(dlg_level_fatal, tags, __VA_ARGS__) + +// Assert macros useing DLG_DEFAULT_ASSERT as level +#define dlg_assert(expr) dlg_assertl(DLG_DEFAULT_ASSERT, expr) +#define dlg_assertt(tags, expr) dlg_assertlt(DLG_DEFAULT_ASSERT, tags, expr) +#define dlg_assertm(expr, ...) dlg_assertlm(DLG_DEFAULT_ASSERT, expr, __VA_ARGS__) +#define dlg_asserttm(tags, expr, ...) dlg_assertltm(DLG_DEFAULT_ASSERT, tags, expr, __VA_ARGS__) + +// If (expr) does not evaluate to true, always executes 'code' (no matter what +// DLG_ASSERT_LEVEL is or if dlg is disabled or not). +// When dlg is enabled and the level is greater or equal to DLG_ASSERT_LEVEL, +// logs the failed assertion. +// Example usages: +// dlg_assertl_or(dlg_level_warn, data != nullptr, return); +// dlg_assertlm_or(dlg_level_fatal, data != nullptr, return, "Data must not be null"); +// dlg_assert_or(data != nullptr, logError(); return false); +#define dlg_assertltm_or(level, tags, expr, code, ...) dlg__assert_or(level, \ + DLG_CREATE_TAGS tags, expr, code, DLG_FMT_FUNC(__VA_ARGS__)) +#define dlg_assertlm_or(level, expr, code, ...) dlg__assert_or(level, \ + DLG_CREATE_TAGS(NULL), expr, code, DLG_FMT_FUNC(__VA_ARGS__)) +#define dlg_assertl_or(level, expr, code) dlg__assert_or(level, \ + DLG_CREATE_TAGS(NULL), expr, code, NULL) + +#define dlg_assert_or(expr, code) dlg_assertl_or(DLG_DEFAULT_ASSERT, expr, code) +#define dlg_assertm_or(expr, code, ...) dlg_assertlm_or(DLG_DEFAULT_ASSERT, expr, code, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif // header guard diff --git a/src/thirdparty/freetype2/include/dlg/output.h b/src/thirdparty/freetype2/include/dlg/output.h new file mode 100644 index 000000000..453e4a561 --- /dev/null +++ b/src/thirdparty/freetype2/include/dlg/output.h @@ -0,0 +1,172 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#ifndef INC_DLG_OUTPUT_H_ +#define INC_DLG_OUTPUT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Text style +enum dlg_text_style { + dlg_text_style_reset = 0, + dlg_text_style_bold = 1, + dlg_text_style_dim = 2, + dlg_text_style_italic = 3, + dlg_text_style_underline = 4, + dlg_text_style_blink = 5, + dlg_text_style_rblink = 6, + dlg_text_style_reversed = 7, + dlg_text_style_conceal = 8, + dlg_text_style_crossed = 9, + dlg_text_style_none, +}; + +// Text color +enum dlg_color { + dlg_color_black = 0, + dlg_color_red, + dlg_color_green, + dlg_color_yellow, + dlg_color_blue, + dlg_color_magenta, + dlg_color_cyan, + dlg_color_gray, + dlg_color_reset = 9, + + dlg_color_black2 = 60, + dlg_color_red2, + dlg_color_green2, + dlg_color_yellow2, + dlg_color_blue2, + dlg_color_magenta2, + dlg_color_cyan2, + dlg_color_gray2, + + dlg_color_none = 69, +}; + +struct dlg_style { + enum dlg_text_style style; + enum dlg_color fg; + enum dlg_color bg; +}; + +// Like fprintf but fixes utf-8 output to console on windows. +// On non-windows sytems just uses the corresponding standard library +// functions. On windows, if dlg was compiled with the win_console option, +// will first try to output it in a way that allows the default console +// to display utf-8. If that fails, will fall back to the standard +// library functions. +DLG_API int dlg_fprintf(FILE* stream, const char* format, ...) DLG_PRINTF_ATTRIB(2, 3); +DLG_API int dlg_vfprintf(FILE* stream, const char* format, va_list list); + +// Like dlg_printf, but also applies the given style to this output. +// The style will always be applied (using escape sequences), independent of the given stream. +// On windows escape sequences don't work out of the box, see dlg_win_init_ansi(). +DLG_API int dlg_styled_fprintf(FILE* stream, struct dlg_style style, + const char* format, ...) DLG_PRINTF_ATTRIB(3, 4); + +// Features to output from the generic output handler. +// Some features might have only an effect in the specializations. +enum dlg_output_feature { + dlg_output_tags = 1, // output tags list + dlg_output_time = 2, // output time of log call (hour:minute:second) + dlg_output_style = 4, // whether to use the supplied styles + dlg_output_func = 8, // output function + dlg_output_file_line = 16, // output file:line, + dlg_output_newline = 32, // output a newline at the end + dlg_output_threadsafe = 64, // locks stream before printing + dlg_output_time_msecs = 128 // output micro seconds (ms on windows) +}; + +// The default level-dependent output styles. The array values represent the styles +// to be used for the associated level (i.e. [0] for trace level). +DLG_API extern const struct dlg_style dlg_default_output_styles[6]; + +// Generic output function. Used by the default output handler and might be useful +// for custom output handlers (that don't want to manually format the output). +// Will call the given output func with the given data (and format + args to print) +// for everything it has to print in printf format. +// See also the *_stream and *_buf specializations for common usage. +// The given output function must not be NULL. +typedef void(*dlg_generic_output_handler)(void* data, const char* format, ...); +DLG_API void dlg_generic_output(dlg_generic_output_handler output, void* data, + unsigned int features, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); + +// Generic output function, using a format string instead of feature flags. +// Use following conversion characters: +// %h - output the time in H:M:S format +// %m - output the time in milliseconds +// %t - output the full list of tags, comma separated +// %f - output the function name noted in the origin +// %o - output the file:line of the origin +// %s - print the appropriate style escape sequence. +// %r - print the escape sequence to reset the style. +// %c - The content of the log/assert +// %% - print the '%' character +// Only the above specified conversion characters are valid, the rest are +// written as it is. +DLG_API void dlg_generic_outputf(dlg_generic_output_handler output, void* data, + const char* format_string, const struct dlg_origin* origin, + const char* string, const struct dlg_style styles[6]); + +// Generic output function. Used by the default output handler and might be useful +// for custom output handlers (that don't want to manually format the output). +// If stream is NULL uses stdout. +// Automatically uses dlg_fprintf to assure correct utf-8 even on windows consoles. +// Locks the stream (i.e. assures threadsafe access) when the associated feature +// is passed (note that stdout/stderr might still mix from multiple threads). +DLG_API void dlg_generic_output_stream(FILE* stream, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); +DLG_API void dlg_generic_outputf_stream(FILE* stream, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6], bool lock_stream); + +// Generic output function (see dlg_generic_output) that uses a buffer instead of +// a stream. buf must at least point to *size bytes. Will set *size to the number +// of bytes written (capped to the given size), if buf == NULL will set *size +// to the needed size. The size parameter must not be NULL. +DLG_API void dlg_generic_output_buf(char* buf, size_t* size, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); +DLG_API void dlg_generic_outputf_buf(char* buf, size_t* size, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]); + +// Returns if the given stream is a tty. Useful for custom output handlers +// e.g. to determine whether to use color. +// NOTE: Due to windows limitations currently returns false for wsl ttys. +DLG_API bool dlg_is_tty(FILE* stream); + +// Returns the null-terminated escape sequence for the given style into buf. +// Undefined behvaiour if any member of style has a value outside its enum range (will +// probably result in a buffer overflow or garbage being printed). +// If all member of style are 'none' will simply nullterminate the first buf char. +DLG_API void dlg_escape_sequence(struct dlg_style style, char buf[12]); + +// The reset style escape sequence. +DLG_API extern const char* const dlg_reset_sequence; + +// Just returns true without other effect on non-windows systems or if dlg +// was compiled without the win_console option. +// On windows tries to set the console mode to ansi to make escape sequences work. +// This works only on newer windows 10 versions. Returns false on error. +// Only the first call to it will have an effect, following calls just return the result. +// The function is threadsafe. Automatically called by the default output handler. +// This will only be able to set the mode for the stdout and stderr consoles, so +// other streams to consoles will still not work. +DLG_API bool dlg_win_init_ansi(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // header guard diff --git a/src/thirdparty/freetype2/include/freetype/config/ftconfig.h b/src/thirdparty/freetype2/include/freetype/config/ftconfig.h index 946660337..d66c5df99 100644 --- a/src/thirdparty/freetype2/include/freetype/config/ftconfig.h +++ b/src/thirdparty/freetype2/include/freetype/config/ftconfig.h @@ -4,7 +4,7 @@ * * ANSI-specific configuration file (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -41,533 +41,9 @@ #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 - * `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 - - - /* `FT_UNUSED` indicates 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( __MWERKS__ ) && defined( macintosh ) ) - /* No Carbon frameworks for 64bit 10.4.x. */ - /* `AvailabilityMacros.h` is available since Mac OS X 10.2, */ - /* so guess the system version by maximum errno before inclusion. */ -#include -#ifdef ECANCELED /* defined since 10.2 */ -#include "AvailabilityMacros.h" -#endif -#if defined( __LP64__ ) && \ - ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) -#undef FT_MACINTOSH -#endif - -#elif defined( __SC__ ) || defined( __MRC__ ) - /* Classic MacOS compilers */ -#include "ConditionalMacros.h" -#if TARGET_OS_MAC -#define FT_MACINTOSH 1 -#endif - -#endif - - - /* Fix compiler warning with sgi compiler. */ -#if defined( __sgi ) && !defined( __GNUC__ ) -#if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) -#pragma set woff 3505 -#endif -#endif - - - /************************************************************************** - * - * @section: - * basic_types - * - */ - - - /************************************************************************** - * - * @type: - * FT_Int16 - * - * @description: - * A typedef for a 16bit signed integer type. - */ - typedef signed short FT_Int16; - - - /************************************************************************** - * - * @type: - * FT_UInt16 - * - * @description: - * A typedef for a 16bit unsigned integer type. - */ - typedef unsigned short FT_UInt16; - - /* */ - - - /* this #if 0 ... #endif clause is for documentation purposes */ -#if 0 - - /************************************************************************** - * - * @type: - * FT_Int32 - * - * @description: - * A typedef for a 32bit signed integer type. The size depends on the - * configuration. - */ - typedef signed XXX FT_Int32; - - - /************************************************************************** - * - * @type: - * FT_UInt32 - * - * A typedef for a 32bit unsigned integer type. The size depends on the - * configuration. - */ - typedef unsigned XXX FT_UInt32; - - - /************************************************************************** - * - * @type: - * FT_Int64 - * - * A typedef for a 64bit signed integer type. The size depends on the - * configuration. Only defined if there is real 64bit support; - * otherwise, it gets emulated with a structure (if necessary). - */ - typedef signed XXX FT_Int64; - - - /************************************************************************** - * - * @type: - * FT_UInt64 - * - * A typedef for a 64bit unsigned integer type. The size depends on the - * configuration. Only defined if there is real 64bit support; - * otherwise, it gets emulated with a structure (if necessary). - */ - typedef unsigned XXX FT_UInt64; - - /* */ - -#endif - -#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 -#define FT_UINT64 unsigned long - - /************************************************************************** - * - * A 64-bit data type may create compilation problems if you compile in - * strict ANSI mode. To avoid them, we disable other 64-bit data types if - * `__STDC__` is defined. You can however ignore this rule by defining the - * `FT_CONFIG_OPTION_FORCE_INT64` configuration macro. - */ -#elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) - -#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L - -#define FT_LONG64 -#define FT_INT64 long long int -#define FT_UINT64 unsigned long long int - -#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 -#define FT_UINT64 unsigned __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 -#define FT_UINT64 unsigned __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 -#define FT_UINT64 unsigned long long int - -#elif defined( __GNUC__ ) - - /* GCC provides the `long long` type */ -#define FT_LONG64 -#define FT_INT64 long long int -#define FT_UINT64 unsigned long long int - -#endif /* __STDC_VERSION__ >= 199901L */ - -#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ - -#ifdef FT_LONG64 - typedef FT_INT64 FT_Int64; - typedef FT_UINT64 FT_UInt64; -#endif - - -#ifdef _WIN64 - /* only 64bit Windows uses the LLP64 data model, i.e., */ - /* 32bit integers, 64bit pointers */ -#define FT_UINT_TO_POINTER( x ) (void*)(unsigned __int64)(x) -#else -#define FT_UINT_TO_POINTER( x ) (void*)(unsigned long)(x) -#endif - - - /************************************************************************** - * - * miscellaneous - * - */ - - -#define FT_BEGIN_STMNT do { -#define FT_END_STMNT } while ( 0 ) -#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT - - - /* `typeof` condition taken from gnulib's `intprops.h` header file */ -#if ( ( defined( __GNUC__ ) && __GNUC__ >= 2 ) || \ - ( defined( __IBMC__ ) && __IBMC__ >= 1210 && \ - defined( __IBM__TYPEOF__ ) ) || \ - ( defined( __SUNPRO_C ) && __SUNPRO_C >= 0x5110 && !__STDC__ ) ) -#define FT_TYPEOF( type ) ( __typeof__ ( type ) ) -#else -#define FT_TYPEOF( type ) /* empty */ -#endif - - - /* Use `FT_LOCAL` and `FT_LOCAL_DEF` to declare and define, */ - /* respectively, a function that gets used only within the scope of a */ - /* module. Normally, both the header and source code files for such a */ - /* function are within a single module directory. */ - /* */ - /* Intra-module arrays should be tagged with `FT_LOCAL_ARRAY` and */ - /* `FT_LOCAL_ARRAY_DEF`. */ - /* */ -#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 */ - -#define FT_LOCAL_ARRAY( x ) extern const x -#define FT_LOCAL_ARRAY_DEF( x ) const x - - - /* Use `FT_BASE` and `FT_BASE_DEF` to declare and define, respectively, */ - /* functions that are used in more than a single module. In the */ - /* current setup this implies that the declaration is in a header file */ - /* in the `include/freetype/internal` directory, and the function body */ - /* is in a file in `src/base`. */ - /* */ -#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 */ - - - /* When compiling FreeType as a DLL or DSO with hidden visibility */ - /* some systems/compilers need a special attribute 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. */ - /* */ - /* To export a variable, use `FT_EXPORT_VAR`. */ - /* */ -#ifndef FT_EXPORT - -#ifdef FT2_BUILD_LIBRARY - -#if defined( _WIN32 ) && defined( DLL_EXPORT ) -#define FT_EXPORT( x ) __declspec( dllexport ) x -#elif defined( __GNUC__ ) && __GNUC__ >= 4 -#define FT_EXPORT( x ) __attribute__(( visibility( "default" ) )) x -#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 -#define FT_EXPORT( x ) __global x -#elif defined( __cplusplus ) -#define FT_EXPORT( x ) extern "C" x -#else -#define FT_EXPORT( x ) extern x -#endif - -#else - -#if defined( _WIN32 ) && defined( DLL_IMPORT ) -#define FT_EXPORT( x ) __declspec( dllimport ) x -#elif defined( __cplusplus ) -#define FT_EXPORT( x ) extern "C" x -#else -#define FT_EXPORT( x ) extern x -#endif - -#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, */ - /* located in the same source code file as the structure that uses */ - /* it. */ - /* */ - /* FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare */ - /* and define a callback function, respectively, in a similar way */ - /* as FT_BASE and FT_BASE_DEF work. */ - /* */ - /* 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_BASE_CALLBACK -#ifdef __cplusplus -#define FT_BASE_CALLBACK( x ) extern "C" x -#define FT_BASE_CALLBACK_DEF( x ) extern "C" x -#else -#define FT_BASE_CALLBACK( x ) extern x -#define FT_BASE_CALLBACK_DEF( x ) x -#endif -#endif /* FT_BASE_CALLBACK */ - -#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 - +#include +#include +#include #endif /* FTCONFIG_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/config/ftheader.h b/src/thirdparty/freetype2/include/freetype/config/ftheader.h index 696d6ba90..16eab9048 100644 --- a/src/thirdparty/freetype2/include/freetype/config/ftheader.h +++ b/src/thirdparty/freetype2/include/freetype/config/ftheader.h @@ -4,7 +4,7 @@ * * Build macros of the FreeType 2 library. * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -30,10 +30,12 @@ /* 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 */ +#ifndef FT_BEGIN_HEADER +# ifdef __cplusplus +# define FT_BEGIN_HEADER extern "C" { +# else +# define FT_BEGIN_HEADER /* nothing */ +# endif #endif @@ -48,10 +50,12 @@ /* encapsulated in an `extern "C" { .. }` block when included from a */ /* C++ compiler. */ /* */ -#ifdef __cplusplus -#define FT_END_HEADER } -#else -#define FT_END_HEADER /* nothing */ +#ifndef FT_END_HEADER +# ifdef __cplusplus +# define FT_END_HEADER } +# else +# define FT_END_HEADER /* nothing */ +# endif #endif @@ -73,9 +77,16 @@ * 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: + * In addition to the normal scheme of including header files like + * + * ``` + * #include + * #include + * #include + * ``` + * + * it is possible to used named macros instead. They can be used + * directly in `#include` statements as in * * ``` * #include FT_FREETYPE_H @@ -83,13 +94,9 @@ * #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. + * These macros were introduced to overcome the infamous 8.3~naming rule + * required by DOS (and `FT_MULTIPLE_MASTERS_H` is a lot more meaningful + * than `ftmm.h`). * */ @@ -770,6 +777,18 @@ #define FT_COLOR_H + /************************************************************************** + * + * @macro: + * FT_OTSVG_H + * + * @description: + * A macro used in `#include` statements to name the file containing the + * FreeType~2 API which handles the OpenType 'SVG~' glyphs. + */ +#define FT_OTSVG_H + + /* */ /* These header files don't need to be included by the user. */ @@ -797,16 +816,19 @@ #define FT_CACHE_INTERNAL_IMAGE_H FT_CACHE_H #define FT_CACHE_INTERNAL_SBITS_H FT_CACHE_H - - /* - * Include internal headers definitions from `` only when - * building the library. - */ +/* TODO(david): Move this section below to a different header */ #ifdef FT2_BUILD_LIBRARY -#define FT_INTERNAL_INTERNAL_H -#include FT_INTERNAL_INTERNAL_H -#endif /* FT2_BUILD_LIBRARY */ +#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. */ + /* In particular, the warning complains about stuff like `while(0)' */ + /* which is very useful in macro definitions. There is no benefit */ + /* in having it enabled. */ +#pragma warning( disable : 4127 ) + +#endif /* _MSC_VER */ +#endif /* FT2_BUILD_LIBRARY */ #endif /* FTHEADER_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/config/ftmodule.h b/src/thirdparty/freetype2/include/freetype/config/ftmodule.h index 7c603e532..b315baba8 100644 --- a/src/thirdparty/freetype2/include/freetype/config/ftmodule.h +++ b/src/thirdparty/freetype2/include/freetype/config/ftmodule.h @@ -19,14 +19,15 @@ FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, pcf_driver_class ) +FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) FT_USE_MODULE( FT_Module_Class, psaux_module_class ) FT_USE_MODULE( FT_Module_Class, psnames_module_class ) FT_USE_MODULE( FT_Module_Class, pshinter_module_class ) -FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) FT_USE_MODULE( FT_Module_Class, sfnt_module_class ) FT_USE_MODULE( FT_Renderer_Class, ft_smooth_renderer_class ) -FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcd_renderer_class ) -FT_USE_MODULE( FT_Renderer_Class, ft_smooth_lcdv_renderer_class ) -FT_USE_MODULE( FT_Driver_ClassRec, bdf_driver_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_raster1_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_bitmap_sdf_renderer_class ) +FT_USE_MODULE( FT_Renderer_Class, ft_svg_renderer_class ) /* EOF */ diff --git a/src/thirdparty/freetype2/include/freetype/config/ftoption.h b/src/thirdparty/freetype2/include/freetype/config/ftoption.h index 63b122344..0e4c57c61 100644 --- a/src/thirdparty/freetype2/include/freetype/config/ftoption.h +++ b/src/thirdparty/freetype2/include/freetype/config/ftoption.h @@ -4,7 +4,7 @@ * * User-selectable configuration macros (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -42,7 +42,7 @@ FT_BEGIN_HEADER * 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 + * The default FreeType Makefiles use the build directory * `builds/` by default, but you can easily change that for your * own projects. * @@ -105,8 +105,7 @@ FT_BEGIN_HEADER * * ``` * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ - * cff:no-stem-darkening=1 \ - * autofitter:warping=1 + * cff:no-stem-darkening=1 * ``` * */ @@ -121,12 +120,10 @@ FT_BEGIN_HEADER * mitigate color fringes inherent to this technology, you also need to * explicitly set up LCD filtering. * - * Note that this feature is covered by several Microsoft patents and - * should not be activated in any default build of the library. When this - * macro is not defined, FreeType offers alternative LCD rendering - * technology that produces excellent output without LCD filtering. + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. */ -/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ +#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING /************************************************************************** @@ -161,12 +158,12 @@ FT_BEGIN_HEADER /************************************************************************** * - * If this macro is defined, try to use an inlined assembler version of the - * @FT_MulFix function, which is a 'hotspot' when loading and hinting - * glyphs, and which should be executed as fast as possible. + * If this macro is defined, try to use an inlined 64-bit or assembler + * version of the @FT_MulFix function, which is a 'hotspot' when loading + * and hinting glyphs, and which should be executed as fast as possible. * - * Note that if your compiler or CPU is not supported, this will default to - * the standard and portable implementation found in `ftcalc.c`. + * If your compiler is not C99-compliant or CPU assembly is not supported, + * you can disable this option. */ #define FT_CONFIG_OPTION_INLINE_MULFIX @@ -222,6 +219,10 @@ FT_BEGIN_HEADER * If you use a build system like cmake or the `configure` script, * options set by those programs have precedence, overwriting the value * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. */ #define FT_CONFIG_OPTION_SYSTEM_ZLIB @@ -292,6 +293,47 @@ FT_BEGIN_HEADER /* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + /************************************************************************** + * + * HarfBuzz dynamic support. + * + * Define this macro if you want the HarfBuzz library to be loaded at + * runtime instead of being linked to FreeType. + * + * This option has no effect if `FT_CONFIG_OPTION_USE_HARFBUZZ` is not + * defined. + * + * When this option is enabled, FreeType will try to load the HarfBuzz + * library at runtime, using `dlopen` or `LoadLibrary`, depending on the + * platform. On Microsoft platforms, the library name looked up is + * `libharfbuzz-0.dll`. On Apple platforms, the library name looked up + * is `libharfbuzz.0.dylib`. On all other platforms, the library name + * looked up is `libharfbuzz.so.0`. This name can be overridden by + * defining the macro `FT_LIBHARFBUZZ` at FreeType compilation time. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + + /************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BROTLI */ + + /************************************************************************** * * Glyph Postscript Names handling @@ -417,6 +459,23 @@ FT_BEGIN_HEADER /* #define FT_DEBUG_LEVEL_TRACE */ + /************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +/* #define FT_DEBUG_LOGGING */ + + /************************************************************************** * * Autofitter debugging @@ -427,9 +486,9 @@ FT_BEGIN_HEADER * while compiling in 'release' mode): * * ``` - * _af_debug_disable_horz_hints - * _af_debug_disable_vert_hints - * _af_debug_disable_blue_hints + * af_debug_disable_horz_hints_ + * af_debug_disable_vert_hints_ + * af_debug_disable_blue_hints_ * ``` * * Additionally, the following functions provide dumps of various @@ -446,7 +505,7 @@ FT_BEGIN_HEADER * As an argument, they use another global variable: * * ``` - * _af_debug_hints + * af_debug_hints_ * ``` * * Please have a look at the `ftgrid` demo program to see how those @@ -493,6 +552,20 @@ FT_BEGIN_HEADER #undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + /************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + + /************************************************************************** * * Error Strings @@ -526,7 +599,7 @@ FT_BEGIN_HEADER /************************************************************************** * - * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support coloured + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' * module (namely TrueType~& OpenType). */ @@ -536,12 +609,12 @@ FT_BEGIN_HEADER /************************************************************************** * * 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 + * load and enumerate Postscript names of glyphs 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. + * Note that if you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` macro, the 'sfnt' module will + * contain additional code to read the PostScript name table from a font. * * (By default, the module uses 'psnames' to extract glyph names.) */ @@ -613,36 +686,12 @@ FT_BEGIN_HEADER * not) instructions in a certain way so that all TrueType fonts look like * they do in a Windows ClearType (DirectWrite) environment. See [1] for a * technical overview on what this means. See `ttinterp.h` for more - * details on the LEAN option. + * details on this option. * - * There are three possible values. - * - * Value 1: - * This value is associated with the 'Infinality' moniker, contributed by - * an individual nicknamed Infinality with the goal of making TrueType - * fonts render better than on Windows. A high amount of configurability - * and flexibility, down to rules for single glyphs in fonts, but also - * very slow. Its experimental and slow nature and the original - * developer losing interest meant that this option was never enabled in - * default builds. - * - * The corresponding interpreter version is v38. - * - * Value 2: - * The new default mode for the TrueType driver. The Infinality code - * base was stripped to the bare minimum and all configurability removed - * in the name of speed and simplicity. The configurability was mainly - * aimed at legacy fonts like 'Arial', 'Times New Roman', or 'Courier'. - * Legacy fonts are fonts that modify vertical stems to achieve clean - * black-and-white bitmaps. The new mode focuses on applying a minimal - * set of rules to all fonts indiscriminately so that modern and web - * fonts render well while legacy fonts render okay. - * - * The corresponding interpreter version is v40. - * - * Value 3: - * Compile both, making both v38 and v40 available (the latter is the - * default). + * The new default mode focuses on applying a minimal set of rules to all + * fonts indiscriminately so that modern and web fonts render well while + * legacy fonts render okay. The corresponding interpreter version is v40. + * The so-called Infinality mode (v38) is no longer available in FreeType. * * By undefining these, you get rendering behavior like on Windows without * ClearType, i.e., Windows XP without ClearType enabled and Win9x @@ -655,11 +704,9 @@ FT_BEGIN_HEADER * defined. * * [1] - * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + * https://learn.microsoft.com/typography/cleartype/truetypecleartype */ -/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ -#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 -/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING /************************************************************************** @@ -675,7 +722,7 @@ FT_BEGIN_HEADER * flags array which can be used to disambiguate, but old fonts will not * have them. * - * https://www.microsoft.com/typography/otspec/glyf.htm + * https://learn.microsoft.com/typography/opentype/spec/glyf * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html */ #undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED @@ -691,6 +738,24 @@ FT_BEGIN_HEADER #define TT_CONFIG_OPTION_GX_VAR_SUPPORT + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_NO_BORING_EXPANSION` if you want to exclude + * support for 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec + * + * Right now, the following features are covered: + * + * - 'avar' version 2.0 + * + * Most likely, this is a temporary configuration option to be removed in + * the near future, since it is assumed that eventually those features are + * added to the OpenType standard. + */ +/* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + + /************************************************************************** * * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an @@ -717,6 +782,22 @@ FT_BEGIN_HEADER #endif + /************************************************************************** + * + * Option `TT_CONFIG_OPTION_GPOS_KERNING` enables a basic GPOS kerning + * implementation (for TrueType and OpenType fonts only). With this + * defined, FreeType is able to get kerning pair data from the GPOS 'kern' + * feature as well as legacy 'kern' tables; without this defined, FreeType + * will only be able to use legacy 'kern' tables. + * + * Note that FreeType does not support more advanced GPOS layout features; + * even the 'kern' feature implemented here doesn't handle more + * sophisticated kerning variants. Use a higher-level library like + * HarfBuzz instead for that. + */ +/* #define TT_CONFIG_OPTION_GPOS_KERNING */ + + /*************************************************************************/ /*************************************************************************/ /**** ****/ @@ -871,27 +952,11 @@ FT_BEGIN_HEADER * * Compile 'autofit' module with fallback Indic script support, covering * some scripts that the 'latin' submodule of the 'autofit' module doesn't - * (yet) handle. + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. */ +#ifdef AF_CONFIG_OPTION_CJK #define AF_CONFIG_OPTION_INDIC - - - /************************************************************************** - * - * Compile 'autofit' module with warp hinting. The idea of the warping - * code is to slightly scale and shift a glyph within a single dimension so - * that as much of its segments are aligned (more or less) on the grid. To - * find out the optimal scaling and shifting value, various parameter - * combinations are tried and scored. - * - * You can switch warping on and off with the `warping` property of the - * auto-hinter (see file `ftdriver.h` for more information; by default it - * is switched off). - * - * This experimental option is not active if the rendering mode is - * `FT_RENDER_MODE_LIGHT`. - */ -#define AF_CONFIG_OPTION_USE_WARPER +#endif /************************************************************************** @@ -927,21 +992,29 @@ FT_BEGIN_HEADER /* - * The next three macros are defined if native TrueType hinting is + * The next two macros are defined if native TrueType hinting is * requested by the definitions above. Don't change this. */ #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER #define TT_USE_BYTECODE_INTERPRETER - #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING -#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1 -#define TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY -#endif - -#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2 #define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL #endif #endif + + + /* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 #endif @@ -973,8 +1046,8 @@ FT_BEGIN_HEADER #error "Invalid CFF darkening parameters!" #endif -FT_END_HEADER +FT_END_HEADER #endif /* FTOPTION_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/config/ftstdlib.h b/src/thirdparty/freetype2/include/freetype/config/ftstdlib.h index 438b6145d..f846b4456 100644 --- a/src/thirdparty/freetype2/include/freetype/config/ftstdlib.h +++ b/src/thirdparty/freetype2/include/freetype/config/ftstdlib.h @@ -5,7 +5,7 @@ * ANSI-specific library and header configuration file (specification * only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -43,7 +43,8 @@ * * `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. + * platforms the library has been tested on. We also check `ULLONG_MAX` + * to see whether we can use 64-bit `long long` later 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 @@ -66,6 +67,15 @@ #define FT_LONG_MIN LONG_MIN #define FT_LONG_MAX LONG_MAX #define FT_ULONG_MAX ULONG_MAX +#ifdef LLONG_MAX +#define FT_LLONG_MAX LLONG_MAX +#endif +#ifdef LLONG_MIN +#define FT_LLONG_MIN LLONG_MIN +#endif +#ifdef ULLONG_MAX +#define FT_ULLONG_MAX ULLONG_MAX +#endif /************************************************************************** @@ -101,13 +111,13 @@ #include -#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 +#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_snprintf snprintf /************************************************************************** diff --git a/src/thirdparty/freetype2/include/freetype/config/integer-types.h b/src/thirdparty/freetype2/include/freetype/config/integer-types.h new file mode 100644 index 000000000..a0b892ece --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/config/integer-types.h @@ -0,0 +1,277 @@ +/**************************************************************************** + * + * config/integer-types.h + * + * FreeType integer types definitions. + * + * Copyright (C) 1996-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FREETYPE_CONFIG_INTEGER_TYPES_H_ +#define FREETYPE_CONFIG_INTEGER_TYPES_H_ + +FT_BEGIN_HEADER + + /* 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 + +#ifndef FT_SIZEOF_INT + + /* 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 + +#endif /* !defined(FT_SIZEOF_INT) */ + +#ifndef FT_SIZEOF_LONG + + /* 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 + +#endif /* !defined(FT_SIZEOF_LONG) */ + +#ifndef FT_SIZEOF_LONG_LONG + + /* The size of a `long long` type if available */ +#if defined( FT_ULLONG_MAX ) && FT_ULLONG_MAX >= 0xFFFFFFFFFFFFFFFFULL +#define FT_SIZEOF_LONG_LONG ( 64 / FT_CHAR_BIT ) +#else +#define FT_SIZEOF_LONG_LONG 0 +#endif + +#endif /* !defined(FT_SIZEOF_LONG_LONG) */ + + + /************************************************************************** + * + * @section: + * basic_types + * + */ + + + /************************************************************************** + * + * @type: + * FT_Int16 + * + * @description: + * A typedef for a 16bit signed integer type. + */ + typedef signed short FT_Int16; + + + /************************************************************************** + * + * @type: + * FT_UInt16 + * + * @description: + * A typedef for a 16bit unsigned integer type. + */ + typedef unsigned short FT_UInt16; + + /* */ + + + /* this #if 0 ... #endif clause is for documentation purposes */ +#if 0 + + /************************************************************************** + * + * @type: + * FT_Int32 + * + * @description: + * A typedef for a 32bit signed integer type. The size depends on the + * configuration. + */ + typedef signed XXX FT_Int32; + + + /************************************************************************** + * + * @type: + * FT_UInt32 + * + * A typedef for a 32bit unsigned integer type. The size depends on the + * configuration. + */ + typedef unsigned XXX FT_UInt32; + + + /************************************************************************** + * + * @type: + * FT_Int64 + * + * A typedef for a 64bit signed integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef signed XXX FT_Int64; + + + /************************************************************************** + * + * @type: + * FT_UInt64 + * + * A typedef for a 64bit unsigned integer type. The size depends on the + * configuration. Only defined if there is real 64bit support; + * otherwise, it gets emulated with a structure (if necessary). + */ + typedef unsigned XXX FT_UInt64; + + /* */ + +#endif + +#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 integer type */ +#if FT_SIZEOF_LONG == ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long +#define FT_UINT64 unsigned long + +#elif FT_SIZEOF_LONG_LONG >= ( 64 / FT_CHAR_BIT ) + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + + /************************************************************************** + * + * A 64-bit data type may create compilation problems if you compile in + * strict ANSI mode. To avoid them, we disable other 64-bit data types if + * `__STDC__` is defined. You can however ignore this rule by defining the + * `FT_CONFIG_OPTION_FORCE_INT64` configuration macro. + */ +#elif !defined( __STDC__ ) || defined( FT_CONFIG_OPTION_FORCE_INT64 ) + +#if defined( _MSC_VER ) && _MSC_VER >= 900 /* Visual C++ (and Intel C++) */ + + /* this compiler provides the `__int64` type */ +#define FT_INT64 __int64 +#define FT_UINT64 unsigned __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_INT64 __int64 +#define FT_UINT64 unsigned __int64 + +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1100 /* Watcom C++ */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __MWERKS__ ) /* Metrowerks CodeWarrior */ + +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#elif defined( __GNUC__ ) + + /* GCC provides the `long long` type */ +#define FT_INT64 long long int +#define FT_UINT64 unsigned long long int + +#endif /* !__STDC__ */ + +#endif /* FT_SIZEOF_LONG == (64 / FT_CHAR_BIT) */ + +#ifdef FT_INT64 + + typedef FT_INT64 FT_Int64; + typedef FT_UINT64 FT_UInt64; + +# define FT_INT64_ZERO 0 + +#else /* !FT_INT64 */ + + /* we need to emulate 64-bit data types if none are available */ + + typedef struct FT_Int64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_Int64; + + typedef struct FT_UInt64_ + { + FT_UInt32 lo; + FT_UInt32 hi; + + } FT_UInt64; + +# define FT_INT64_ZERO { 0, 0 } + +#endif /* !FT_INT64 */ + +FT_END_HEADER + +#endif /* FREETYPE_CONFIG_INTEGER_TYPES_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/config/mac-support.h b/src/thirdparty/freetype2/include/freetype/config/mac-support.h new file mode 100644 index 000000000..d1b6a9898 --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/config/mac-support.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * config/mac-support.h + * + * Mac/OS X support configuration header. + * + * Copyright (C) 1996-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FREETYPE_CONFIG_MAC_SUPPORT_H_ +#define FREETYPE_CONFIG_MAC_SUPPORT_H_ + + /************************************************************************** + * + * Mac support + * + * This is the only necessary change, so it is defined here instead + * providing a new configuration file. + */ +#if defined( __APPLE__ ) || ( defined( __MWERKS__ ) && defined( macintosh ) ) + /* No Carbon frameworks for 64bit 10.4.x. */ + /* `AvailabilityMacros.h` is available since Mac OS X 10.2, */ + /* so guess the system version by maximum errno before inclusion. */ +#include +#ifdef ECANCELED /* defined since 10.2 */ +#include "AvailabilityMacros.h" +#endif +#if defined( __LP64__ ) && \ + ( MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 ) +#undef FT_MACINTOSH +#endif + +#elif defined( __SC__ ) || defined( __MRC__ ) + /* Classic MacOS compilers */ +#include "ConditionalMacros.h" +#if TARGET_OS_MAC +#define FT_MACINTOSH 1 +#endif + +#endif /* Mac support */ + +#endif /* FREETYPE_CONFIG_MAC_SUPPORT_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/config/public-macros.h b/src/thirdparty/freetype2/include/freetype/config/public-macros.h new file mode 100644 index 000000000..9f28b3947 --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/config/public-macros.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * + * config/public-macros.h + * + * Define a set of compiler macros used in public FreeType headers. + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 definitions in this file are used by the public FreeType headers + * and thus should be considered part of the public API. + * + * Other compiler-specific macro definitions that are not exposed by the + * FreeType API should go into + * `include/freetype/internal/compiler-macros.h` instead. + */ +#ifndef FREETYPE_CONFIG_PUBLIC_MACROS_H_ +#define FREETYPE_CONFIG_PUBLIC_MACROS_H_ + + /* + * `FT_BEGIN_HEADER` and `FT_END_HEADER` might have already been defined + * by `freetype/config/ftheader.h`, but we don't want to include this + * header here, so redefine the macros here only when needed. Their + * definition is very stable, so keeping them in sync with the ones in the + * header should not be a maintenance issue. + */ +#ifndef FT_BEGIN_HEADER +#ifdef __cplusplus +#define FT_BEGIN_HEADER extern "C" { +#else +#define FT_BEGIN_HEADER /* empty */ +#endif +#endif /* FT_BEGIN_HEADER */ + +#ifndef FT_END_HEADER +#ifdef __cplusplus +#define FT_END_HEADER } +#else +#define FT_END_HEADER /* empty */ +#endif +#endif /* FT_END_HEADER */ + + +FT_BEGIN_HEADER + + /* + * Mark a function declaration as public. This ensures it will be + * properly exported to client code. Place this before a function + * declaration. + * + * NOTE: This macro should be considered an internal implementation + * detail, and not part of the FreeType API. It is only defined here + * because it is needed by `FT_EXPORT`. + */ + + /* Visual C, MinGW, Cygwin */ +#if defined( _WIN32 ) || defined( __CYGWIN__ ) + +#if defined( FT2_BUILD_LIBRARY ) && defined( DLL_EXPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllexport ) +#elif defined( DLL_IMPORT ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __declspec( dllimport ) +#endif + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_PUBLIC_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "default" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_PUBLIC_FUNCTION_ATTRIBUTE __global +#endif + + +#ifndef FT_PUBLIC_FUNCTION_ATTRIBUTE +#define FT_PUBLIC_FUNCTION_ATTRIBUTE /* empty */ +#endif + + + /* + * Define a public FreeType API function. This ensures it is properly + * exported or imported at build time. The macro parameter is the + * function's return type as in: + * + * FT_EXPORT( FT_Bool ) + * FT_Object_Method( FT_Object obj, + * ... ); + * + * NOTE: This requires that all `FT_EXPORT` uses are inside + * `FT_BEGIN_HEADER ... FT_END_HEADER` blocks. This guarantees that the + * functions are exported with C linkage, even when the header is included + * by a C++ source file. + */ +#define FT_EXPORT( x ) FT_PUBLIC_FUNCTION_ATTRIBUTE extern x + + + /* + * `FT_UNUSED` indicates that a given parameter is not used -- this is + * only used to get rid of unpleasant compiler warnings. + * + * Technically, this was not meant to be part of the public API, but some + * third-party code depends on it. + */ +#ifndef FT_UNUSED +#define FT_UNUSED( arg ) ( (arg) = (arg) ) +#endif + + + /* + * Support for casts in both C and C++. + */ +#ifdef __cplusplus +#define FT_STATIC_CAST( type, var ) static_cast(var) +#define FT_REINTERPRET_CAST( type, var ) reinterpret_cast(var) + +#define FT_STATIC_BYTE_CAST( type, var ) \ + static_cast( static_cast( var ) ) +#else +#define FT_STATIC_CAST( type, var ) (type)(var) +#define FT_REINTERPRET_CAST( type, var ) (type)(var) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) +#endif + + +FT_END_HEADER + +#endif /* FREETYPE_CONFIG_PUBLIC_MACROS_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/freetype.h b/src/thirdparty/freetype2/include/freetype/freetype.h index a6bb667e3..1e2492358 100644 --- a/src/thirdparty/freetype2/include/freetype/freetype.h +++ b/src/thirdparty/freetype2/include/freetype/freetype.h @@ -4,7 +4,7 @@ * * FreeType high-level API and common types (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,25 +20,44 @@ #define FREETYPE_H_ -#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 " -#error " #include FT_FREETYPE_H" -#endif - - #include #include FT_CONFIG_CONFIG_H -#include FT_TYPES_H -#include FT_ERRORS_H +#include +#include FT_BEGIN_HEADER + /************************************************************************** + * + * @section: + * preamble + * + * @title: + * Preamble + * + * @abstract: + * What FreeType is and isn't + * + * @description: + * FreeType is a library that provides access to glyphs in font files. It + * scales the glyph images and their metrics to a requested size, and it + * rasterizes the glyph images to produce pixel or subpixel alpha coverage + * bitmaps. + * + * Note that FreeType is _not_ a text layout engine. You have to use + * higher-level libraries like HarfBuzz, Pango, or ICU for that. + * + * Note also that FreeType does _not_ perform alpha blending or + * compositing the resulting bitmaps or pixmaps by itself. Use your + * favourite graphics library (for example, Cairo or Skia) to further + * process FreeType's output. + * + */ + + /************************************************************************** * * @section: @@ -51,22 +70,15 @@ FT_BEGIN_HEADER * How client applications should include FreeType header files. * * @description: - * To be as flexible as possible (and for historical reasons), FreeType - * uses a very special inclusion scheme to load header files, for example + * To be as flexible as possible (and for historical reasons), you must + * load file `ft2build.h` first before other header files, for example * * ``` * #include * - * #include FT_FREETYPE_H - * #include FT_OUTLINE_H + * #include + * #include * ``` - * - * A compiler and its preprocessor only needs an include path to find the - * file `ft2build.h`; the exact locations and names of the other FreeType - * header files are hidden by @header_file_macros, loaded by - * `ft2build.h`. The API documentation always gives the header macro - * name needed for a particular function. - * */ @@ -90,6 +102,277 @@ FT_BEGIN_HEADER */ + /************************************************************************** + * + * @section: + * font_testing_macros + * + * @title: + * Font Testing Macros + * + * @abstract: + * Macros to test various properties of fonts. + * + * @description: + * Macros to test the most important font properties. + * + * It is recommended to use these high-level macros instead of directly + * testing the corresponding flags, which are scattered over various + * structures. + * + * @order: + * FT_HAS_HORIZONTAL + * FT_HAS_VERTICAL + * FT_HAS_KERNING + * FT_HAS_FIXED_SIZES + * FT_HAS_GLYPH_NAMES + * FT_HAS_COLOR + * FT_HAS_MULTIPLE_MASTERS + * FT_HAS_SVG + * FT_HAS_SBIX + * FT_HAS_SBIX_OVERLAY + * + * FT_IS_SFNT + * FT_IS_SCALABLE + * FT_IS_FIXED_WIDTH + * FT_IS_CID_KEYED + * FT_IS_TRICKY + * FT_IS_NAMED_INSTANCE + * FT_IS_VARIATION + * + */ + + + /************************************************************************** + * + * @section: + * library_setup + * + * @title: + * Library Setup + * + * @abstract: + * Functions to start and end the usage of the FreeType library. + * + * @description: + * Functions to start and end the usage of the FreeType library. + * + * Note that @FT_Library_Version and @FREETYPE_XXX are of limited use + * because even a new release of FreeType with only documentation + * changes increases the version number. + * + * @order: + * FT_Library + * FT_Init_FreeType + * FT_Done_FreeType + * + * FT_Library_Version + * FREETYPE_XXX + * + */ + + + /************************************************************************** + * + * @section: + * face_creation + * + * @title: + * Face Creation + * + * @abstract: + * Functions to manage fonts. + * + * @description: + * The functions and structures collected in this section operate on + * fonts globally. + * + * @order: + * FT_Face + * FT_FaceRec + * FT_FACE_FLAG_XXX + * FT_STYLE_FLAG_XXX + * + * FT_New_Face + * FT_Done_Face + * FT_Reference_Face + * FT_New_Memory_Face + * FT_Face_Properties + * FT_Open_Face + * FT_Open_Args + * FT_OPEN_XXX + * FT_Parameter + * FT_Attach_File + * FT_Attach_Stream + * + */ + + + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + * @title: + * Sizing and Scaling + * + * @abstract: + * Functions to manage font sizes. + * + * @description: + * The functions and structures collected in this section are related to + * selecting and manipulating the size of a font globally. + * + * @order: + * FT_Size + * FT_SizeRec + * FT_Size_Metrics + * + * FT_Bitmap_Size + * + * FT_Set_Char_Size + * FT_Set_Pixel_Sizes + * FT_Request_Size + * FT_Select_Size + * FT_Size_Request_Type + * FT_Size_RequestRec + * FT_Size_Request + * + * FT_Set_Transform + * FT_Get_Transform + * + */ + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + * @title: + * Glyph Retrieval + * + * @abstract: + * Functions to manage glyphs. + * + * @description: + * The functions and structures collected in this section operate on + * single glyphs, of which @FT_Load_Glyph is most important. + * + * @order: + * FT_GlyphSlot + * FT_GlyphSlotRec + * FT_Glyph_Metrics + * + * FT_Load_Glyph + * FT_LOAD_XXX + * FT_LOAD_TARGET_MODE + * FT_LOAD_TARGET_XXX + * + * FT_Render_Glyph + * FT_Render_Mode + * FT_Get_Kerning + * FT_Kerning_Mode + * FT_Get_Track_Kerning + * + */ + + + /************************************************************************** + * + * @section: + * character_mapping + * + * @title: + * Character Mapping + * + * @abstract: + * Functions to manage character-to-glyph maps. + * + * @description: + * This section holds functions and structures that are related to + * mapping character input codes to glyph indices. + * + * Note that for many scripts the simplistic approach used by FreeType + * of mapping a single character to a single glyph is not valid or + * possible! In general, a higher-level library like HarfBuzz or ICU + * should be used for handling text strings. + * + * @order: + * FT_CharMap + * FT_CharMapRec + * FT_Encoding + * FT_ENC_TAG + * + * FT_Select_Charmap + * FT_Set_Charmap + * FT_Get_Charmap_Index + * + * FT_Get_Char_Index + * FT_Get_First_Char + * FT_Get_Next_Char + * FT_Load_Char + * + */ + + + /************************************************************************** + * + * @section: + * information_retrieval + * + * @title: + * Information Retrieval + * + * @abstract: + * Functions to retrieve font and glyph information. + * + * @description: + * Functions to retrieve font and glyph information. Only some very + * basic data is covered; see also the chapter on the format-specific + * API for more. + * + * + * @order: + * FT_Get_Name_Index + * FT_Get_Glyph_Name + * FT_Get_Postscript_Name + * FT_Get_FSType_Flags + * FT_FSTYPE_XXX + * FT_Get_SubGlyph_Info + * FT_SUBGLYPH_FLAG_XXX + * + */ + + + /************************************************************************** + * + * @section: + * other_api_data + * + * @title: + * Other API Data + * + * @abstract: + * Other structures, enumerations, and macros. + * + * @description: + * Other structures, enumerations, and macros. Deprecated functions are + * also listed here. + * + * @order: + * FT_Face_Internal + * FT_Size_Internal + * FT_Slot_Internal + * + * FT_SubGlyph + * + * FT_HAS_FAST_GLYPHS + * FT_Face_CheckTrueTypePatents + * FT_Face_SetUnpatentedHinting + * + */ + /*************************************************************************/ /*************************************************************************/ @@ -103,165 +386,10 @@ FT_BEGIN_HEADER /************************************************************************** * * @section: - * base_interface - * - * @title: - * Base Interface - * - * @abstract: - * The FreeType~2 base font interface. - * - * @description: - * This section describes the most important public high-level API - * functions of FreeType~2. - * - * @order: - * FT_Library - * FT_Face - * FT_Size - * FT_GlyphSlot - * FT_CharMap - * FT_Encoding - * FT_ENC_TAG - * - * 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_COLOR - * FT_FACE_FLAG_SFNT - * FT_FACE_FLAG_CID_KEYED - * FT_FACE_FLAG_TRICKY - * FT_FACE_FLAG_KERNING - * FT_FACE_FLAG_MULTIPLE_MASTERS - * FT_FACE_FLAG_VARIATION - * FT_FACE_FLAG_GLYPH_NAMES - * FT_FACE_FLAG_EXTERNAL_STREAM - * FT_FACE_FLAG_HINTER - * - * FT_HAS_HORIZONTAL - * FT_HAS_VERTICAL - * FT_HAS_KERNING - * FT_HAS_FIXED_SIZES - * FT_HAS_GLYPH_NAMES - * FT_HAS_COLOR - * FT_HAS_MULTIPLE_MASTERS - * - * FT_IS_SFNT - * FT_IS_SCALABLE - * FT_IS_FIXED_WIDTH - * FT_IS_CID_KEYED - * FT_IS_TRICKY - * FT_IS_NAMED_INSTANCE - * FT_IS_VARIATION - * - * 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_Reference_Face - * FT_New_Memory_Face - * FT_Face_Properties - * 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_RequestRec - * FT_Size_Request - * FT_Set_Transform - * FT_Load_Glyph - * FT_Get_Char_Index - * FT_Get_First_Char - * FT_Get_Next_Char - * 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_NO_AUTOHINT - * FT_LOAD_COLOR - * - * FT_LOAD_VERTICAL_LAYOUT - * FT_LOAD_IGNORE_TRANSFORM - * 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_LOAD_TARGET_MODE - * - * 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 - * - * FT_Get_FSType_Flags - * FT_Get_SubGlyph_Info - * - * FT_Face_Internal - * FT_Size_Internal - * FT_Slot_Internal - * - * FT_FACE_FLAG_XXX - * FT_STYLE_FLAG_XXX - * FT_OPEN_XXX - * FT_LOAD_XXX - * FT_LOAD_TARGET_XXX - * FT_SUBGLYPH_FLAG_XXX - * FT_FSTYPE_XXX - * - * FT_HAS_FAST_GLYPHS + * glyph_retrieval * */ - /************************************************************************** * * @struct: @@ -329,6 +457,13 @@ FT_BEGIN_HEADER } FT_Glyph_Metrics; + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + /************************************************************************** * * @struct: @@ -389,6 +524,13 @@ FT_BEGIN_HEADER /*************************************************************************/ /*************************************************************************/ + /************************************************************************** + * + * @section: + * library_setup + * + */ + /************************************************************************** * * @type: @@ -463,7 +605,7 @@ FT_BEGIN_HEADER /************************************************************************** * * @section: - * base_interface + * face_creation * */ @@ -499,6 +641,13 @@ FT_BEGIN_HEADER typedef struct FT_FaceRec_* FT_Face; + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + /************************************************************************** * * @type: @@ -509,13 +658,15 @@ FT_BEGIN_HEADER * size. * * @note: - * An @FT_Face has one _active_ @FT_Size object that is used by functions - * like @FT_Load_Glyph to determine the scaling transformation that in - * turn is used to load and hint glyphs and metrics. + * An @FT_Face has one _active_ `FT_Size` object that is used by + * functions like @FT_Load_Glyph to determine the scaling transformation + * that in turn is used to load and hint glyphs and metrics. * - * You can use @FT_Set_Char_Size, @FT_Set_Pixel_Sizes, @FT_Request_Size + * A newly created `FT_Size` object contains only meaningless zero values. + * You must 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. + * values) of the active `FT_Size`. Otherwise, the scaling and hinting + * will not be performed. * * 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 @@ -529,6 +680,13 @@ FT_BEGIN_HEADER typedef struct FT_SizeRec_* FT_Size; + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + /************************************************************************** * * @type: @@ -548,6 +706,13 @@ FT_BEGIN_HEADER typedef struct FT_GlyphSlotRec_* FT_GlyphSlot; + /************************************************************************** + * + * @section: + * character_mapping + * + */ + /************************************************************************** * * @type: @@ -603,11 +768,12 @@ FT_BEGIN_HEADER */ #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) ) + +#define FT_ENC_TAG( value, a, b, c, d ) \ + value = ( ( FT_STATIC_BYTE_CAST( FT_UInt32, a ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, b ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_UInt32, c ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_UInt32, d ) ) #endif /* FT_ENC_TAG */ @@ -623,7 +789,7 @@ FT_BEGIN_HEADER * * @note: * Despite the name, this enumeration lists specific character - * repertories (i.e., charsets), and not text encoding methods (e.g., + * repertoires (i.e., charsets), and not text encoding methods (e.g., * UTF-8, UTF-16, etc.). * * Other encodings might be defined in the future. @@ -645,7 +811,7 @@ FT_BEGIN_HEADER * FT_ENCODING_MS_SYMBOL :: * Microsoft Symbol encoding, used to encode mathematical symbols and * wingdings. For more information, see - * 'https://www.microsoft.com/typography/otspec/recom.htm#non-standard-symbol-fonts', + * 'https://learn.microsoft.com/typography/opentype/spec/recom#non-standard-symbol-fonts', * 'http://www.kostis.net/charsets/symbol.htm', and * 'http://www.kostis.net/charsets/wingding.htm'. * @@ -717,11 +883,16 @@ FT_BEGIN_HEADER * Same as FT_ENCODING_JOHAB. Deprecated. * * @note: - * By default, FreeType enables a Unicode charmap and tags it with - * `FT_ENCODING_UNICODE` when it is either provided or can be generated - * from PostScript glyph name dictionaries in the font file. All other - * encodings are considered legacy and tagged only if explicitly defined - * in the font file. Otherwise, `FT_ENCODING_NONE` is used. + * When loading a font, FreeType makes a Unicode charmap active if + * possible (either if the font provides such a charmap, or if FreeType + * can synthesize one from PostScript glyph name dictionaries; in either + * case, the charmap is tagged with `FT_ENCODING_UNICODE`). If such a + * charmap is synthesized, it is placed at the first position of the + * charmap array. + * + * All other encodings are considered legacy and tagged only if + * explicitly defined in the font file. Otherwise, `FT_ENCODING_NONE` is + * used. * * `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 @@ -751,7 +922,7 @@ FT_BEGIN_HEADER * `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. + * `TT_MAC_LANGID_FARSI` means the Farsi variant of the Arabic encoding. */ typedef enum FT_Encoding_ { @@ -849,6 +1020,13 @@ FT_BEGIN_HEADER /*************************************************************************/ + /************************************************************************** + * + * @section: + * other_api_data + * + */ + /************************************************************************** * * @type: @@ -864,6 +1042,13 @@ FT_BEGIN_HEADER typedef struct FT_Face_InternalRec_* FT_Face_Internal; + /************************************************************************** + * + * @section: + * face_creation + * + */ + /************************************************************************** * * @struct: @@ -883,14 +1068,14 @@ FT_BEGIN_HEADER * the face in the font file (starting with value~0). They are set * to~0 if there is only one face in the font file. * - * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation - * fonts only, holding the named instance index for the current face - * index (starting with value~1; value~0 indicates font access without - * a named instance). For non-variation fonts, bits 16-30 are ignored. - * If we have the third named instance of face~4, say, `face_index` is - * set to 0x00030004. + * [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType + * Font Variations only, holding the named instance index for the + * current face index (starting with value~1; value~0 indicates font + * access without a named instance). For non-variation fonts, bits + * 16-30 are ignored. If we have the third named instance of face~4, + * say, `face_index` is set to 0x00030004. * - * Bit 31 is always zero (this is, `face_index` is always a positive + * Bit 31 is always zero (that is, `face_index` is always a positive * value). * * [Since 2.9] Changing the design coordinates with @@ -907,10 +1092,10 @@ FT_BEGIN_HEADER * the face; see @FT_STYLE_FLAG_XXX for the details. * * [Since 2.6.1] Bits 16-30 hold the number of named instances - * available for the current face if we have a GX or OpenType variation - * (sub)font. Bit 31 is always zero (this is, `style_flags` is always - * a positive value). Note that a variation font has always at least - * one named instance, namely the default instance. + * available for the current face if we have a TrueType GX or OpenType + * Font Variation. Bit 31 is always zero (that is, `style_flags` is + * always a positive value). Note that a variation font has always at + * least one named instance, namely the default instance. * * num_glyphs :: * The number of glyphs in the face. If the face is scalable and has @@ -974,6 +1159,9 @@ FT_BEGIN_HEADER * Note that the bounding box might be off by (at least) one pixel for * hinted fonts. See @FT_Size_Metrics for further discussion. * + * Note that the bounding box does not vary in OpenType Font Variations + * and should only be used in relation to the default instance. + * * 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 @@ -1030,7 +1218,7 @@ FT_BEGIN_HEADER * Fields may be changed after a call to @FT_Attach_File or * @FT_Attach_Stream. * - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `ascender`, `descender`, `height`, * `underline_position`, and `underline_thickness`. @@ -1059,9 +1247,9 @@ FT_BEGIN_HEADER FT_Generic generic; - /*# The following member variables (down to `underline_thickness`) */ - /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ - /*# for bitmap fonts. */ + /* 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; @@ -1079,7 +1267,7 @@ FT_BEGIN_HEADER FT_Size size; FT_CharMap charmap; - /*@private begin */ + /* private fields, internal to FreeType */ FT_Driver driver; FT_Memory memory; @@ -1092,8 +1280,6 @@ FT_BEGIN_HEADER FT_Face_Internal internal; - /*@private end */ - } FT_FaceRec; @@ -1136,9 +1322,13 @@ FT_BEGIN_HEADER * FT_FACE_FLAG_KERNING :: * The face contains kerning information. If set, the kerning distance * can be retrieved using the function @FT_Get_Kerning. Otherwise the - * function always return the vector (0,0). Note that FreeType doesn't - * handle kerning data from the SFNT 'GPOS' table (as present in many - * OpenType fonts). + * function always returns the vector (0,0). + * + * Note that for TrueType fonts only, FreeType supports both the 'kern' + * table and the basic, pair-wise kerning feature from the 'GPOS' table + * (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), though FreeType does + * not support the more advanced GPOS layout features; use a library + * like HarfBuzz for those instead. * * FT_FACE_FLAG_FAST_GLYPHS :: * THIS FLAG IS DEPRECATED. DO NOT USE OR TEST IT. @@ -1146,7 +1336,7 @@ FT_BEGIN_HEADER * FT_FACE_FLAG_MULTIPLE_MASTERS :: * The face contains multiple masters and is capable of interpolating * between them. Supported formats are Adobe MM, TrueType GX, and - * OpenType variation fonts. + * OpenType Font Variations. * * See section @multiple_masters for API details. * @@ -1176,13 +1366,13 @@ FT_BEGIN_HEADER * successfully; in all other cases you get an * `FT_Err_Invalid_Argument` error. * - * Note that CID-keyed fonts that are in an SFNT wrapper (this is, all + * Note that CID-keyed fonts that are in an SFNT wrapper (that is, all * OpenType/CFF fonts) don't have this flag set since the glyphs are * accessed in the normal way (using contiguous indices); the * 'CID-ness' isn't visible to the application. * * FT_FACE_FLAG_TRICKY :: - * The face is 'tricky', this is, it always needs the font format's + * The face is 'tricky', that is, it always needs the font format's * native hinting engine to get a reasonable result. A typical example * is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that * uses TrueType bytecode instructions to move and scale all of its @@ -1204,8 +1394,21 @@ FT_BEGIN_HEADER * FT_FACE_FLAG_VARIATION :: * [Since 2.9] Set if the current face (or named instance) has been * altered with @FT_Set_MM_Design_Coordinates, - * @FT_Set_Var_Design_Coordinates, or @FT_Set_Var_Blend_Coordinates. - * This flag is unset by a call to @FT_Set_Named_Instance. + * @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or + * @FT_Set_MM_WeightVector to select a non-default instance. + * + * FT_FACE_FLAG_SVG :: + * [Since 2.12] The face has an 'SVG~' OpenType table. + * + * FT_FACE_FLAG_SBIX :: + * [Since 2.12] The face has an 'sbix' OpenType table *and* outlines. + * For such fonts, @FT_FACE_FLAG_SCALABLE is not set by default to + * retain backward compatibility. + * + * FT_FACE_FLAG_SBIX_OVERLAY :: + * [Since 2.12] The face has an 'sbix' OpenType table where outlines + * should be drawn on top of bitmap strikes. + * */ #define FT_FACE_FLAG_SCALABLE ( 1L << 0 ) #define FT_FACE_FLAG_FIXED_SIZES ( 1L << 1 ) @@ -1223,8 +1426,18 @@ FT_BEGIN_HEADER #define FT_FACE_FLAG_TRICKY ( 1L << 13 ) #define FT_FACE_FLAG_COLOR ( 1L << 14 ) #define FT_FACE_FLAG_VARIATION ( 1L << 15 ) +#define FT_FACE_FLAG_SVG ( 1L << 16 ) +#define FT_FACE_FLAG_SBIX ( 1L << 17 ) +#define FT_FACE_FLAG_SBIX_OVERLAY ( 1L << 18 ) + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + /************************************************************************** * * @macro: @@ -1239,7 +1452,7 @@ FT_BEGIN_HEADER * */ #define FT_HAS_HORIZONTAL( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_HORIZONTAL ) + ( !!( (face)->face_flags & FT_FACE_FLAG_HORIZONTAL ) ) /************************************************************************** @@ -1253,7 +1466,7 @@ FT_BEGIN_HEADER * */ #define FT_HAS_VERTICAL( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_VERTICAL ) + ( !!( (face)->face_flags & FT_FACE_FLAG_VERTICAL ) ) /************************************************************************** @@ -1267,7 +1480,7 @@ FT_BEGIN_HEADER * */ #define FT_HAS_KERNING( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_KERNING ) + ( !!( (face)->face_flags & FT_FACE_FLAG_KERNING ) ) /************************************************************************** @@ -1282,7 +1495,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_SCALABLE( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_SCALABLE ) + ( !!( (face)->face_flags & FT_FACE_FLAG_SCALABLE ) ) /************************************************************************** @@ -1301,7 +1514,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_SFNT( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_SFNT ) + ( !!( (face)->face_flags & FT_FACE_FLAG_SFNT ) ) /************************************************************************** @@ -1316,7 +1529,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_FIXED_WIDTH( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_WIDTH ) ) /************************************************************************** @@ -1331,9 +1544,16 @@ FT_BEGIN_HEADER * */ #define FT_HAS_FIXED_SIZES( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_FIXED_SIZES ) + ( !!( (face)->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) + /************************************************************************** + * + * @section: + * other_api_data + * + */ + /************************************************************************** * * @macro: @@ -1346,6 +1566,13 @@ FT_BEGIN_HEADER #define FT_HAS_FAST_GLYPHS( face ) 0 + /************************************************************************** + * + * @section: + * font_testing_macros + * + */ + /************************************************************************** * * @macro: @@ -1357,7 +1584,7 @@ FT_BEGIN_HEADER * */ #define FT_HAS_GLYPH_NAMES( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + ( !!( (face)->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) ) /************************************************************************** @@ -1372,7 +1599,7 @@ FT_BEGIN_HEADER * */ #define FT_HAS_MULTIPLE_MASTERS( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) + ( !!( (face)->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) ) /************************************************************************** @@ -1382,7 +1609,7 @@ FT_BEGIN_HEADER * * @description: * A macro that returns true whenever a face object is a named instance - * of a GX or OpenType variation font. + * of a TrueType GX or OpenType Font Variations. * * [Since 2.9] Changing the design coordinates with * @FT_Set_Var_Design_Coordinates or @FT_Set_Var_Blend_Coordinates does @@ -1394,7 +1621,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_NAMED_INSTANCE( face ) \ - ( (face)->face_index & 0x7FFF0000L ) + ( !!( (face)->face_index & 0x7FFF0000L ) ) /************************************************************************** @@ -1404,15 +1631,15 @@ FT_BEGIN_HEADER * * @description: * A macro that returns true whenever a face object has been altered by - * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, or - * @FT_Set_Var_Blend_Coordinates. + * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, + * @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector. * * @since: * 2.9 * */ #define FT_IS_VARIATION( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_VARIATION ) + ( !!( (face)->face_flags & FT_FACE_FLAG_VARIATION ) ) /************************************************************************** @@ -1429,7 +1656,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_CID_KEYED( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_CID_KEYED ) + ( !!( (face)->face_flags & FT_FACE_FLAG_CID_KEYED ) ) /************************************************************************** @@ -1443,7 +1670,7 @@ FT_BEGIN_HEADER * */ #define FT_IS_TRICKY( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_TRICKY ) + ( !!( (face)->face_flags & FT_FACE_FLAG_TRICKY ) ) /************************************************************************** @@ -1460,9 +1687,134 @@ FT_BEGIN_HEADER * */ #define FT_HAS_COLOR( face ) \ - ( (face)->face_flags & FT_FACE_FLAG_COLOR ) + ( !!( (face)->face_flags & FT_FACE_FLAG_COLOR ) ) + /************************************************************************** + * + * @macro: + * FT_HAS_SVG + * + * @description: + * A macro that returns true whenever a face object contains an 'SVG~' + * OpenType table. + * + * @since: + * 2.12 + */ +#define FT_HAS_SVG( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SVG ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table *and* outline glyphs. + * + * Currently, FreeType only supports bitmap glyphs in PNG format for this + * table (i.e., JPEG and TIFF formats are unsupported, as are + * Apple-specific formats not part of the OpenType specification). + * + * @note: + * For backward compatibility, a font with an 'sbix' table is treated as + * a bitmap-only face. Using @FT_Open_Face with + * @FT_PARAM_TAG_IGNORE_SBIX, an application can switch off 'sbix' + * handling so that the face is treated as an ordinary outline font with + * scalable outlines. + * + * Here is some pseudo code that roughly illustrates how to implement + * 'sbix' handling according to the OpenType specification. + * + * ``` + * if ( FT_HAS_SBIX( face ) ) + * { + * // open font as a scalable one without sbix handling + * FT_Face face2; + * FT_Parameter param = { FT_PARAM_TAG_IGNORE_SBIX, NULL }; + * FT_Open_Args args = { FT_OPEN_PARAMS | ..., + * ..., + * 1, ¶m }; + * + * + * FT_Open_Face( library, &args, 0, &face2 ); + * + * available_size` as necessary into + * `preferred_sizes`[*]> + * + * for ( i = 0; i < face->num_fixed_sizes; i++ ) + * { + * size = preferred_sizes[i].size; + * + * error = FT_Set_Pixel_Sizes( face, size, size ); + * + * + * // check whether we have a glyph in a bitmap strike + * error = FT_Load_Glyph( face, + * glyph_index, + * FT_LOAD_SBITS_ONLY | + * FT_LOAD_BITMAP_METRICS_ONLY ); + * if ( error == FT_Err_Invalid_Argument ) + * continue; + * else if ( error ) + * + * else + * break; + * } + * + * if ( i != face->num_fixed_sizes ) + * + * + * if ( i == face->num_fixed_sizes || + * FT_HAS_SBIX_OVERLAY( face ) ) + * + * } + * ``` + * + * [*] Assuming a target value of 400dpi and available strike sizes 100, + * 200, 300, and 400dpi, a possible order might be [400, 200, 300, 100]: + * scaling 200dpi to 400dpi usually gives better results than scaling + * 300dpi to 400dpi; it is also much faster. However, scaling 100dpi to + * 400dpi can yield a too pixelated result, thus the preference might be + * 300dpi over 100dpi. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX ) ) + + + /************************************************************************** + * + * @macro: + * FT_HAS_SBIX_OVERLAY + * + * @description: + * A macro that returns true whenever a face object contains an 'sbix' + * OpenType table with bit~1 in its `flags` field set, instructing the + * application to overlay the bitmap strike with the corresponding + * outline glyph. See @FT_HAS_SBIX for pseudo code how to use it. + * + * @since: + * 2.12 + */ +#define FT_HAS_SBIX_OVERLAY( face ) \ + ( !!( (face)->face_flags & FT_FACE_FLAG_SBIX_OVERLAY ) ) + + + /************************************************************************** + * + * @section: + * face_creation + * + */ + /************************************************************************** * * @enum: @@ -1489,6 +1841,13 @@ FT_BEGIN_HEADER #define FT_STYLE_FLAG_BOLD ( 1 << 1 ) + /************************************************************************** + * + * @section: + * other_api_data + * + */ + /************************************************************************** * * @type: @@ -1501,6 +1860,13 @@ FT_BEGIN_HEADER typedef struct FT_Size_InternalRec_* FT_Size_Internal; + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + /************************************************************************** * * @struct: @@ -1652,6 +2018,13 @@ FT_BEGIN_HEADER } FT_SizeRec; + /************************************************************************** + * + * @section: + * other_api_data + * + */ + /************************************************************************** * * @struct: @@ -1683,6 +2056,13 @@ FT_BEGIN_HEADER typedef struct FT_Slot_InternalRec_* FT_Slot_Internal; + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + /************************************************************************** * * @struct: @@ -1727,13 +2107,13 @@ FT_BEGIN_HEADER * 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. + * WYSIWYG layout. Only relevant for scalable 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. + * WYSIWYG layout. Only relevant for scalable glyphs. * * advance :: * This shorthand is, depending on @FT_LOAD_IGNORE_TRANSFORM, the @@ -1767,7 +2147,7 @@ FT_BEGIN_HEADER * freed. * * [Since 2.10.1] If @FT_LOAD_NO_SCALE is set, outline coordinates of - * OpenType variation fonts for a selected instance are internally + * OpenType Font Variations for a selected instance are internally * handled as 26.6 fractional font units but returned as (rounded) * integers, as expected. To get unrounded font units, don't use * @FT_LOAD_NO_SCALE but load the glyph with @FT_LOAD_NO_HINTING and @@ -1927,6 +2307,13 @@ FT_BEGIN_HEADER /*************************************************************************/ + /************************************************************************** + * + * @section: + * library_setup + * + */ + /************************************************************************** * * @function: @@ -1984,6 +2371,13 @@ FT_BEGIN_HEADER FT_Done_FreeType( FT_Library library ); + /************************************************************************** + * + * @section: + * face_creation + * + */ + /************************************************************************** * * @enum: @@ -2078,7 +2472,9 @@ FT_BEGIN_HEADER * The size in bytes of the file in memory. * * pathname :: - * A pointer to an 8-bit file pathname. + * A pointer to an 8-bit file pathname, which must be a C~string (i.e., + * no null bytes except at the very end). The pointer is not owned by + * FreeType. * * stream :: * A handle to a source stream object. @@ -2096,8 +2492,7 @@ FT_BEGIN_HEADER * Extra parameters passed to the font driver when opening a new face. * * @note: - * The stream type is determined by the contents of `flags` that are - * tested in the following order by @FT_Open_Face: + * The stream type is determined by the contents of `flags`: * * 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 not @@ -2110,6 +2505,9 @@ FT_BEGIN_HEADER * Otherwise, if the @FT_OPEN_PATHNAME bit is set, assume that this is a * normal file and use `pathname` to open it. * + * If none of the above bits are set or if multiple are set at the same + * time, the flags are invalid and @FT_Open_Face fails. + * * 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`. * @@ -2162,6 +2560,13 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: + * The `pathname` string should be recognizable as such by a standard + * `fopen` call on your system; in particular, this means that `pathname` + * must not contain null bytes. If that is not sufficient to address all + * file name possibilities (for example, to handle wide character file + * names on Windows in UTF-16 encoding) you might use @FT_Open_Face to + * pass a memory array or a stream object instead. + * * Use @FT_Done_Face to destroy the created @FT_Face object (along with * its slot and sizes). */ @@ -2235,14 +2640,14 @@ FT_BEGIN_HEADER * the face in the font file (starting with value~0). Set it to~0 if * there is only one face in the font file. * - * [Since 2.6.1] Bits 16-30 are relevant to GX and OpenType variation - * fonts only, specifying the named instance index for the current face - * index (starting with value~1; value~0 makes FreeType ignore named - * instances). For non-variation fonts, bits 16-30 are ignored. - * Assuming that you want to access the third named instance in face~4, - * `face_index` should be set to 0x00030004. If you want to access - * face~4 without variation handling, simply set `face_index` to - * value~4. + * [Since 2.6.1] Bits 16-30 are relevant to TrueType GX and OpenType + * Font Variations only, specifying the named instance index for the + * current face index (starting with value~1; value~0 makes FreeType + * ignore named instances). For non-variation fonts, bits 16-30 are + * ignored. Assuming that you want to access the third named instance + * in face~4, `face_index` should be set to 0x00030004. If you want + * to access face~4 without variation handling, simply set + * `face_index` to value~4. * * `FT_Open_Face` and its siblings can be used to quickly check whether * the font format of a given font resource is supported by FreeType. @@ -2275,13 +2680,17 @@ FT_BEGIN_HEADER * Each new face object created with this function also owns a default * @FT_Size object, accessible as `face->size`. * - * One @FT_Library instance can have multiple face objects, this is, + * One @FT_Library instance can have multiple face objects, that is, * @FT_Open_Face and its siblings can be called multiple times using the * same `library` argument. * * See the discussion of reference counters in the description of * @FT_Reference_Face. * + * If `FT_OPEN_STREAM` is set in `args->flags`, the stream in + * `args->stream` is automatically closed before this function returns + * any error (including `FT_Err_Invalid_Argument`). + * * @example: * To loop over all faces, use code similar to the following snippet * (omitting the error handling). @@ -2413,8 +2822,8 @@ FT_BEGIN_HEADER * stream attachments. */ FT_EXPORT( FT_Error ) - FT_Attach_Stream( FT_Face face, - FT_Open_Args* parameters ); + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ); /************************************************************************** @@ -2440,6 +2849,7 @@ FT_BEGIN_HEADER * * @since: * 2.4.2 + * */ FT_EXPORT( FT_Error ) FT_Reference_Face( FT_Face face ); @@ -2469,6 +2879,13 @@ FT_BEGIN_HEADER FT_Done_Face( FT_Face face ); + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + /************************************************************************** * * @function: @@ -2497,11 +2914,11 @@ FT_BEGIN_HEADER * of the available glyphs at a given ppem value is available. FreeType * silently uses outlines if there is no bitmap for a given glyph index. * - * For GX and OpenType variation fonts, a bitmap strike makes sense only - * if the default instance is active (this is, no glyph variation takes - * place); otherwise, FreeType simply ignores bitmap strikes. The same - * is true for all named instances that are different from the default - * instance. + * For TrueType GX and OpenType Font Variations, a bitmap strike makes + * sense only if the default instance is active (that is, no glyph + * variation takes place); otherwise, FreeType simply ignores bitmap + * strikes. The same is true for all named instances that are different + * from the default instance. * * Don't use this function if you are using the FreeType cache API. */ @@ -2661,11 +3078,11 @@ FT_BEGIN_HEADER * is dependent entirely on how the size is defined in the source face. * The font designer chooses the final size of each glyph relative to * this size. For more information refer to - * 'https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html'. + * 'https://freetype.org/freetype2/docs/glyphs/glyphs-2.html'. * * Contrary to @FT_Set_Char_Size, this function doesn't have special code - * to normalize zero-valued widths, heights, or resolutions (which lead - * to errors in most cases). + * to normalize zero-valued widths, heights, or resolutions, which are + * treated as @FT_LOAD_NO_SCALE. * * Don't use this function if you are using the FreeType cache API. */ @@ -2761,6 +3178,13 @@ FT_BEGIN_HEADER FT_UInt pixel_height ); + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + /************************************************************************** * * @function: @@ -2781,7 +3205,7 @@ FT_BEGIN_HEADER * * 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., + * flags 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). * @@ -2789,11 +3213,13 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * The loaded glyph may be transformed. See @FT_Set_Transform for the - * details. + * For proper scaling and hinting, the active @FT_Size object owned by + * the face has to be meaningfully initialized by calling + * @FT_Set_Char_Size before this function, for example. The loaded + * glyph may be transformed. See @FT_Set_Transform for the details. * * For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned - * for invalid CID values (this is, for CID values that don't have a + * for invalid CID values (that is, for CID values that don't have a * corresponding glyph in the font). See the discussion of the * @FT_FACE_FLAG_CID_KEYED flag for more details. * @@ -2807,6 +3233,13 @@ FT_BEGIN_HEADER FT_Int32 load_flags ); + /************************************************************************** + * + * @section: + * character_mapping + * + */ + /************************************************************************** * * @function: @@ -2850,6 +3283,13 @@ FT_BEGIN_HEADER FT_Int32 load_flags ); + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + /************************************************************************** * * @enum: @@ -2880,19 +3320,21 @@ FT_BEGIN_HEADER * * FT_LOAD_NO_SCALE :: * Don't scale the loaded outline glyph but keep it in font units. + * This flag is also assumed if @FT_Size owned by the face was not + * properly initialized. * * This flag implies @FT_LOAD_NO_HINTING and @FT_LOAD_NO_BITMAP, and * unsets @FT_LOAD_RENDER. * * If the font is 'tricky' (see @FT_FACE_FLAG_TRICKY for more), using * `FT_LOAD_NO_SCALE` usually yields meaningless outlines because the - * subglyphs must be scaled and positioned with hinting instructions. + * subglyphs must be scaled and positioned with hinting instructions. * This can be solved by loading the font without `FT_LOAD_NO_SCALE` * and setting the character size to `font->units_per_EM`. * * FT_LOAD_NO_HINTING :: * Disable hinting. This generally generates 'blurrier' bitmap glyphs - * when the glyph are rendered in any of the anti-aliased modes. See + * when the glyphs are rendered in any of the anti-aliased modes. See * also the note below. * * This flag is implied by @FT_LOAD_NO_SCALE. @@ -2910,6 +3352,15 @@ FT_BEGIN_HEADER * * @FT_LOAD_NO_SCALE always sets this flag. * + * FT_LOAD_SBITS_ONLY :: + * [Since 2.12] This is the opposite of @FT_LOAD_NO_BITMAP, more or + * less: @FT_Load_Glyph returns `FT_Err_Invalid_Argument` if the face + * contains a bitmap strike for the given size (or the strike selected + * by @FT_Select_Size) but there is no glyph in the strike. + * + * Note that this load flag was part of FreeType since version 2.0.6 + * but previously tagged as internal. + * * FT_LOAD_VERTICAL_LAYOUT :: * Load the glyph for vertical text layout. In particular, the * `advance` value in the @FT_GlyphSlotRec structure is set to the @@ -2966,25 +3417,41 @@ FT_BEGIN_HEADER * Disable the auto-hinter. See also the note below. * * FT_LOAD_COLOR :: - * Load colored glyphs. There are slight differences depending on the - * font format. + * Load colored glyphs. FreeType searches in the following order; + * there are slight differences depending on the font format. * - * [Since 2.5] Load embedded color bitmap images. The resulting color - * bitmaps, if available, will have the @FT_PIXEL_MODE_BGRA format, - * with pre-multiplied color channels. If the flag is not set and - * color bitmaps are found, they are converted to 256-level gray - * bitmaps, using the @FT_PIXEL_MODE_GRAY format. + * [Since 2.5] Load embedded color bitmap images (provided + * @FT_LOAD_NO_BITMAP is not set). The resulting color bitmaps, if + * available, have the @FT_PIXEL_MODE_BGRA format, with pre-multiplied + * color channels. If the flag is not set and color bitmaps are found, + * they are converted to 256-level gray bitmaps, using the + * @FT_PIXEL_MODE_GRAY format. * - * [Since 2.10, experimental] If the glyph index contains an entry in + * [Since 2.12] If the glyph index maps to an entry in the face's + * 'SVG~' table, load the associated SVG document from this table and + * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG + * ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set). Note that + * FreeType itself can't render SVG documents; however, the library + * provides hooks to seamlessly integrate an external renderer. See + * sections @ot_svg_driver and @svg_fonts for more. + * + * [Since 2.10, experimental] If the glyph index maps to an entry in * the face's 'COLR' table with a 'CPAL' palette table (as defined in * the OpenType specification), make @FT_Render_Glyph provide a default * blending of the color glyph layers associated with the glyph index, * using the same bitmap format as embedded color bitmap images. This - * is mainly for convenience; for full control of color layers use + * is mainly for convenience and works only for glyphs in 'COLR' v0 + * tables. **There is no rendering support for 'COLR' v1** (with the + * exception of v1 tables that exclusively use v0 features)! You need + * a graphics library like Skia or Cairo to interpret the graphics + * commands stored in v1 tables. For full control of color layers use * @FT_Get_Color_Glyph_Layer and FreeType's color functions like * @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering * so that the client application can handle blending by itself. * + * FT_LOAD_NO_SVG :: + * [Since 2.13.1] Ignore SVG glyph data when loading. + * * FT_LOAD_COMPUTE_METRICS :: * [Since 2.6.1] Compute glyph metrics from the glyph data, without the * use of bundled metrics tables (for example, the 'hdmx' table in @@ -3031,30 +3498,32 @@ FT_BEGIN_HEADER * */ #define FT_LOAD_DEFAULT 0x0 -#define FT_LOAD_NO_SCALE ( 1L << 0 ) -#define FT_LOAD_NO_HINTING ( 1L << 1 ) -#define FT_LOAD_RENDER ( 1L << 2 ) -#define FT_LOAD_NO_BITMAP ( 1L << 3 ) -#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) -#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) -#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) -#define FT_LOAD_PEDANTIC ( 1L << 7 ) -#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) +#define FT_LOAD_NO_SCALE ( 1L << 0 ) +#define FT_LOAD_NO_HINTING ( 1L << 1 ) +#define FT_LOAD_RENDER ( 1L << 2 ) +#define FT_LOAD_NO_BITMAP ( 1L << 3 ) +#define FT_LOAD_VERTICAL_LAYOUT ( 1L << 4 ) +#define FT_LOAD_FORCE_AUTOHINT ( 1L << 5 ) +#define FT_LOAD_CROP_BITMAP ( 1L << 6 ) +#define FT_LOAD_PEDANTIC ( 1L << 7 ) +#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ( 1L << 9 ) #define FT_LOAD_NO_RECURSE ( 1L << 10 ) #define FT_LOAD_IGNORE_TRANSFORM ( 1L << 11 ) #define FT_LOAD_MONOCHROME ( 1L << 12 ) #define FT_LOAD_LINEAR_DESIGN ( 1L << 13 ) +#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) #define FT_LOAD_NO_AUTOHINT ( 1L << 15 ) /* Bits 16-19 are used by `FT_LOAD_TARGET_` */ #define FT_LOAD_COLOR ( 1L << 20 ) #define FT_LOAD_COMPUTE_METRICS ( 1L << 21 ) #define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 ) +#define FT_LOAD_NO_SVG ( 1L << 24 ) /* */ /* used internally only by certain font drivers */ -#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) -#define FT_LOAD_SBITS_ONLY ( 1L << 14 ) +#define FT_LOAD_ADVANCE_ONLY ( 1L << 8 ) +#define FT_LOAD_SVG_ONLY ( 1L << 23 ) /************************************************************************** @@ -3144,7 +3613,7 @@ FT_BEGIN_HEADER * necessary to empty the cache after a mode switch to avoid false hits. * */ -#define FT_LOAD_TARGET_( x ) ( (FT_Int32)( (x) & 15 ) << 16 ) +#define FT_LOAD_TARGET_( x ) ( FT_STATIC_CAST( 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 ) @@ -3163,9 +3632,17 @@ FT_BEGIN_HEADER * @FT_LOAD_TARGET_XXX value. * */ -#define FT_LOAD_TARGET_MODE( x ) ( (FT_Render_Mode)( ( (x) >> 16 ) & 15 ) ) +#define FT_LOAD_TARGET_MODE( x ) \ + FT_STATIC_CAST( FT_Render_Mode, ( (x) >> 16 ) & 15 ) + /************************************************************************** + * + * @section: + * sizing_and_scaling + * + */ + /************************************************************************** * * @function: @@ -3184,9 +3661,16 @@ FT_BEGIN_HEADER * A pointer to the transformation's 2x2 matrix. Use `NULL` for the * identity matrix. * delta :: - * A pointer to the translation vector. Use `NULL` for the null vector. + * A pointer to the translation vector. Use `NULL` for the null + * vector. * * @note: + * This function is provided as a convenience, but keep in mind that + * @FT_Matrix coefficients are only 16.16 fixed-point values, which can + * limit the accuracy of the results. Using floating-point computations + * to perform the transform directly in client code instead will always + * yield better numbers. + * * 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 @@ -3201,6 +3685,46 @@ FT_BEGIN_HEADER FT_Vector* delta ); + /************************************************************************** + * + * @function: + * FT_Get_Transform + * + * @description: + * Return the transformation that is applied to glyph images when they + * are loaded into a glyph slot through @FT_Load_Glyph. See + * @FT_Set_Transform for more details. + * + * @input: + * face :: + * A handle to the source face object. + * + * @output: + * matrix :: + * A pointer to a transformation's 2x2 matrix. Set this to NULL if you + * are not interested in the value. + * + * delta :: + * A pointer to a translation vector. Set this to NULL if you are not + * interested in the value. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ); + + + /************************************************************************** + * + * @section: + * glyph_retrieval + * + */ + /************************************************************************** * * @enum: @@ -3219,6 +3743,10 @@ FT_BEGIN_HEADER * correction to correctly render non-monochrome glyph bitmaps onto a * surface; see @FT_Render_Glyph. * + * The @FT_RENDER_MODE_SDF is a special render mode that uses up to 256 + * distance values, indicating the signed distance from the grid position + * to the nearest outline. + * * @values: * FT_RENDER_MODE_NORMAL :: * Default render mode; it corresponds to 8-bit anti-aliased bitmaps. @@ -3244,19 +3772,19 @@ FT_BEGIN_HEADER * bitmaps that are 3~times the height of the original glyph outline in * pixels and use the @FT_PIXEL_MODE_LCD_V mode. * - * @note: - * Should you define `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` in your - * `ftoption.h`, which enables patented ClearType-style rendering, the - * LCD-optimized glyph bitmaps should be filtered to reduce color fringes - * inherent to this technology. You can either set up LCD filtering with - * @FT_Library_SetLcdFilter or @FT_Face_Properties, or do the filtering - * yourself. The default FreeType LCD rendering technology does not - * require filtering. + * FT_RENDER_MODE_SDF :: + * The positive (unsigned) 8-bit bitmap values can be converted to the + * single-channel signed distance field (SDF) by subtracting 128, with + * the positive and negative results corresponding to the inside and + * the outside of a glyph contour, respectively. The distance units are + * arbitrarily determined by an adjustable @spread property. * - * The selected render mode only affects vector glyphs of a font. + * @note: + * The selected render mode only affects scalable vector glyphs of a font. * Embedded bitmaps often have a different pixel mode like * @FT_PIXEL_MODE_MONO. You can use @FT_Bitmap_Convert to transform them * into 8-bit pixmaps. + * */ typedef enum FT_Render_Mode_ { @@ -3265,6 +3793,7 @@ FT_BEGIN_HEADER FT_RENDER_MODE_MONO, FT_RENDER_MODE_LCD, FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_SDF, FT_RENDER_MODE_MAX @@ -3296,7 +3825,7 @@ FT_BEGIN_HEADER * @FT_Render_Mode for a list of possible values. * * If @FT_RENDER_MODE_NORMAL is used, a previous call of @FT_Load_Glyph - * with flag @FT_LOAD_COLOR makes FT_Render_Glyph provide a default + * with flag @FT_LOAD_COLOR makes `FT_Render_Glyph` provide a default * blending of colored glyph layers associated with the current glyph * slot (provided the font contains such layers) instead of rendering * the glyph slot's outline. This is an experimental feature; see @@ -3306,9 +3835,6 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * To get meaningful results, font scaling values must be set with - * functions like @FT_Set_Char_Size before calling `FT_Render_Glyph`. - * * When FreeType outputs a bitmap of a glyph, it really outputs an alpha * coverage map. If a pixel is completely covered by a filled-in * outline, the bitmap contains 0xFF at that pixel, meaning that @@ -3352,7 +3878,8 @@ FT_BEGIN_HEADER * * which is known as the OVER operator. * - * To correctly composite an antialiased pixel of a glyph onto a surface, + * To correctly composite an anti-aliased pixel of a glyph onto a + * surface, * * 1. take the foreground and background colors (e.g., in sRGB space) * and apply gamma to get them in a linear space, @@ -3370,8 +3897,10 @@ FT_BEGIN_HEADER * * This process can cost performance. There is an approximation that * does not need to know about the background color; see - * https://bel.fi/alankila/lcd/ and - * https://bel.fi/alankila/lcd/alpcor.html for details. + * https://web.archive.org/web/20211019204945/https://bel.fi/alankila/lcd/ + * and + * https://web.archive.org/web/20210211002939/https://bel.fi/alankila/lcd/alpcor.html + * for details. * * **ATTENTION**: Linear blending is even more important when dealing * with subpixel-rendered glyphs to prevent color-fringing! A @@ -3468,9 +3997,26 @@ FT_BEGIN_HEADER * out of the scope of this API function -- they can be implemented * through format-specific interfaces. * - * Kerning for OpenType fonts implemented in a 'GPOS' table is not - * supported; use @FT_HAS_KERNING to find out whether a font has data - * that can be extracted with `FT_Get_Kerning`. + * Note that, for TrueType and OpenType fonts only, this can extract data + * from both the 'kern' table and the basic, pair-wise kerning feature + * from the GPOS table (with `TT_CONFIG_OPTION_GPOS_KERNING` enabled), + * though FreeType does not support the more advanced GPOS layout + * features; use a library like HarfBuzz for those instead. If a font + * has both a 'kern' table and kern features of a GPOS table, the 'kern' + * table will be used. + * + * Also note for right-to-left scripts, the functionality may differ for + * fonts with GPOS tables vs. 'kern' tables. For GPOS, right-to-left + * fonts typically use both a placement offset and an advance for pair + * positioning, which this API does not support, so it would output + * kerning values of zero; though if the right-to-left font used only + * advances in GPOS pair positioning, then this API could output kerning + * values for it, but it would use `left_glyph` to mean the first glyph + * for that case. Whereas 'kern' tables are always advance-only and + * always store the left glyph first. + * + * Use @FT_HAS_KERNING to find out whether a font has data that can be + * extracted with `FT_Get_Kerning`. */ FT_EXPORT( FT_Error ) FT_Get_Kerning( FT_Face face, @@ -3525,86 +4071,10 @@ FT_BEGIN_HEADER /************************************************************************** * - * @function: - * FT_Get_Glyph_Name + * @section: + * character_mapping * - * @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 maximum 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. - * - * Be aware that FreeType reorders glyph indices internally so that glyph - * index~0 always corresponds to the 'missing glyph' (called '.notdef'). - * - * This function always returns an error if the config macro - * `FT_CONFIG_OPTION_NO_GLYPH_NAMES` is not defined in `ftoption.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, TrueType, and OpenType 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. - * - * For variation fonts, this string changes if you select a different - * instance, and you have to call `FT_Get_PostScript_Name` again to - * retrieve it. FreeType follows Adobe TechNote #5902, 'Generating - * PostScript Names for Fonts Using OpenType Font Variations'. - * - * https://download.macromedia.com/pub/developer/opentype/tech-notes/5902.AdobePSNameGeneration.html - * - * [Since 2.9] Special PostScript names for named instances are only - * returned if the named instance is set with @FT_Set_Named_Instance (and - * the font has corresponding entries in its 'fvar' table). If - * @FT_IS_VARIATION returns true, the algorithmically derived PostScript - * name is provided, not looking up special entries for named instances. - */ - FT_EXPORT( const char* ) - FT_Get_Postscript_Name( FT_Face face ); - /************************************************************************** * @@ -3822,6 +4292,13 @@ FT_BEGIN_HEADER FT_UInt *agindex ); + /************************************************************************** + * + * @section: + * face_creation + * + */ + /************************************************************************** * * @function: @@ -3920,13 +4397,21 @@ FT_BEGIN_HEADER FT_Parameter* properties ); + /************************************************************************** + * + * @section: + * information_retrieval + * + */ + /************************************************************************** * * @function: * FT_Get_Name_Index * * @description: - * Return the glyph index of a given glyph name. + * Return the glyph index of a given glyph name. This only works + * for those faces where @FT_HAS_GLYPH_NAMES returns true. * * @input: * face :: @@ -3937,12 +4422,108 @@ FT_BEGIN_HEADER * * @return: * The glyph index. 0~means 'undefined character code'. + * + * @note: + * Acceptable glyph names might come from the [Adobe Glyph + * List](https://github.com/adobe-type-tools/agl-aglfn). See + * @FT_Get_Glyph_Name for the inverse functionality. + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). */ FT_EXPORT( FT_UInt ) FT_Get_Name_Index( FT_Face face, const FT_String* glyph_name ); + /************************************************************************** + * + * @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 returns true. + * + * @input: + * face :: + * A handle to a source face object. + * + * glyph_index :: + * The glyph index. + * + * buffer_max :: + * The maximum 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. + * + * Be aware that FreeType reorders glyph indices internally so that glyph + * index~0 always corresponds to the 'missing glyph' (called '.notdef'). + * + * This function has limited capabilities if the config macro + * `FT_CONFIG_OPTION_POSTSCRIPT_NAMES` is not defined in `ftoption.h`: + * It then works only for fonts that actually embed glyph names (which + * many recent OpenType fonts do not). + */ + 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, TrueType, and OpenType 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. + * + * For variation fonts, this string changes if you select a different + * instance, and you have to call `FT_Get_PostScript_Name` again to + * retrieve it. FreeType follows Adobe TechNote #5902, 'Generating + * PostScript Names for Fonts Using OpenType Font Variations'. + * + * https://download.macromedia.com/pub/developer/opentype/tech-notes/5902.AdobePSNameGeneration.html + * + * [Since 2.9] Special PostScript names for named instances are only + * returned if the named instance is set with @FT_Set_Named_Instance (and + * the font has corresponding entries in its 'fvar' table or is the + * default named instance). If @FT_IS_VARIATION returns true, the + * algorithmically derived PostScript name is provided, not looking up + * special entries for named instances. + */ + FT_EXPORT( const char* ) + FT_Get_Postscript_Name( FT_Face face ); + + /************************************************************************** * * @enum: @@ -3953,7 +4534,7 @@ FT_BEGIN_HEADER * table description in the OpenType specification for the meaning of the * various flags (which get synthesized for non-OpenType subglyphs). * - * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description * * @values: * FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS :: @@ -4016,7 +4597,7 @@ FT_BEGIN_HEADER * interpreted depending on the flags returned in `*p_flags`. See the * OpenType specification for details. * - * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description + * https://learn.microsoft.com/typography/opentype/spec/glyf#composite-glyph-description * */ FT_EXPORT( FT_Error ) @@ -4029,175 +4610,6 @@ FT_BEGIN_HEADER FT_Matrix *p_transform ); - /************************************************************************** - * - * @section: - * layer_management - * - * @title: - * Glyph Layer Management - * - * @abstract: - * Retrieving and manipulating OpenType's 'COLR' table data. - * - * @description: - * The functions described here allow access of colored glyph layer data - * in OpenType's 'COLR' tables. - */ - - - /************************************************************************** - * - * @struct: - * FT_LayerIterator - * - * @description: - * This iterator object is needed for @FT_Get_Color_Glyph_Layer. - * - * @fields: - * num_layers :: - * The number of glyph layers for the requested glyph index. Will be - * set by @FT_Get_Color_Glyph_Layer. - * - * layer :: - * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. - * - * p :: - * An opaque pointer into 'COLR' table data. The caller must set this - * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. - */ - typedef struct FT_LayerIterator_ - { - FT_UInt num_layers; - FT_UInt layer; - FT_Byte* p; - - } FT_LayerIterator; - - - /************************************************************************** - * - * @function: - * FT_Get_Color_Glyph_Layer - * - * @description: - * This is an interface to the 'COLR' table in OpenType fonts to - * iteratively retrieve the colored glyph layers associated with the - * current glyph slot. - * - * https://docs.microsoft.com/en-us/typography/opentype/spec/colr - * - * The glyph layer data for a given glyph index, if present, provides an - * alternative, multi-colour glyph representation: Instead of rendering - * the outline or bitmap with the given glyph index, glyphs with the - * indices and colors returned by this function are rendered layer by - * layer. - * - * The returned elements are ordered in the z~direction from bottom to - * top; the 'n'th element should be rendered with the associated palette - * color and blended on top of the already rendered layers (elements 0, - * 1, ..., n-1). - * - * @input: - * face :: - * A handle to the parent face object. - * - * base_glyph :: - * The glyph index the colored glyph layers are associated with. - * - * @inout: - * iterator :: - * An @FT_LayerIterator object. For the first call you should set - * `iterator->p` to `NULL`. For all following calls, simply use the - * same object again. - * - * @output: - * aglyph_index :: - * The glyph index of the current layer. - * - * acolor_index :: - * The color index into the font face's color palette of the current - * layer. The value 0xFFFF is special; it doesn't reference a palette - * entry but indicates that the text foreground color should be used - * instead (to be set up by the application outside of FreeType). - * - * The color palette can be retrieved with @FT_Palette_Select. - * - * @return: - * Value~1 if everything is OK. If there are no more layers (or if there - * are no layers at all), value~0 gets returned. In case of an error, - * value~0 is returned also. - * - * @note: - * This function is necessary if you want to handle glyph layers by - * yourself. In particular, functions that operate with @FT_GlyphRec - * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access - * to this information. - * - * Note that @FT_Render_Glyph is able to handle colored glyph layers - * automatically if the @FT_LOAD_COLOR flag is passed to a previous call - * to @FT_Load_Glyph. [This is an experimental feature.] - * - * @example: - * ``` - * FT_Color* palette; - * FT_LayerIterator iterator; - * - * FT_Bool have_layers; - * FT_UInt layer_glyph_index; - * FT_UInt layer_color_index; - * - * - * error = FT_Palette_Select( face, palette_index, &palette ); - * if ( error ) - * palette = NULL; - * - * iterator.p = NULL; - * have_layers = FT_Get_Color_Glyph_Layer( face, - * glyph_index, - * &layer_glyph_index, - * &layer_color_index, - * &iterator ); - * - * if ( palette && have_layers ) - * { - * do - * { - * FT_Color layer_color; - * - * - * if ( layer_color_index == 0xFFFF ) - * layer_color = text_foreground_color; - * else - * layer_color = palette[layer_color_index]; - * - * // Load and render glyph `layer_glyph_index', then - * // blend resulting pixmap (using color `layer_color') - * // with previously created pixmaps. - * - * } while ( FT_Get_Color_Glyph_Layer( face, - * glyph_index, - * &layer_glyph_index, - * &layer_color_index, - * &iterator ) ); - * } - * ``` - */ - FT_EXPORT( FT_Bool ) - FT_Get_Color_Glyph_Layer( FT_Face face, - FT_UInt base_glyph, - FT_UInt *aglyph_index, - FT_UInt *acolor_index, - FT_LayerIterator* iterator ); - - - /************************************************************************** - * - * @section: - * base_interface - * - */ - /************************************************************************** * * @enum: @@ -4211,7 +4623,7 @@ FT_BEGIN_HEADER * associated with a font. * * See - * https://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/FontPolicies.pdf + * https://adobe-type-tools.github.io/font-tech-notes/pdfs/AcrobatDC_FontPolicies.pdf * for more details. * * @values: @@ -4281,6 +4693,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.8 + * */ FT_EXPORT( FT_UShort ) FT_Get_FSType_Flags( FT_Face face ); @@ -4374,6 +4787,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt ) FT_Face_GetCharVariantIndex( FT_Face face, @@ -4410,6 +4824,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.6 + * */ FT_EXPORT( FT_Int ) FT_Face_GetCharVariantIsDefault( FT_Face face, @@ -4441,6 +4856,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetVariantSelectors( FT_Face face ); @@ -4474,6 +4890,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetVariantsOfChar( FT_Face face, @@ -4508,6 +4925,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.6 + * */ FT_EXPORT( FT_UInt32* ) FT_Face_GetCharsOfVariant( FT_Face face, @@ -4527,7 +4945,8 @@ FT_BEGIN_HEADER * * @description: * This section contains various functions used to perform computations - * on 16.16 fixed-float numbers or 2d vectors. + * on 16.16 fixed-point numbers or 2D vectors. FreeType does not use + * floating-point data types. * * **Attention**: Most arithmetic functions take `FT_Long` as arguments. * For historical reasons, FreeType was designed under the assumption @@ -4731,32 +5150,10 @@ FT_BEGIN_HEADER /************************************************************************** * * @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. - * - * @order: - * FT_Library_Version - * - * FREETYPE_MAJOR - * FREETYPE_MINOR - * FREETYPE_PATCH - * - * FT_Face_CheckTrueTypePatents - * FT_Face_SetUnpatentedHinting + * library_setup * */ - /************************************************************************** * * @enum: @@ -4780,7 +5177,7 @@ FT_BEGIN_HEADER * */ #define FREETYPE_MAJOR 2 -#define FREETYPE_MINOR 10 +#define FREETYPE_MINOR 14 #define FREETYPE_PATCH 1 @@ -4823,6 +5220,13 @@ FT_BEGIN_HEADER FT_Int *apatch ); + /************************************************************************** + * + * @section: + * other_api_data + * + */ + /************************************************************************** * * @function: @@ -4843,6 +5247,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.5 + * */ FT_EXPORT( FT_Bool ) FT_Face_CheckTrueTypePatents( FT_Face face ); @@ -4871,6 +5276,7 @@ FT_BEGIN_HEADER * * @since: * 2.3.5 + * */ FT_EXPORT( FT_Bool ) FT_Face_SetUnpatentedHinting( FT_Face face, diff --git a/src/thirdparty/freetype2/include/freetype/ftadvanc.h b/src/thirdparty/freetype2/include/freetype/ftadvanc.h index 95c38f92b..62a856ccb 100644 --- a/src/thirdparty/freetype2/include/freetype/ftadvanc.h +++ b/src/thirdparty/freetype2/include/freetype/ftadvanc.h @@ -4,7 +4,7 @@ * * Quick computation of advance widths (specification only). * - * Copyright (C) 2008-2019 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTADVANC_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -96,6 +95,7 @@ FT_BEGIN_HEADER * load_flags :: * A set of bit flags similar to those used when calling * @FT_Load_Glyph, used to determine what kind of advances you need. + * * @output: * padvance :: * The advance value. If scaling is performed (based on the value of diff --git a/src/thirdparty/freetype2/include/freetype/ftbbox.h b/src/thirdparty/freetype2/include/freetype/ftbbox.h index 22da70c0d..348b4b3a2 100644 --- a/src/thirdparty/freetype2/include/freetype/ftbbox.h +++ b/src/thirdparty/freetype2/include/freetype/ftbbox.h @@ -4,7 +4,7 @@ * * FreeType exact bbox computation (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -31,8 +31,7 @@ #define FTBBOX_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftbdf.h b/src/thirdparty/freetype2/include/freetype/ftbdf.h index 1c46da598..faad25689 100644 --- a/src/thirdparty/freetype2/include/freetype/ftbdf.h +++ b/src/thirdparty/freetype2/include/freetype/ftbdf.h @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTBDF_H_ #define FTBDF_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftbitmap.h b/src/thirdparty/freetype2/include/freetype/ftbitmap.h index a6acdb969..a22d43adf 100644 --- a/src/thirdparty/freetype2/include/freetype/ftbitmap.h +++ b/src/thirdparty/freetype2/include/freetype/ftbitmap.h @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define FTBITMAP_H_ -#include -#include FT_FREETYPE_H -#include FT_COLOR_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftbzip2.h b/src/thirdparty/freetype2/include/freetype/ftbzip2.h index ae88cfdbd..38b524582 100644 --- a/src/thirdparty/freetype2/include/freetype/ftbzip2.h +++ b/src/thirdparty/freetype2/include/freetype/ftbzip2.h @@ -4,7 +4,7 @@ * * Bzip2-compressed stream support. * - * Copyright (C) 2010-2019 by + * Copyright (C) 2010-2025 by * Joel Klinghed. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTBZIP2_H_ #define FTBZIP2_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -43,6 +42,16 @@ FT_BEGIN_HEADER * Using bzip2-compressed font files. * * @description: + * In certain builds of the library, bzip2 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 bzip2 compressed + * stream from it and re-open the face with it. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * * This section contains the declaration of Bzip2-specific functions. * */ @@ -75,15 +84,6 @@ FT_BEGIN_HEADER * **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, bzip2 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 bzip2 compressed - * 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 bzip2 support. */ diff --git a/src/thirdparty/freetype2/include/freetype/ftcache.h b/src/thirdparty/freetype2/include/freetype/ftcache.h index 0d589d0b3..865b743a6 100644 --- a/src/thirdparty/freetype2/include/freetype/ftcache.h +++ b/src/thirdparty/freetype2/include/freetype/ftcache.h @@ -4,7 +4,7 @@ * * FreeType Cache subsystem (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTCACHE_H_ -#include -#include FT_GLYPH_H +#include FT_BEGIN_HEADER @@ -44,61 +43,61 @@ FT_BEGIN_HEADER * 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. + * Note that all types and functions begin with the `FTC_` prefix rather + * than the usual `FT_` prefix in the rest of FreeType. * - * 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: + * The cache is highly portable and, thus, doesn't know anything about + * the fonts installed on your system, or how to access them. Therefore, + * it requires the following. * - * 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. + * * @FTC_FaceID, an arbitrary non-zero value that uniquely identifies + * available or installed font faces, has to be 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, but they + * have to be persistent on the client side. * - * Second, the cache calls, only when needed, a client-provided function - * to convert an @FTC_FaceID into a new @FT_Face object. The latter is - * then completely managed by the cache, including its termination - * through @FT_Done_Face. To monitor termination of face objects, the - * finalizer callback in the `generic` field of the @FT_Face object can - * be used, which might also be used to store the @FTC_FaceID of the - * face. + * * @FTC_Face_Requester, a method to convert an @FTC_FaceID into a new + * @FT_Face object when necessary, has to be provided to the cache by + * the client. The @FT_Face object is completely managed by the cache, + * including its termination through @FT_Done_Face. To monitor + * termination of face objects, the finalizer callback in the `generic` + * field of the @FT_Face object can be used, which might also be used + * to store the @FTC_FaceID of the 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. + * Clients are free to map face IDs to anything useful. The most simple + * usage is, for example, to associate them to a `{pathname,face_index}` + * pair that is then used by @FTC_Face_Requester 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 + * 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. + * crashes in @FTC_Face_Requester. * * 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. + * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively, and + * use them in any FreeType work stream. You can also cache other + * FreeType objects as follows. * - * 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 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. + * * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New, + * 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). * * @order: * FTC_Manager @@ -425,7 +424,7 @@ FT_BEGIN_HEADER * 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. + * 1/64 of points. * * x_res :: * Only used when `pixel` is value~0 to indicate the horizontal diff --git a/src/thirdparty/freetype2/include/freetype/ftchapters.h b/src/thirdparty/freetype2/include/freetype/ftchapters.h index 2ee26973e..7566fbd10 100644 --- a/src/thirdparty/freetype2/include/freetype/ftchapters.h +++ b/src/thirdparty/freetype2/include/freetype/ftchapters.h @@ -15,6 +15,7 @@ * General Remarks * * @sections: + * preamble * header_inclusion * user_allocation * @@ -30,9 +31,28 @@ * Core API * * @sections: - * version * basic_types - * base_interface + * library_setup + * face_creation + * font_testing_macros + * sizing_and_scaling + * glyph_retrieval + * character_mapping + * information_retrieval + * other_api_data + * + */ + + + /************************************************************************** + * + * @chapter: + * extended_api + * + * @title: + * Extended API + * + * @sections: * glyph_variants * color_management * layer_management @@ -61,6 +81,7 @@ * cid_fonts * pfr_fonts * winfnt_fonts + * svg_fonts * font_formats * gasp_table * @@ -81,6 +102,7 @@ * t1_cid_driver * tt_driver * pcf_driver + * ot_svg_driver * properties * parameter_tags * lcd_rendering @@ -123,6 +145,7 @@ * gzip * lzw * bzip2 + * debugging_apis * */ diff --git a/src/thirdparty/freetype2/include/freetype/ftcid.h b/src/thirdparty/freetype2/include/freetype/ftcid.h index 8eafc1c78..7cda8ff3f 100644 --- a/src/thirdparty/freetype2/include/freetype/ftcid.h +++ b/src/thirdparty/freetype2/include/freetype/ftcid.h @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information (specification). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * Dereg Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTCID_H_ #define FTCID_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftcolor.h b/src/thirdparty/freetype2/include/freetype/ftcolor.h index cf1802195..129b1a23f 100644 --- a/src/thirdparty/freetype2/include/freetype/ftcolor.h +++ b/src/thirdparty/freetype2/include/freetype/ftcolor.h @@ -4,7 +4,7 @@ * * FreeType's glyph color management (specification). * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTCOLOR_H_ #define FTCOLOR_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -125,9 +124,9 @@ FT_BEGIN_HEADER * The number of palettes. * * palette_name_ids :: - * A read-only array of palette name IDs with `num_palettes` elements, - * corresponding to entries like 'dark' or 'light' in the font's 'name' - * table. + * An optional read-only array of palette name IDs with `num_palettes` + * elements, corresponding to entries like 'dark' or 'light' in the + * font's 'name' table. * * An empty name ID in the 'CPAL' table gets represented as value * 0xFFFF. @@ -135,8 +134,8 @@ FT_BEGIN_HEADER * `NULL` if the font's 'CPAL' table doesn't contain appropriate data. * * palette_flags :: - * A read-only array of palette flags with `num_palettes` elements. - * Possible values are an ORed combination of + * An optional read-only array of palette flags with `num_palettes` + * elements. Possible values are an ORed combination of * @FT_PALETTE_FOR_LIGHT_BACKGROUND and * @FT_PALETTE_FOR_DARK_BACKGROUND. * @@ -147,7 +146,7 @@ FT_BEGIN_HEADER * same size. * * palette_entry_name_ids :: - * A read-only array of palette entry name IDs with + * An optional read-only array of palette entry name IDs with * `num_palette_entries`. In each palette, entries with the same index * have the same function. For example, index~0 might correspond to * string 'outline' in the font's 'name' table to indicate that this @@ -163,6 +162,9 @@ FT_BEGIN_HEADER * Use function @FT_Get_Sfnt_Name to map name IDs and entry name IDs to * name strings. * + * Use function @FT_Palette_Select to get the colors associated with a + * palette entry. + * * @since: * 2.10 */ @@ -300,6 +302,1369 @@ FT_BEGIN_HEADER FT_Palette_Set_Foreground_Color( FT_Face face, FT_Color foreground_color ); + + /************************************************************************** + * + * @section: + * layer_management + * + * @title: + * Glyph Layer Management + * + * @abstract: + * Retrieving and manipulating OpenType's 'COLR' table data. + * + * @description: + * The functions described here allow access of colored glyph layer data + * in OpenType's 'COLR' tables. + * + * Note that FreeType does *not* provide rendering in general of glyphs + * that use a 'COLR' table! While FreeType has very limited rendering + * support for 'COLR' v0 tables (without a possibility to change the + * color palette) via @FT_Render_Glyph, there is no such convenience + * code for 'COLR' v1 tables -- while it appears that v1 is simply an + * 'improved' version of v0, this is not the case: it is a completely + * different color font format, and you need a dedicated graphics + * library like Skia or Cairo to handle a v1 table's drawing commands. + */ + + + /************************************************************************** + * + * @struct: + * FT_LayerIterator + * + * @description: + * This iterator object is needed for @FT_Get_Color_Glyph_Layer. + * + * @fields: + * num_layers :: + * The number of glyph layers for the requested glyph index. Will be + * set by @FT_Get_Color_Glyph_Layer. + * + * layer :: + * The current layer. Will be set by @FT_Get_Color_Glyph_Layer. + * + * p :: + * An opaque pointer into 'COLR' table data. The caller must set this + * to `NULL` before the first call of @FT_Get_Color_Glyph_Layer. + */ + typedef struct FT_LayerIterator_ + { + FT_UInt num_layers; + FT_UInt layer; + FT_Byte* p; + + } FT_LayerIterator; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Layer + * + * @description: + * This is an interface to the 'COLR' table in OpenType fonts to + * iteratively retrieve the colored glyph layers associated with the + * current glyph slot. + * + * https://learn.microsoft.com/typography/opentype/spec/colr + * + * The glyph layer data for a given glyph index, if present, provides an + * alternative, multi-color glyph representation: Instead of rendering + * the outline or bitmap with the given glyph index, glyphs with the + * indices and colors returned by this function are rendered layer by + * layer. + * + * The returned elements are ordered in the z~direction from bottom to + * top; the 'n'th element should be rendered with the associated palette + * color and blended on top of the already rendered layers (elements 0, + * 1, ..., n-1). + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @inout: + * iterator :: + * An @FT_LayerIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * aglyph_index :: + * The glyph index of the current layer. + * + * acolor_index :: + * The color index into the font face's color palette of the current + * layer. The value 0xFFFF is special; it doesn't reference a palette + * entry but indicates that the text foreground color should be used + * instead (to be set up by the application outside of FreeType). + * + * The color palette can be retrieved with @FT_Palette_Select. + * + * @return: + * Value~1 if everything is OK. If there are no more layers (or if there + * are no layers at all), value~0 gets returned. In case of an error, + * value~0 is returned also. + * + * @note: + * This function is necessary if you want to handle glyph layers by + * yourself. In particular, functions that operate with @FT_GlyphRec + * objects (like @FT_Get_Glyph or @FT_Glyph_To_Bitmap) don't have access + * to this information. + * + * Note that @FT_Render_Glyph is able to handle colored glyph layers + * automatically if the @FT_LOAD_COLOR flag is passed to a previous call + * to @FT_Load_Glyph. [This is an experimental feature.] + * + * @example: + * ``` + * FT_Color* palette; + * FT_LayerIterator iterator; + * + * FT_Bool have_layers; + * FT_UInt layer_glyph_index; + * FT_UInt layer_color_index; + * + * + * error = FT_Palette_Select( face, palette_index, &palette ); + * if ( error ) + * palette = NULL; + * + * iterator.p = NULL; + * have_layers = FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ); + * + * if ( palette && have_layers ) + * { + * do + * { + * FT_Color layer_color; + * + * + * if ( layer_color_index == 0xFFFF ) + * layer_color = text_foreground_color; + * else + * layer_color = palette[layer_color_index]; + * + * // Load and render glyph `layer_glyph_index', then + * // blend resulting pixmap (using color `layer_color') + * // with previously created pixmaps. + * + * } while ( FT_Get_Color_Glyph_Layer( face, + * glyph_index, + * &layer_glyph_index, + * &layer_color_index, + * &iterator ) ); + * } + * ``` + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Layer( FT_Face face, + FT_UInt base_glyph, + FT_UInt *aglyph_index, + FT_UInt *acolor_index, + FT_LayerIterator* iterator ); + + + /************************************************************************** + * + * @enum: + * FT_PaintFormat + * + * @description: + * Enumeration describing the different paint format types of the v1 + * extensions to the 'COLR' table, see + * 'https://github.com/googlefonts/colr-gradients-spec'. + * + * The enumeration values loosely correspond with the format numbers of + * the specification: FreeType always returns a fully specified 'Paint' + * structure for the 'Transform', 'Translate', 'Scale', 'Rotate', and + * 'Skew' table types even though the specification has different formats + * depending on whether or not a center is specified, whether the scale + * is uniform in x and y~direction or not, etc. Also, only non-variable + * format identifiers are listed in this enumeration; as soon as support + * for variable 'COLR' v1 fonts is implemented, interpolation is + * performed dependent on axis coordinates, which are configured on the + * @FT_Face through @FT_Set_Var_Design_Coordinates. This implies that + * always static, readily interpolated values are returned in the 'Paint' + * structures. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintFormat_ + { + FT_COLR_PAINTFORMAT_COLR_LAYERS = 1, + FT_COLR_PAINTFORMAT_SOLID = 2, + FT_COLR_PAINTFORMAT_LINEAR_GRADIENT = 4, + FT_COLR_PAINTFORMAT_RADIAL_GRADIENT = 6, + FT_COLR_PAINTFORMAT_SWEEP_GRADIENT = 8, + FT_COLR_PAINTFORMAT_GLYPH = 10, + FT_COLR_PAINTFORMAT_COLR_GLYPH = 11, + FT_COLR_PAINTFORMAT_TRANSFORM = 12, + FT_COLR_PAINTFORMAT_TRANSLATE = 14, + FT_COLR_PAINTFORMAT_SCALE = 16, + FT_COLR_PAINTFORMAT_ROTATE = 24, + FT_COLR_PAINTFORMAT_SKEW = 28, + FT_COLR_PAINTFORMAT_COMPOSITE = 32, + FT_COLR_PAINT_FORMAT_MAX = 33, + FT_COLR_PAINTFORMAT_UNSUPPORTED = 255 + + } FT_PaintFormat; + + + /************************************************************************** + * + * @struct: + * FT_ColorStopIterator + * + * @description: + * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps + * state while iterating over the stops of an @FT_ColorLine, representing + * the `ColorLine` struct of the v1 extensions to 'COLR', see + * 'https://github.com/googlefonts/colr-gradients-spec'. Do not manually + * modify fields of this iterator. + * + * @fields: + * num_color_stops :: + * The number of color stops for the requested glyph index. Set by + * @FT_Get_Paint. + * + * current_color_stop :: + * The current color stop. Set by @FT_Get_Colorline_Stops. + * + * p :: + * An opaque pointer into 'COLR' table data. Set by @FT_Get_Paint. + * Updated by @FT_Get_Colorline_Stops. + * + * read_variable :: + * A boolean keeping track of whether variable color lines are to be + * read. Set by @FT_Get_Paint. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStopIterator_ + { + FT_UInt num_color_stops; + FT_UInt current_color_stop; + + FT_Byte* p; + + FT_Bool read_variable; + + } FT_ColorStopIterator; + + + /************************************************************************** + * + * @struct: + * FT_ColorIndex + * + * @description: + * A structure representing a `ColorIndex` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * palette_index :: + * The palette index into a 'CPAL' palette. + * + * alpha :: + * Alpha transparency value multiplied with the value from 'CPAL'. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorIndex_ + { + FT_UInt16 palette_index; + FT_F2Dot14 alpha; + + } FT_ColorIndex; + + + /************************************************************************** + * + * @struct: + * FT_ColorStop + * + * @description: + * A structure representing a `ColorStop` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * + * @fields: + * stop_offset :: + * The stop offset along the gradient, expressed as a 16.16 fixed-point + * coordinate. + * + * color :: + * The color information for this stop, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorStop_ + { + FT_Fixed stop_offset; + FT_ColorIndex color; + + } FT_ColorStop; + + + /************************************************************************** + * + * @enum: + * FT_PaintExtend + * + * @description: + * An enumeration representing the 'Extend' mode of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes how the gradient fill continues at the other boundaries. + * + * @since: + * 2.13 + */ + typedef enum FT_PaintExtend_ + { + FT_COLR_PAINT_EXTEND_PAD = 0, + FT_COLR_PAINT_EXTEND_REPEAT = 1, + FT_COLR_PAINT_EXTEND_REFLECT = 2 + + } FT_PaintExtend; + + + /************************************************************************** + * + * @struct: + * FT_ColorLine + * + * @description: + * A structure representing a `ColorLine` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * It describes a list of color stops along the defined gradient. + * + * @fields: + * extend :: + * The extend mode at the outer boundaries, see @FT_PaintExtend. + * + * color_stop_iterator :: + * The @FT_ColorStopIterator used to enumerate and retrieve the + * actual @FT_ColorStop's. + * + * @since: + * 2.13 + */ + typedef struct FT_ColorLine_ + { + FT_PaintExtend extend; + FT_ColorStopIterator color_stop_iterator; + + } FT_ColorLine; + + + /************************************************************************** + * + * @struct: + * FT_Affine23 + * + * @description: + * A structure used to store a 2x3 matrix. Coefficients are in + * 16.16 fixed-point format. The computation performed is + * + * ``` + * x' = x*xx + y*xy + dx + * y' = x*yx + y*yy + dy + * ``` + * + * @fields: + * xx :: + * Matrix coefficient. + * + * xy :: + * Matrix coefficient. + * + * dx :: + * x translation. + * + * yx :: + * Matrix coefficient. + * + * yy :: + * Matrix coefficient. + * + * dy :: + * y translation. + * + * @since: + * 2.13 + */ + typedef struct FT_Affine_23_ + { + FT_Fixed xx, xy, dx; + FT_Fixed yx, yy, dy; + + } FT_Affine23; + + + /************************************************************************** + * + * @enum: + * FT_Composite_Mode + * + * @description: + * An enumeration listing the 'COLR' v1 composite modes used in + * @FT_PaintComposite. For more details on each paint mode, see + * 'https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators'. + * + * @since: + * 2.13 + */ + typedef enum FT_Composite_Mode_ + { + FT_COLR_COMPOSITE_CLEAR = 0, + FT_COLR_COMPOSITE_SRC = 1, + FT_COLR_COMPOSITE_DEST = 2, + FT_COLR_COMPOSITE_SRC_OVER = 3, + FT_COLR_COMPOSITE_DEST_OVER = 4, + FT_COLR_COMPOSITE_SRC_IN = 5, + FT_COLR_COMPOSITE_DEST_IN = 6, + FT_COLR_COMPOSITE_SRC_OUT = 7, + FT_COLR_COMPOSITE_DEST_OUT = 8, + FT_COLR_COMPOSITE_SRC_ATOP = 9, + FT_COLR_COMPOSITE_DEST_ATOP = 10, + FT_COLR_COMPOSITE_XOR = 11, + FT_COLR_COMPOSITE_PLUS = 12, + FT_COLR_COMPOSITE_SCREEN = 13, + FT_COLR_COMPOSITE_OVERLAY = 14, + FT_COLR_COMPOSITE_DARKEN = 15, + FT_COLR_COMPOSITE_LIGHTEN = 16, + FT_COLR_COMPOSITE_COLOR_DODGE = 17, + FT_COLR_COMPOSITE_COLOR_BURN = 18, + FT_COLR_COMPOSITE_HARD_LIGHT = 19, + FT_COLR_COMPOSITE_SOFT_LIGHT = 20, + FT_COLR_COMPOSITE_DIFFERENCE = 21, + FT_COLR_COMPOSITE_EXCLUSION = 22, + FT_COLR_COMPOSITE_MULTIPLY = 23, + FT_COLR_COMPOSITE_HSL_HUE = 24, + FT_COLR_COMPOSITE_HSL_SATURATION = 25, + FT_COLR_COMPOSITE_HSL_COLOR = 26, + FT_COLR_COMPOSITE_HSL_LUMINOSITY = 27, + FT_COLR_COMPOSITE_MAX = 28 + + } FT_Composite_Mode; + + + /************************************************************************** + * + * @struct: + * FT_OpaquePaint + * + * @description: + * A structure representing an offset to a `Paint` value stored in any + * of the paint tables of a 'COLR' v1 font. Compare Offset<24> there. + * When 'COLR' v1 paint tables represented by FreeType objects such as + * @FT_PaintColrLayers, @FT_PaintComposite, or @FT_PaintTransform + * reference downstream nested paint tables, we do not immediately + * retrieve them but encapsulate their location in this type. Use + * @FT_Get_Paint to retrieve the actual @FT_COLR_Paint object that + * describes the details of the respective paint table. + * + * @fields: + * p :: + * An internal offset to a Paint table, needs to be set to NULL before + * passing this struct as an argument to @FT_Get_Paint. + * + * insert_root_transform :: + * An internal boolean to track whether an initial root transform is + * to be provided. Do not set this value. + * + * @since: + * 2.13 + */ + typedef struct FT_Opaque_Paint_ + { + FT_Byte* p; + FT_Bool insert_root_transform; + } FT_OpaquePaint; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrLayers + * + * @description: + * A structure representing a `PaintColrLayers` table of a 'COLR' v1 + * font. This table describes a set of layers that are to be composited + * with composite mode `FT_COLR_COMPOSITE_SRC_OVER`. The return value + * of this function is an @FT_LayerIterator initialized so that it can + * be used with @FT_Get_Paint_Layers to retrieve the @FT_OpaquePaint + * objects as references to each layer. + * + * @fields: + * layer_iterator :: + * The layer iterator that describes the layers of this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrLayers_ + { + FT_LayerIterator layer_iterator; + + } FT_PaintColrLayers; + + + /************************************************************************** + * + * @struct: + * FT_PaintSolid + * + * @description: + * A structure representing a `PaintSolid` value of the 'COLR' v1 + * extensions, see 'https://github.com/googlefonts/colr-gradients-spec'. + * Using a `PaintSolid` value means that the glyph layer filled with + * this paint is solid-colored and does not contain a gradient. + * + * @fields: + * color :: + * The color information for this solid paint, see @FT_ColorIndex. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSolid_ + { + FT_ColorIndex color; + + } FT_PaintSolid; + + + /************************************************************************** + * + * @struct: + * FT_PaintLinearGradient + * + * @description: + * A structure representing a `PaintLinearGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a linear gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * p0 :: + * The starting point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p1 :: + * The end point of the gradient definition in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * p2 :: + * Optional point~p2 to rotate the gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * Otherwise equal to~p0. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintLinearGradient_ + { + FT_ColorLine colorline; + + /* TODO: Potentially expose those as x0, y0 etc. */ + FT_Vector p0; + FT_Vector p1; + FT_Vector p2; + + } FT_PaintLinearGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintRadialGradient + * + * @description: + * A structure representing a `PaintRadialGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a radial gradient. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * c0 :: + * The center of the starting point of the radial gradient in font + * units represented as a 16.16 fixed-point `FT_Vector`. + * + * r0 :: + * The radius of the starting circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * c1 :: + * The center of the end point of the radial gradient in font units + * represented as a 16.16 fixed-point `FT_Vector`. + * + * r1 :: + * The radius of the end circle of the radial gradient in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintRadialGradient_ + { + FT_ColorLine colorline; + + FT_Vector c0; + FT_Pos r0; + FT_Vector c1; + FT_Pos r1; + + } FT_PaintRadialGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintSweepGradient + * + * @description: + * A structure representing a `PaintSweepGradient` value of the 'COLR' + * v1 extensions, see + * 'https://github.com/googlefonts/colr-gradients-spec'. The glyph + * layer filled with this paint is drawn filled with a sweep gradient + * from `start_angle` to `end_angle`. + * + * @fields: + * colorline :: + * The @FT_ColorLine information for this paint, i.e., the list of + * color stops along the gradient. + * + * center :: + * The center of the sweep gradient in font units represented as a + * vector of 16.16 fixed-point values. + * + * start_angle :: + * The start angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * end_angle :: + * The end angle of the sweep gradient in 16.16 fixed-point + * format specifying degrees divided by 180.0 (as in the + * spec). Multiply by 180.0f to receive degrees value. Values are + * given counter-clockwise, starting from the (positive) y~axis. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSweepGradient_ + { + FT_ColorLine colorline; + + FT_Vector center; + FT_Fixed start_angle; + FT_Fixed end_angle; + + } FT_PaintSweepGradient; + + + /************************************************************************** + * + * @struct: + * FT_PaintGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintGlyph` paint table. + * + * @fields: + * paint :: + * An opaque paint object pointing to a `Paint` table that serves as + * the fill for the glyph ID. + * + * glyphID :: + * The glyph ID from the 'glyf' table, which serves as the contour + * information that is filled with paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintGlyph_ + { + FT_OpaquePaint paint; + FT_UInt glyphID; + + } FT_PaintGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintColrGlyph + * + * @description: + * A structure representing a 'COLR' v1 `PaintColorGlyph` paint table. + * + * @fields: + * glyphID :: + * The glyph ID from the `BaseGlyphV1List` table that is drawn for + * this paint. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintColrGlyph_ + { + FT_UInt glyphID; + + } FT_PaintColrGlyph; + + + /************************************************************************** + * + * @struct: + * FT_PaintTransform + * + * @description: + * A structure representing a 'COLR' v1 `PaintTransform` paint table. + * + * @fields: + * paint :: + * An opaque paint that is subject to being transformed. + * + * affine :: + * A 2x3 transformation matrix in @FT_Affine23 format containing + * 16.16 fixed-point values. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTransform_ + { + FT_OpaquePaint paint; + FT_Affine23 affine; + + } FT_PaintTransform; + + + /************************************************************************** + * + * @struct: + * FT_PaintTranslate + * + * @description: + * A structure representing a 'COLR' v1 `PaintTranslate` paint table. + * Used for translating downstream paints by a given x and y~delta. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * dx :: + * Translation in x~direction in font units represented as a + * 16.16 fixed-point value. + * + * dy :: + * Translation in y~direction in font units represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintTranslate_ + { + FT_OpaquePaint paint; + + FT_Fixed dx; + FT_Fixed dy; + + } FT_PaintTranslate; + + + /************************************************************************** + * + * @struct: + * FT_PaintScale + * + * @description: + * A structure representing all of the 'COLR' v1 'PaintScale*' paint + * tables. Used for scaling downstream paints by a given x and y~scale, + * with a given center. This structure is used for all 'PaintScale*' + * types that are part of specification; fields of this structure are + * filled accordingly. If there is a center, the center values are set, + * otherwise they are set to the zero coordinate. If the source font + * file has 'PaintScaleUniform*' set, the scale values are set + * accordingly to the same value. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * scaled. + * + * scale_x :: + * Scale factor in x~direction represented as a + * 16.16 fixed-point value. + * + * scale_y :: + * Scale factor in y~direction represented as a + * 16.16 fixed-point value. + * + * center_x :: + * x~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * center_y :: + * y~coordinate of center point to scale from represented as a + * 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintScale_ + { + FT_OpaquePaint paint; + + FT_Fixed scale_x; + FT_Fixed scale_y; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintScale; + + + /************************************************************************** + * + * @struct: + * FT_PaintRotate + * + * @description: + * A structure representing a 'COLR' v1 `PaintRotate` paint table. Used + * for rotating downstream paints with a given center and angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * rotated. + * + * angle :: + * The rotation angle that is to be applied in degrees divided by + * 180.0 (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees value. + * + * center_x :: + * The x~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the rotation in font + * units represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + + typedef struct FT_PaintRotate_ + { + FT_OpaquePaint paint; + + FT_Fixed angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintRotate; + + + /************************************************************************** + * + * @struct: + * FT_PaintSkew + * + * @description: + * A structure representing a 'COLR' v1 `PaintSkew` paint table. Used + * for skewing or shearing downstream paints by a given center and + * angle. + * + * @fields: + * paint :: + * An @FT_OpaquePaint object referencing the paint that is to be + * skewed. + * + * x_skew_angle :: + * The skewing angle in x~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * y_skew_angle :: + * The skewing angle in y~direction in degrees divided by 180.0 + * (as in the spec) represented as a 16.16 fixed-point + * value. Multiply by 180.0f to receive degrees. + * + * center_x :: + * The x~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * center_y :: + * The y~coordinate of the pivot point of the skew in font units + * represented as a 16.16 fixed-point value. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintSkew_ + { + FT_OpaquePaint paint; + + FT_Fixed x_skew_angle; + FT_Fixed y_skew_angle; + + FT_Fixed center_x; + FT_Fixed center_y; + + } FT_PaintSkew; + + + /************************************************************************** + * + * @struct: + * FT_PaintComposite + * + * @description: + * A structure representing a 'COLR' v1 `PaintComposite` paint table. + * Used for compositing two paints in a 'COLR' v1 directed acyclic graph. + * + * @fields: + * source_paint :: + * An @FT_OpaquePaint object referencing the source that is to be + * composited. + * + * composite_mode :: + * An @FT_Composite_Mode enum value determining the composition + * operation. + * + * backdrop_paint :: + * An @FT_OpaquePaint object referencing the backdrop paint that + * `source_paint` is composited onto. + * + * @since: + * 2.13 + */ + typedef struct FT_PaintComposite_ + { + FT_OpaquePaint source_paint; + FT_Composite_Mode composite_mode; + FT_OpaquePaint backdrop_paint; + + } FT_PaintComposite; + + + /************************************************************************** + * + * @union: + * FT_COLR_Paint + * + * @description: + * A union object representing format and details of a paint table of a + * 'COLR' v1 font, see + * 'https://github.com/googlefonts/colr-gradients-spec'. Use + * @FT_Get_Paint to retrieve a @FT_COLR_Paint for an @FT_OpaquePaint + * object. + * + * @fields: + * format :: + * The gradient format for this Paint structure. + * + * u :: + * Union of all paint table types: + * + * * @FT_PaintColrLayers + * * @FT_PaintGlyph + * * @FT_PaintSolid + * * @FT_PaintLinearGradient + * * @FT_PaintRadialGradient + * * @FT_PaintSweepGradient + * * @FT_PaintTransform + * * @FT_PaintTranslate + * * @FT_PaintRotate + * * @FT_PaintSkew + * * @FT_PaintComposite + * * @FT_PaintColrGlyph + * + * @since: + * 2.13 + */ + typedef struct FT_COLR_Paint_ + { + FT_PaintFormat format; + + union + { + FT_PaintColrLayers colr_layers; + FT_PaintGlyph glyph; + FT_PaintSolid solid; + FT_PaintLinearGradient linear_gradient; + FT_PaintRadialGradient radial_gradient; + FT_PaintSweepGradient sweep_gradient; + FT_PaintTransform transform; + FT_PaintTranslate translate; + FT_PaintScale scale; + FT_PaintRotate rotate; + FT_PaintSkew skew; + FT_PaintComposite composite; + FT_PaintColrGlyph colr_glyph; + + } u; + + } FT_COLR_Paint; + + + /************************************************************************** + * + * @enum: + * FT_Color_Root_Transform + * + * @description: + * An enumeration to specify whether @FT_Get_Color_Glyph_Paint is to + * return a root transform to configure the client's graphics context + * matrix. + * + * @values: + * FT_COLOR_INCLUDE_ROOT_TRANSFORM :: + * Do include the root transform as the initial @FT_COLR_Paint object. + * + * FT_COLOR_NO_ROOT_TRANSFORM :: + * Do not output an initial root transform. + * + * @since: + * 2.13 + */ + typedef enum FT_Color_Root_Transform_ + { + FT_COLOR_INCLUDE_ROOT_TRANSFORM, + FT_COLOR_NO_ROOT_TRANSFORM, + + FT_COLOR_ROOT_TRANSFORM_MAX + + } FT_Color_Root_Transform; + + + /************************************************************************** + * + * @struct: + * FT_ClipBox + * + * @description: + * A structure representing a 'COLR' v1 'ClipBox' table. 'COLR' v1 + * glyphs may optionally define a clip box for aiding allocation or + * defining a maximum drawable region. Use @FT_Get_Color_Glyph_ClipBox + * to retrieve it. + * + * @fields: + * bottom_left :: + * The bottom left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_left :: + * The top left corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * top_right :: + * The top right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * bottom_right :: + * The bottom right corner of the clip box as an @FT_Vector with + * fixed-point coordinates in 26.6 format. + * + * @since: + * 2.13 + */ + typedef struct FT_ClipBox_ + { + FT_Vector bottom_left; + FT_Vector top_left; + FT_Vector top_right; + FT_Vector bottom_right; + + } FT_ClipBox; + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_Paint + * + * @description: + * This is the starting point and interface to color gradient + * information in a 'COLR' v1 table in OpenType fonts to recursively + * retrieve the paint tables for the directed acyclic graph of a colored + * glyph, given a glyph ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * In a 'COLR' v1 font, each color glyph defines a directed acyclic + * graph of nested paint tables, such as `PaintGlyph`, `PaintSolid`, + * `PaintLinearGradient`, `PaintRadialGradient`, and so on. Using this + * function and specifying a glyph ID, one retrieves the root paint + * table for this glyph ID. + * + * This function allows control whether an initial root transform is + * returned to configure scaling, transform, and translation correctly + * on the client's graphics context. The initial root transform is + * computed and returned according to the values configured for @FT_Size + * and @FT_Set_Transform on the @FT_Face object, see below for details + * of the `root_transform` parameter. This has implications for a + * client 'COLR' v1 implementation: When this function returns an + * initially computed root transform, at the time of executing the + * @FT_PaintGlyph operation, the contours should be retrieved using + * @FT_Load_Glyph at unscaled, untransformed size. This is because the + * root transform applied to the graphics context will take care of + * correct scaling. + * + * Alternatively, to allow hinting of contours, at the time of executing + * @FT_Load_Glyph, the current graphics context transformation matrix + * can be decomposed into a scaling matrix and a remainder, and + * @FT_Load_Glyph can be used to retrieve the contours at scaled size. + * Care must then be taken to blit or clip to the graphics context with + * taking this remainder transformation into account. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the root paint table. + * + * root_transform :: + * Specifies whether an initially computed root is returned by the + * @FT_PaintTransform operation to account for the activated size + * (see @FT_Activate_Size) and the configured transform and translate + * (see @FT_Set_Transform). + * + * This root transform is returned before nodes of the glyph graph of + * the font are returned. Subsequent @FT_COLR_Paint structures + * contain unscaled and untransformed values. The inserted root + * transform enables the client application to apply an initial + * transform to its graphics context. When executing subsequent + * FT_COLR_Paint operations, values from @FT_COLR_Paint operations + * will ultimately be correctly scaled because of the root transform + * applied to the graphics context. Use + * @FT_COLOR_INCLUDE_ROOT_TRANSFORM to include the root transform, use + * @FT_COLOR_NO_ROOT_TRANSFORM to not include it. The latter may be + * useful when traversing the 'COLR' v1 glyph graph and reaching a + * @FT_PaintColrGlyph. When recursing into @FT_PaintColrGlyph and + * painting that inline, no additional root transform is needed as it + * has already been applied to the graphics context at the beginning + * of drawing this glyph. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Color_Glyph_ClipBox + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @return: + * Value~1 if a clip box is found. If no clip box is found or an error + * occurred, value~0 is returned. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint_Layers + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * If the root paint of a color glyph, or a nested paint of a 'COLR' + * glyph is a `PaintColrLayers` table, this function retrieves the + * layers of the `PaintColrLayers` table. + * + * The @FT_PaintColrLayers object contains an @FT_LayerIterator, which + * is used here to iterate over the layers. Each layer is returned as + * an @FT_OpaquePaint object, which then can be used with @FT_Get_Paint + * to retrieve the actual paint object. + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The @FT_OpaquePaint object that references the actual paint table. + * The respective actual @FT_COLR_Paint object is retrieved via + * @FT_Get_Paint. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + + /************************************************************************** + * + * @function: + * FT_Get_Colorline_Stops + * + * @description: + * This is an interface to color gradient information in a 'COLR' v1 + * table in OpenType fonts to iteratively retrieve the gradient and + * solid fill information for colored glyph layers for a specified glyph + * ID. + * + * https://github.com/googlefonts/colr-gradients-spec + * + * @input: + * face :: + * A handle to the parent face object. + * + * @inout: + * iterator :: + * The retrieved @FT_ColorStopIterator, configured on an @FT_ColorLine, + * which in turn got retrieved via paint information in + * @FT_PaintLinearGradient or @FT_PaintRadialGradient. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Colorline_Stops( FT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @function: + * FT_Get_Paint + * + * @description: + * Access the details of a paint using an @FT_OpaquePaint opaque paint + * object, which internally stores the offset to the respective `Paint` + * object in the 'COLR' table. + * + * @input: + * face :: + * A handle to the parent face object. + * + * opaque_paint :: + * The opaque paint object for which the underlying @FT_COLR_Paint + * data is to be retrieved. + * + * @output: + * paint :: + * The specific @FT_COLR_Paint object containing information coming + * from one of the font's `Paint*` tables. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occurred. + * + * @since: + * 2.13 + */ + FT_EXPORT( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + /* */ diff --git a/src/thirdparty/freetype2/include/freetype/ftdriver.h b/src/thirdparty/freetype2/include/freetype/ftdriver.h index 497bde9f6..b65a06ab6 100644 --- a/src/thirdparty/freetype2/include/freetype/ftdriver.h +++ b/src/thirdparty/freetype2/include/freetype/ftdriver.h @@ -4,7 +4,7 @@ * * FreeType API for controlling driver modules (specification only). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,8 @@ #ifndef FTDRIVER_H_ #define FTDRIVER_H_ -#include -#include FT_FREETYPE_H -#include FT_PARAMETER_TAGS_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -54,10 +53,10 @@ FT_BEGIN_HEADER * reasons. * * Available properties are @increase-x-height, @no-stem-darkening - * (experimental), @darkening-parameters (experimental), @warping - * (experimental), @glyph-to-script-map (experimental), @fallback-script - * (experimental), and @default-script (experimental), as documented in - * the @properties section. + * (experimental), @darkening-parameters (experimental), + * @glyph-to-script-map (experimental), @fallback-script (experimental), + * and @default-script (experimental), as documented in the @properties + * section. * */ @@ -85,15 +84,15 @@ FT_BEGIN_HEADER * @properties section. * * - * **Hinting and antialiasing principles of the new engine** + * **Hinting and anti-aliasing principles of the new engine** * * The rasterizer is positioning horizontal features (e.g., ascender * height & x-height, or crossbars) on the pixel grid and minimizing the - * amount of antialiasing applied to them, while placing vertical + * amount of anti-aliasing applied to them, while placing vertical * features (vertical stems) on the pixel grid without hinting, thus * representing the stem position and weight accurately. Sometimes the * vertical stems may be only partially black. In this context, - * 'antialiasing' means that stems are not positioned exactly on pixel + * 'anti-aliasing' means that stems are not positioned exactly on pixel * borders, causing a fuzzy appearance. * * There are two principles behind this approach. @@ -109,7 +108,7 @@ FT_BEGIN_HEADER * sizes are comparable to kerning values and thus would be noticeable * (and distracting) while reading if hinting were applied. * - * One of the reasons to not hint horizontally is antialiasing for LCD + * One of the reasons to not hint horizontally is anti-aliasing for LCD * screens: The pixel geometry of modern displays supplies three vertical * subpixels as the eye moves horizontally across each visible pixel. On * devices where we can be certain this characteristic is present a @@ -117,7 +116,7 @@ FT_BEGIN_HEADER * weight. In Western writing systems this turns out to be the more * critical direction anyway; the weights and spacing of vertical stems * (see above) are central to Armenian, Cyrillic, Greek, and Latin type - * designs. Even when the rasterizer uses greyscale antialiasing instead + * designs. Even when the rasterizer uses greyscale anti-aliasing instead * of color (a necessary compromise when one doesn't know the screen * characteristics), the unhinted vertical features preserve the design's * weight and spacing much better than aliased type would. @@ -135,7 +134,7 @@ FT_BEGIN_HEADER * each being rounded to the nearest pixel edge, taking care of overshoot * suppression at small sizes, stem darkening, and scaling. * - * Hstems (this is, hint values defined in the font to help align + * Hstems (that is, hint values defined in the font to help align * horizontal features) that fall within a blue zone are said to be * 'captured' and are aligned to that zone. Uncaptured stems are moved * in one of four ways, top edge up or down, bottom edge up or down. @@ -213,16 +212,14 @@ FT_BEGIN_HEADER * @description: * While FreeType's TrueType driver doesn't expose API functions by * itself, it is possible to control its behaviour with @FT_Property_Set - * and @FT_Property_Get. The following lists the available properties - * together with the necessary macros and structures. + * and @FT_Property_Get. * - * The TrueType driver's module name is 'truetype'. + * The TrueType driver's module name is 'truetype'; a single property + * @interpreter-version is available, as documented in the @properties + * section. * - * A single property @interpreter-version is available, as documented in - * the @properties section. - * - * We start with a list of definitions, kindly provided by Greg - * Hitchcock. + * To help understand the differences between interpreter versions, we + * introduce a list of definitions, kindly provided by Greg Hitchcock. * * _Bi-Level Rendering_ * @@ -285,7 +282,7 @@ FT_BEGIN_HEADER * minimize hinting techniques that were problematic with the extra * resolution of ClearType; see * http://rastertragedy.com/RTRCh4.htm#Sec1 and - * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx. + * https://learn.microsoft.com/typography/cleartype/truetypecleartype. * This technique is not to be confused with ClearType compatible widths. * ClearType backward compatibility has no direct impact on changing * advance widths, but there might be an indirect impact on disabling @@ -301,6 +298,31 @@ FT_BEGIN_HEADER */ + /************************************************************************** + * + * @section: + * ot_svg_driver + * + * @title: + * The SVG driver + * + * @abstract: + * Controlling the external rendering of OT-SVG glyphs. + * + * @description: + * By default, FreeType can only load the 'SVG~' table of OpenType fonts + * if configuration macro `FT_CONFIG_OPTION_SVG` is defined. To make it + * render SVG glyphs, an external SVG rendering library is needed. All + * details on the interface between FreeType and the external library + * via function hooks can be found in section @svg_fonts. + * + * The OT-SVG driver's module name is 'ot-svg'; it supports a single + * property called @svg-hooks, documented below in the @properties + * section. + * + */ + + /************************************************************************** * * @section: @@ -363,12 +385,8 @@ FT_BEGIN_HEADER * The same holds for the Type~1 and CID modules if compiled with * `T1_CONFIG_OPTION_OLD_ENGINE`. * - * For the 'cff' module, the default engine is 'freetype' if - * `CFF_CONFIG_OPTION_OLD_ENGINE` is defined, and 'adobe' otherwise. - * - * For both the 'type1' and 't1cid' modules, the default engine is - * 'freetype' if `T1_CONFIG_OPTION_OLD_ENGINE` is defined, and 'adobe' - * otherwise. + * For the 'cff' module, the default engine is 'adobe'. For both the + * 'type1' and 't1cid' modules, the default engine is 'adobe', too. * * @note: * This property can be used with @FT_Property_Get also. @@ -427,12 +445,8 @@ FT_BEGIN_HEADER * counteracts the 'thinning out' of glyphs, making text remain readable * at smaller sizes. * - * By default, the Adobe engines for CFF, Type~1, and CID fonts darken - * stems at smaller sizes, regardless of hinting, to enhance contrast. - * Setting this property, stem darkening gets switched off. - * * For the auto-hinter, stem-darkening is experimental currently and thus - * switched off by default (this is, `no-stem-darkening` is set to TRUE + * switched off by default (that is, `no-stem-darkening` is set to TRUE * by default). Total consistency with the CFF driver is not achieved * right now because the emboldening method differs and glyphs must be * scaled down on the Y-axis to keep outline points inside their @@ -637,11 +651,8 @@ FT_BEGIN_HEADER * Windows~98; only grayscale and B/W rasterizing is supported. * * TT_INTERPRETER_VERSION_38 :: - * Version~38 corresponds to MS rasterizer v.1.9; it is roughly - * equivalent to the hinting provided by DirectWrite ClearType (as can - * be found, for example, in the Internet Explorer~9 running on - * Windows~7). It is used in FreeType to select the 'Infinality' - * subpixel hinting code. The code may be removed in a future version. + * Version~38 is the same Version~40. The original 'Infinality' code is + * no longer available. * * TT_INTERPRETER_VERSION_40 :: * Version~40 corresponds to MS rasterizer v.2.1; it is roughly @@ -773,7 +784,7 @@ FT_BEGIN_HEADER * * Details on subpixel hinting and some of the necessary tweaks can be * found in Greg Hitchcock's whitepaper at - * 'https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx'. + * 'https://learn.microsoft.com/typography/cleartype/truetypecleartype'. * Note that FreeType currently doesn't really 'subpixel hint' (6x1, 6x2, * or 6x5 supersampling) like discussed in the paper. Depending on the * chosen interpreter, it simply ignores instructions on vertical stems @@ -807,6 +818,113 @@ FT_BEGIN_HEADER */ + /************************************************************************** + * + * @property: + * spread + * + * @description: + * This property of the 'sdf' and 'bsdf' renderers defines how the signed + * distance field (SDF) is represented in the output bitmap. The output + * values are calculated as follows, '128 * ( SDF / spread + 1 )', with + * the result clamped to the 8-bit range [0..255]. Therefore, 'spread' + * is also the maximum euclidean distance from the edge after which the + * values are clamped. The spread is specified in pixels with the + * default value of 8. For accurate SDF texture mapping (interpolation), + * the spread should be large enough to accommodate the target grid unit. + * + * @example: + * The following example code demonstrates how to set the SDF spread + * (omitting the error handling). + * + * ``` + * FT_Library library; + * FT_Int spread = 2; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "sdf", "spread", &spread ); + * ``` + * + * @note: + * FreeType has two rasterizers for generating SDF, namely: + * + * 1. `sdf` for generating SDF directly from glyph's outline, and + * + * 2. `bsdf` for generating SDF from rasterized bitmaps. + * + * Depending on the glyph type (i.e., outline or bitmap), one of the two + * rasterizers is chosen at runtime and used for generating SDFs. To + * force the use of `bsdf` you should render the glyph with any of the + * FreeType's other rendering modes (e.g., `FT_RENDER_MODE_NORMAL`) and + * then re-render with `FT_RENDER_MODE_SDF`. + * + * There are some issues with stability and possible failures of the SDF + * renderers (specifically `sdf`). + * + * 1. The `sdf` rasterizer is sensitive to really small features (e.g., + * sharp turns that are less than 1~pixel) and imperfections in the + * glyph's outline, causing artifacts in the final output. + * + * 2. The `sdf` rasterizer has limited support for handling intersecting + * contours and *cannot* handle self-intersecting contours whatsoever. + * Self-intersection happens when a single connected contour + * intersects itself at some point; having these in your font + * definitely poses a problem to the rasterizer and cause artifacts, + * too. + * + * 3. Generating SDF for really small glyphs may result in undesirable + * output; the pixel grid (which stores distance information) becomes + * too coarse. + * + * 4. Since the output buffer is normalized, precision at smaller spreads + * is greater than precision at larger spread values because the + * output range of [0..255] gets mapped to a smaller SDF range. A + * spread of~2 should be sufficient in most cases. + * + * Points (1) and (2) can be avoided by using the `bsdf` rasterizer, + * which is more stable than the `sdf` rasterizer in general. + * + * @since: + * 2.11 + */ + + + /************************************************************************** + * + * @property: + * svg-hooks + * + * @description: + * Set up the interface between FreeType and an extern SVG rendering + * library like 'librsvg'. All details on the function hooks can be + * found in section @svg_fonts. + * + * @example: + * The following example code expects that the four hook functions + * `svg_*` are defined elsewhere. Error handling is omitted, too. + * + * ``` + * FT_Library library; + * SVG_RendererHooks hooks = { + * (SVG_Lib_Init_Func)svg_init, + * (SVG_Lib_Free_Func)svg_free, + * (SVG_Lib_Render_Func)svg_render, + * (SVG_Lib_Preset_Slot_Func)svg_preset_slot }; + * + * + * FT_Init_FreeType( &library ); + * + * FT_Property_Set( library, "ot-svg", + * "svg-hooks", &hooks ); + * ``` + * + * @since: + * 2.12 + */ + + /************************************************************************** * * @property: @@ -1171,48 +1289,18 @@ FT_BEGIN_HEADER * warping * * @description: - * **Experimental only** + * **Obsolete** * - * If FreeType gets compiled with option `AF_CONFIG_OPTION_USE_WARPER` to - * activate the warp hinting code in the auto-hinter, this property - * switches warping on and off. + * This property was always experimental and probably never worked + * correctly. It was entirely removed from the FreeType~2 sources. This + * entry is only here for historical reference. * - * Warping only works in 'normal' auto-hinting mode replacing it. The - * idea of the code is to slightly scale and shift a glyph along the + * Warping only worked in 'normal' auto-hinting mode replacing it. The + * idea of the code was to slightly scale and shift a glyph along the * non-hinted dimension (which is usually the horizontal axis) so that as - * much of its segments are aligned (more or less) to the grid. To find + * much of its segments were aligned (more or less) to the grid. To find * out a glyph's optimal scaling and shifting value, various parameter - * combinations are tried and scored. - * - * By default, warping is off. - * - * @note: - * This property can be used with @FT_Property_Get also. - * - * This property can be set via the `FREETYPE_PROPERTIES` environment - * variable (using values 1 and 0 for 'on' and 'off', respectively). - * - * The warping code can also change advance widths. Have a look at the - * `lsb_delta` and `rsb_delta` fields in the @FT_GlyphSlotRec structure - * for details on improving inter-glyph distances while rendering. - * - * Since warping is a global property of the auto-hinter it is best to - * change its value before rendering any face. Otherwise, you should - * reload all faces that get auto-hinted in 'normal' hinting mode. - * - * @example: - * This example shows how to switch on warping (omitting the error - * handling). - * - * ``` - * FT_Library library; - * FT_Bool warping = 1; - * - * - * FT_Init_FreeType( &library ); - * - * FT_Property_Set( library, "autofitter", "warping", &warping ); - * ``` + * combinations were tried and scored. * * @since: * 2.6 diff --git a/src/thirdparty/freetype2/include/freetype/fterrdef.h b/src/thirdparty/freetype2/include/freetype/fterrdef.h index 9bc7dc65e..3e591bede 100644 --- a/src/thirdparty/freetype2/include/freetype/fterrdef.h +++ b/src/thirdparty/freetype2/include/freetype/fterrdef.h @@ -4,7 +4,7 @@ * * FreeType error codes (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -101,6 +101,8 @@ "too many hints" ) FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, "invalid pixel size" ) + FT_ERRORDEF_( Invalid_SVG_Document, 0x18, + "invalid SVG document" ) /* handle errors */ @@ -234,6 +236,8 @@ "found FDEF or IDEF opcode in glyf bytecode" ) FT_ERRORDEF_( Missing_Bitmap, 0x9D, "missing bitmap in strike" ) + FT_ERRORDEF_( Missing_SVG_Hooks, 0x9E, + "SVG hooks have not been set" ) /* CFF, CID, and Type 1 errors */ diff --git a/src/thirdparty/freetype2/include/freetype/fterrors.h b/src/thirdparty/freetype2/include/freetype/fterrors.h index 2b47eb209..eca494f90 100644 --- a/src/thirdparty/freetype2/include/freetype/fterrors.h +++ b/src/thirdparty/freetype2/include/freetype/fterrors.h @@ -4,7 +4,7 @@ * * FreeType error code handling (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,7 +29,7 @@ * * @description: * The header file `fterrors.h` (which is automatically included by - * `freetype.h` defines the handling of FreeType's enumeration + * `freetype.h`) defines the handling of FreeType's enumeration * constants. It can also be used to generate error message strings * with a small macro trick explained below. * @@ -89,7 +89,7 @@ * const char* err_msg; * } ft_errors[] = * - * #include FT_ERRORS_H + * #include * ``` * * An alternative to using an array is a switch statement. @@ -124,7 +124,7 @@ /* include module base error codes */ -#include FT_MODULE_ERRORS_H +#include /*******************************************************************/ @@ -197,7 +197,7 @@ /* now include the error codes */ -#include FT_ERROR_DEFINITIONS_H +#include #ifdef FT_ERROR_END_LIST @@ -232,11 +232,16 @@ #undef FT_ERR_PREFIX #endif - /* FT_INCLUDE_ERR_PROTOS: Control if function prototypes should be */ - /* included with `#include FT_ERRORS_H'. This is */ - /* only true where `FT_ERRORDEF` is undefined. */ - /* FT_ERR_PROTOS_DEFINED: Actual multiple-inclusion protection of */ - /* `fterrors.h`. */ + /* FT_INCLUDE_ERR_PROTOS: Control whether function prototypes should be */ + /* included with */ + /* */ + /* #include */ + /* */ + /* This is only true where `FT_ERRORDEF` is */ + /* undefined. */ + /* */ + /* FT_ERR_PROTOS_DEFINED: Actual multiple-inclusion protection of */ + /* `fterrors.h`. */ #ifdef FT_INCLUDE_ERR_PROTOS #undef FT_INCLUDE_ERR_PROTOS @@ -276,6 +281,8 @@ FT_BEGIN_HEADER FT_EXPORT( const char* ) FT_Error_String( FT_Error error_code ); + /* */ + FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/ftfntfmt.h b/src/thirdparty/freetype2/include/freetype/ftfntfmt.h index aae0b1326..5df82447d 100644 --- a/src/thirdparty/freetype2/include/freetype/ftfntfmt.h +++ b/src/thirdparty/freetype2/include/freetype/ftfntfmt.h @@ -4,7 +4,7 @@ * * Support functions for font formats. * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTFNTFMT_H_ #define FTFNTFMT_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftgasp.h b/src/thirdparty/freetype2/include/freetype/ftgasp.h index 24673d8ce..77e5a7e7b 100644 --- a/src/thirdparty/freetype2/include/freetype/ftgasp.h +++ b/src/thirdparty/freetype2/include/freetype/ftgasp.h @@ -4,7 +4,7 @@ * * Access of TrueType's 'gasp' table (specification). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTGASP_H_ #define FTGASP_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftglyph.h b/src/thirdparty/freetype2/include/freetype/ftglyph.h index fedab8491..3691781cf 100644 --- a/src/thirdparty/freetype2/include/freetype/ftglyph.h +++ b/src/thirdparty/freetype2/include/freetype/ftglyph.h @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -33,8 +33,7 @@ #define FTGLYPH_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -127,7 +126,7 @@ FT_BEGIN_HEADER * * @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. + * 'sub-class' of @FT_Glyph, and a pointer to @FT_BitmapGlyphRec. */ typedef struct FT_BitmapGlyphRec_* FT_BitmapGlyph; @@ -143,7 +142,7 @@ FT_BEGIN_HEADER * * @fields: * root :: - * The root @FT_Glyph fields. + * The root fields of @FT_Glyph. * * left :: * The left-side bearing, i.e., the horizontal distance from the @@ -182,7 +181,7 @@ FT_BEGIN_HEADER * * @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. + * 'sub-class' of @FT_Glyph, and a pointer to @FT_OutlineGlyphRec. */ typedef struct FT_OutlineGlyphRec_* FT_OutlineGlyph; @@ -223,6 +222,92 @@ FT_BEGIN_HEADER } FT_OutlineGlyphRec; + /************************************************************************** + * + * @type: + * FT_SvgGlyph + * + * @description: + * A handle to an object used to model an SVG glyph. This is a + * 'sub-class' of @FT_Glyph, and a pointer to @FT_SvgGlyphRec. + * + * @since: + * 2.12 + */ + typedef struct FT_SvgGlyphRec_* FT_SvgGlyph; + + + /************************************************************************** + * + * @struct: + * FT_SvgGlyphRec + * + * @description: + * A structure used for OT-SVG glyphs. This is a 'sub-class' of + * @FT_GlyphRec. + * + * @fields: + * root :: + * The root @FT_GlyphRec fields. + * + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * glyph_index :: + * The index of the glyph to be rendered. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * Translation to apply to the glyph while rendering. + * + * @note: + * The Glyph Management API requires @FT_Glyph or its 'sub-class' to have + * all the information needed to completely define the glyph's rendering. + * Outline-based glyphs can directly apply transformations to the outline + * but this is not possible for an SVG document that hasn't been parsed. + * Therefore, the transformation is stored along with the document. In + * the absence of a 'ViewBox' or 'Width'/'Height' attribute, the size of + * the ViewPort should be assumed to be 'units_per_EM'. + */ + typedef struct FT_SvgGlyphRec_ + { + FT_GlyphRec root; + + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_UInt glyph_index; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SvgGlyphRec; + + /************************************************************************** * * @function: @@ -270,7 +355,7 @@ FT_BEGIN_HEADER * * @output: * aglyph :: - * A handle to the glyph object. + * A handle to the glyph object. `NULL` in case of error. * * @return: * FreeType error code. 0~means success. @@ -300,7 +385,7 @@ FT_BEGIN_HEADER * * @output: * target :: - * A handle to the target glyph object. 0~in case of error. + * A handle to the target glyph object. `NULL` in case of error. * * @return: * FreeType error code. 0~means success. @@ -328,7 +413,7 @@ FT_BEGIN_HEADER * * delta :: * A pointer to a 2d vector to apply. Coordinates are expressed in - * 1/64th of a pixel. + * 1/64 of a pixel. * * @return: * FreeType error code (if not 0, the glyph format is not scalable). @@ -338,9 +423,9 @@ FT_BEGIN_HEADER * vector. */ FT_EXPORT( FT_Error ) - FT_Glyph_Transform( FT_Glyph glyph, - FT_Matrix* matrix, - FT_Vector* delta ); + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ); /************************************************************************** @@ -415,7 +500,7 @@ FT_BEGIN_HEADER * @output: * acbox :: * The glyph coordinate bounding box. Coordinates are expressed in - * 1/64th of pixels if it is grid-fitted. + * 1/64 of pixels if it is grid-fitted. * * @note: * Coordinates are relative to the glyph origin, using the y~upwards @@ -499,9 +584,9 @@ FT_BEGIN_HEADER * 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 + * The first parameter is a pointer to an @FT_Glyph handle that will be * _replaced_ by this function (with newly allocated data). Typically, - * you would use (omitting error handling): + * you would do something like the following (omitting error handling). * * ``` * FT_Glyph glyph; @@ -518,7 +603,7 @@ FT_BEGIN_HEADER * if ( glyph->format != FT_GLYPH_FORMAT_BITMAP ) * { * error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, - * 0, 1 ); + * 0, 1 ); * if ( error ) // `glyph' unchanged * ... * } @@ -533,7 +618,7 @@ FT_BEGIN_HEADER * FT_Done_Glyph( glyph ); * ``` * - * Here is another example, again without error handling: + * Here is another example, again without error handling. * * ``` * FT_Glyph glyphs[MAX_GLYPHS] @@ -570,10 +655,10 @@ FT_BEGIN_HEADER * ``` */ FT_EXPORT( FT_Error ) - FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, - FT_Render_Mode render_mode, - FT_Vector* origin, - FT_Bool destroy ); + FT_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ); /************************************************************************** @@ -586,7 +671,7 @@ FT_BEGIN_HEADER * * @input: * glyph :: - * A handle to the target glyph object. + * A handle to the target glyph object. Can be `NULL`. */ FT_EXPORT( void ) FT_Done_Glyph( FT_Glyph glyph ); diff --git a/src/thirdparty/freetype2/include/freetype/ftgxval.h b/src/thirdparty/freetype2/include/freetype/ftgxval.h index b14f637c5..843e0bc91 100644 --- a/src/thirdparty/freetype2/include/freetype/ftgxval.h +++ b/src/thirdparty/freetype2/include/freetype/ftgxval.h @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Masatake YAMATO, Redhat K.K, * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -28,8 +28,7 @@ #ifndef FTGXVAL_H_ #define FTGXVAL_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftgzip.h b/src/thirdparty/freetype2/include/freetype/ftgzip.h index 418c61228..e26c334c1 100644 --- a/src/thirdparty/freetype2/include/freetype/ftgzip.h +++ b/src/thirdparty/freetype2/include/freetype/ftgzip.h @@ -4,7 +4,7 @@ * * Gzip-compressed stream support. * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTGZIP_H_ #define FTGZIP_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -43,6 +42,16 @@ FT_BEGIN_HEADER * Using gzip-compressed font files. * * @description: + * 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. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * * This section contains the declaration of Gzip-specific functions. * */ @@ -75,15 +84,6 @@ FT_BEGIN_HEADER * **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. */ diff --git a/src/thirdparty/freetype2/include/freetype/ftimage.h b/src/thirdparty/freetype2/include/freetype/ftimage.h index face34fe4..b0a0172ef 100644 --- a/src/thirdparty/freetype2/include/freetype/ftimage.h +++ b/src/thirdparty/freetype2/include/freetype/ftimage.h @@ -5,7 +5,7 @@ * FreeType glyph image formats and default raster interface * (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,12 @@ /************************************************************************** * * Note: A 'raster' is simply a scan-line converter, used to render - * FT_Outlines into FT_Bitmaps. + * `FT_Outline`s into `FT_Bitmap`s. + * + * Note: This file can be used for `STANDALONE_` compilation of raster + * (B/W) and smooth (anti-aliased) renderers. Therefore, it must + * rely on standard variable types only instead of aliases in + * `fttypes.h`. * */ @@ -28,12 +33,6 @@ #define FTIMAGE_H_ - /* STANDALONE_ is from ftgrays.c */ -#ifndef STANDALONE_ -#include -#endif - - FT_BEGIN_HEADER @@ -202,6 +201,11 @@ FT_BEGIN_HEADER #define ft_pixel_mode_pal2 FT_PIXEL_MODE_GRAY2 #define ft_pixel_mode_pal4 FT_PIXEL_MODE_GRAY4 + /* */ + + /* For debugging, the @FT_Pixel_Mode enumeration must stay in sync */ + /* with the `pixel_modes` array in file `ftobjs.c`. */ + /************************************************************************** * @@ -257,6 +261,16 @@ FT_BEGIN_HEADER * palette :: * A typeless pointer to the bitmap palette; this field is intended for * paletted pixel modes. Not used currently. + * + * @note: + * `width` and `rows` refer to the *physical* size of the bitmap, not the + * *logical* one. For example, if @FT_Pixel_Mode is set to + * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the + * physical one. + * + * An empty bitmap with a NULL `buffer` is valid, with `rows` and/or + * `pitch` also set to 0. Such bitmaps might be produced while rendering + * empty or degenerate outlines. */ typedef struct FT_Bitmap_ { @@ -313,7 +327,7 @@ FT_BEGIN_HEADER * * If bit~2 is set, bits 5-7 contain the drop-out mode (as defined in * the OpenType specification; the value is the same as the argument to - * the 'SCANMODE' instruction). + * the 'SCANTYPE' instruction). * * Bits 3 and~4 are reserved for internal purposes. * @@ -336,14 +350,14 @@ FT_BEGIN_HEADER */ typedef struct FT_Outline_ { - short n_contours; /* number of contours in glyph */ - short n_points; /* number of points in the glyph */ + unsigned short n_contours; /* number of contours in glyph */ + unsigned 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 */ + FT_Vector* points; /* the outline's points */ + unsigned char* tags; /* the points flags */ + unsigned short* contours; /* the contour end points */ - int flags; /* outline masks */ + int flags; /* outline masks */ } FT_Outline; @@ -351,8 +365,8 @@ FT_BEGIN_HEADER /* Following limits must be consistent with */ /* FT_Outline.{n_contours,n_points} */ -#define FT_OUTLINE_CONTOURS_MAX SHRT_MAX -#define FT_OUTLINE_POINTS_MAX SHRT_MAX +#define FT_OUTLINE_CONTOURS_MAX USHRT_MAX +#define FT_OUTLINE_POINTS_MAX USHRT_MAX /************************************************************************** @@ -401,6 +415,13 @@ FT_BEGIN_HEADER * if @FT_OUTLINE_IGNORE_DROPOUTS is set. See below for more * information. * + * FT_OUTLINE_OVERLAP :: + * [Since 2.10.3] This flag indicates that this outline contains + * overlapping contours and the anti-aliased renderer should perform + * oversampling to mitigate possible artifacts. This flag should _not_ + * be set for well designed glyphs without overlaps because it quadruples + * the rendering time. + * * 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. @@ -422,8 +443,8 @@ FT_BEGIN_HEADER * rasterizer; see the `tags` field in @FT_Outline. * * Please refer to the description of the 'SCANTYPE' instruction in the - * OpenType specification (in file `ttinst1.doc`) how simple drop-outs, - * smart drop-outs, and stubs are defined. + * [OpenType specification](https://learn.microsoft.com/typography/opentype/spec/tt_instructions#scantype) + * how simple drop-outs, smart drop-outs, and stubs are defined. */ #define FT_OUTLINE_NONE 0x0 #define FT_OUTLINE_OWNER 0x1 @@ -432,6 +453,7 @@ FT_BEGIN_HEADER #define FT_OUTLINE_IGNORE_DROPOUTS 0x8 #define FT_OUTLINE_SMART_DROPOUTS 0x10 #define FT_OUTLINE_INCLUDE_STUBS 0x20 +#define FT_OUTLINE_OVERLAP 0x40 #define FT_OUTLINE_HIGH_PRECISION 0x100 #define FT_OUTLINE_SINGLE_PASS 0x200 @@ -688,11 +710,13 @@ FT_BEGIN_HEADER * 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 ) + +#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \ + value = ( ( FT_STATIC_BYTE_CAST( unsigned long, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( unsigned long, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( unsigned long, _x4 ) ) + #endif /* FT_IMAGE_TAG */ @@ -732,6 +756,10 @@ FT_BEGIN_HEADER * 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. + * + * FT_GLYPH_FORMAT_SVG :: + * [Since 2.12] The glyph is represented by an SVG document in the + * 'SVG~' table. */ typedef enum FT_Glyph_Format_ { @@ -740,7 +768,8 @@ FT_BEGIN_HEADER 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_IMAGE_TAG( FT_GLYPH_FORMAT_PLOTTER, 'p', 'l', 'o', 't' ), + FT_IMAGE_TAG( FT_GLYPH_FORMAT_SVG, 'S', 'V', 'G', ' ' ) } FT_Glyph_Format; @@ -765,17 +794,6 @@ FT_BEGIN_HEADER /*************************************************************************/ - /************************************************************************** - * - * A raster is a scan converter, in charge of rendering an outline into 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 `ftrender.h` for more details - * on renderers. - * - */ - /************************************************************************** * @@ -789,16 +807,35 @@ FT_BEGIN_HEADER * How vectorial outlines are converted into bitmaps and pixmaps. * * @description: - * This section contains technical definitions. + * A raster or a rasterizer is a scan converter in charge of producing a + * pixel coverage bitmap that can be used as an alpha channel when + * compositing a glyph with a background. FreeType comes with two + * rasterizers: bilevel `raster1` and anti-aliased `smooth` are two + * separate modules. They are usually called from the high-level + * @FT_Load_Glyph or @FT_Render_Glyph functions and produce the entire + * coverage bitmap at once, while staying largely invisible to users. + * + * Instead of working with complete coverage bitmaps, it is also possible + * to intercept consecutive pixel runs on the same scanline with the same + * coverage, called _spans_, and process them individually. Only the + * `smooth` rasterizer permits this when calling @FT_Outline_Render with + * @FT_Raster_Params as described below. + * + * Working with either complete bitmaps or spans it is important to think + * of them as colorless coverage objects suitable as alpha channels to + * blend arbitrary colors with a background. For best results, it is + * recommended to use gamma correction, too. + * + * This section also describes the public API needed to set up alternative + * @FT_Renderer modules. * * @order: - * FT_Raster * FT_Span * FT_SpanFunc - * * FT_Raster_Params * FT_RASTER_FLAG_XXX * + * FT_Raster * FT_Raster_NewFunc * FT_Raster_DoneFunc * FT_Raster_ResetFunc @@ -809,26 +846,14 @@ FT_BEGIN_HEADER */ - /************************************************************************** - * - * @type: - * FT_Raster - * - * @description: - * An opaque 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 pixels when rendering - * an anti-aliased bitmap. + * A structure to model a single span of consecutive pixels when + * rendering an anti-aliased bitmap. * * @fields: * x :: @@ -845,8 +870,8 @@ FT_BEGIN_HEADER * This structure is used by the span drawing callback type named * @FT_SpanFunc that takes the y~coordinate of the span as a parameter. * - * The coverage value is always between 0 and 255. If you want less gray - * values, the callback function has to reduce them. + * The anti-aliased rasterizer produces coverage values from 0 to 255, + * that is, from completely transparent to completely opaque. */ typedef struct FT_Span_ { @@ -864,8 +889,8 @@ FT_BEGIN_HEADER * * @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. + * to let client applications draw themselves the pixel spans on each + * scan line. * * @input: * y :: @@ -881,11 +906,12 @@ FT_BEGIN_HEADER * 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 callback allows client applications to directly render the 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. + * background bitmap using alpha compositing. It can also be used for + * oversampling and averaging. */ typedef void (*FT_SpanFunc)( int y, @@ -955,11 +981,17 @@ FT_BEGIN_HEADER * will be clipped to a box specified in the `clip_box` field of the * @FT_Raster_Params structure. Otherwise, the `clip_box` is * effectively set to the bounding box and all spans are generated. + * + * FT_RASTER_FLAG_SDF :: + * This flag is set to indicate that a signed distance field glyph + * image should be generated. This is only used while rendering with + * the @FT_RENDER_MODE_SDF render mode. */ #define FT_RASTER_FLAG_DEFAULT 0x0 #define FT_RASTER_FLAG_AA 0x1 #define FT_RASTER_FLAG_DIRECT 0x2 #define FT_RASTER_FLAG_CLIP 0x4 +#define FT_RASTER_FLAG_SDF 0x8 /* these constants are deprecated; use the corresponding */ /* `FT_RASTER_FLAG_XXX` values instead */ @@ -1004,20 +1036,26 @@ FT_BEGIN_HEADER * 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). + * An optional span clipping box expressed in _integer_ pixels + * (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. + * The @FT_RASTER_FLAG_AA bit flag must be set in the `flags` to + * generate an anti-aliased glyph bitmap, otherwise a monochrome bitmap + * is generated. The `target` should have appropriate pixel mode and its + * dimensions define the clipping region. * - * 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. This - * allows direct composition over a pre-existing bitmap through - * user-provided callbacks to perform the span drawing and composition. - * Not supported by the monochrome rasterizer. + * If both @FT_RASTER_FLAG_AA and @FT_RASTER_FLAG_DIRECT bit flags + * are set in `flags`, the raster calls an @FT_SpanFunc callback + * `gray_spans` with `user` data as an argument ignoring `target`. This + * allows direct composition over a pre-existing user surface to perform + * the span drawing and composition. To optionally clip the spans, set + * the @FT_RASTER_FLAG_CLIP flag and `clip_box`. The monochrome raster + * does not support the direct mode. + * + * The gray-level rasterizer always uses 256 gray levels. If you want + * fewer gray levels, you have to use @FT_RASTER_FLAG_DIRECT and reduce + * the levels in the callback function. */ typedef struct FT_Raster_Params_ { @@ -1034,6 +1072,23 @@ FT_BEGIN_HEADER } FT_Raster_Params; + /************************************************************************** + * + * @type: + * FT_Raster + * + * @description: + * An opaque handle (pointer) to a raster object. Each object can be + * used independently to convert an outline into a bitmap or pixmap. + * + * @note: + * In FreeType 2, all rasters are now encapsulated within specific + * @FT_Renderer modules and only used in their context. + * + */ + typedef struct FT_RasterRec_* FT_Raster; + + /************************************************************************** * * @functype: diff --git a/src/thirdparty/freetype2/include/freetype/ftincrem.h b/src/thirdparty/freetype2/include/freetype/ftincrem.h index a4db02b58..223304475 100644 --- a/src/thirdparty/freetype2/include/freetype/ftincrem.h +++ b/src/thirdparty/freetype2/include/freetype/ftincrem.h @@ -4,7 +4,7 @@ * * FreeType incremental loading (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,8 @@ #ifndef FTINCREM_H_ #define FTINCREM_H_ -#include -#include FT_FREETYPE_H -#include FT_PARAMETER_TAGS_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -214,9 +213,14 @@ FT_BEGIN_HEADER * * @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. + * before accessing its data. This allows for handling font types such + * as PCL~XL Format~1, Class~2 downloaded TrueType fonts, where the glyph + * metrics (`hmtx` and `vmtx` tables) are permitted to be omitted from + * the font, and the relevant metrics included in the header of the glyph + * outline data. Importantly, this is not intended to allow custom glyph + * metrics (for example, Postscript Metrics dictionaries), because that + * conflicts with the requirements of outline hinting. Such custom + * metrics must be handled separately, by the calling application. * * @input: * incremental :: @@ -236,7 +240,7 @@ FT_BEGIN_HEADER * * @output: * ametrics :: - * The replacement glyph metrics in font units. + * The glyph metrics in font units. * */ typedef FT_Error @@ -265,7 +269,7 @@ FT_BEGIN_HEADER * * get_glyph_metrics :: * The function to get glyph metrics. May be null if the font does not - * provide overriding glyph metrics. + * require it. * */ typedef struct FT_Incremental_FuncsRec_ diff --git a/src/thirdparty/freetype2/include/freetype/ftlcdfil.h b/src/thirdparty/freetype2/include/freetype/ftlcdfil.h index 3a19d043b..a0a8e9da9 100644 --- a/src/thirdparty/freetype2/include/freetype/ftlcdfil.h +++ b/src/thirdparty/freetype2/include/freetype/ftlcdfil.h @@ -5,7 +5,7 @@ * FreeType API for color filtering of subpixel bitmap glyphs * (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #ifndef FTLCDFIL_H_ #define FTLCDFIL_H_ -#include -#include FT_FREETYPE_H -#include FT_PARAMETER_TAGS_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -45,9 +44,9 @@ FT_BEGIN_HEADER * API to control subpixel rendering. * * @description: - * FreeType provides two alternative subpixel rendering technologies. + * FreeType provides two alternative subpixel rendering technologies. * Should you define `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` in your - * `ftoption.h` file, this enables patented ClearType-style rendering. + * `ftoption.h` file, this enables ClearType-style rendering. * Otherwise, Harmony LCD rendering is enabled. These technologies are * controlled differently and API described below, although always * available, performs its function when appropriate method is enabled @@ -56,13 +55,12 @@ FT_BEGIN_HEADER * ClearType-style LCD rendering exploits the color-striped structure of * LCD pixels, increasing the available resolution in the direction of * the stripe (usually horizontal RGB) by a factor of~3. Using the - * subpixels coverages unfiltered can create severe color fringes + * subpixel coverages unfiltered can create severe color fringes * especially when rendering thin features. Indeed, to produce * black-on-white text, the nearby color subpixels must be dimmed - * equally. - * - * A good 5-tap FIR filter should be applied to subpixel coverages - * regardless of pixel boundaries and should have these properties: + * evenly. Therefore, an equalizing 5-tap FIR filter should be applied + * to subpixel coverages regardless of pixel boundaries and should have + * these properties: * * 1. It should be symmetrical, like {~a, b, c, b, a~}, to avoid * any shifts in appearance. @@ -85,7 +83,7 @@ FT_BEGIN_HEADER * Harmony LCD rendering is suitable to panels with any regular subpixel * structure, not just monitors with 3 color striped subpixels, as long * as the color subpixels have fixed positions relative to the pixel - * center. In this case, each color channel is then rendered separately + * center. In this case, each color channel can be rendered separately * after shifting the outline opposite to the subpixel shift so that the * coverage maps are aligned. This method is immune to color fringes * because the shifts do not change integral coverage. @@ -102,9 +100,9 @@ FT_BEGIN_HEADER * clockwise. Harmony with default LCD geometry is equivalent to * ClearType with light filter. * - * As a result of ClearType filtering or Harmony rendering, the - * dimensions of LCD bitmaps can be either wider or taller than the - * dimensions of the corresponding outline with regard to the pixel grid. + * As a result of ClearType filtering or Harmony shifts, the resulting + * dimensions of LCD bitmaps can be slightly wider or taller than the + * dimensions the original outline with regard to the pixel grid. * For example, for @FT_RENDER_MODE_LCD, the filter adds 2~subpixels to * the left, and 2~subpixels to the right. The bitmap offset values are * adjusted accordingly, so clients shouldn't need to modify their layout @@ -139,11 +137,11 @@ FT_BEGIN_HEADER * * FT_LCD_FILTER_DEFAULT :: * This is a beveled, normalized, and color-balanced five-tap filter - * with weights of [0x08 0x4D 0x56 0x4D 0x08] in 1/256th units. + * with weights of [0x08 0x4D 0x56 0x4D 0x08] in 1/256 units. * * FT_LCD_FILTER_LIGHT :: * this is a boxy, normalized, and color-balanced three-tap filter with - * weights of [0x00 0x55 0x56 0x55 0x00] in 1/256th units. + * weights of [0x00 0x55 0x56 0x55 0x00] in 1/256 units. * * FT_LCD_FILTER_LEGACY :: * FT_LCD_FILTER_LEGACY1 :: @@ -177,7 +175,7 @@ FT_BEGIN_HEADER * FT_Library_SetLcdFilter * * @description: - * This function is used to apply color filtering to LCD decimated + * This function is used to change filter applied to LCD decimated * bitmaps, like the ones used when calling @FT_Render_Glyph with * @FT_RENDER_MODE_LCD or @FT_RENDER_MODE_LCD_V. * @@ -196,15 +194,14 @@ FT_BEGIN_HEADER * 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. + * Since 2.10.3 the LCD filtering is enabled with @FT_LCD_FILTER_DEFAULT. + * It is no longer necessary to call this function explicitly except + * to choose a different filter or disable filtering altogether with + * @FT_LCD_FILTER_NONE. * - * 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. + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. * * @since: * 2.3.0 @@ -229,17 +226,15 @@ FT_BEGIN_HEADER * * weights :: * A pointer to an array; the function copies the first five bytes and - * uses them to specify the filter weights in 1/256th units. + * uses them to specify the filter weights in 1/256 units. * * @return: * FreeType error code. 0~means success. * * @note: - * 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. + * This function does nothing but returns `FT_Err_Unimplemented_Feature` + * if the configuration macro `FT_CONFIG_OPTION_SUBPIXEL_RENDERING` is + * not defined in your build of the library. * * LCD filter weights can also be set per face using @FT_Face_Properties * with @FT_PARAM_TAG_LCD_FILTER_WEIGHTS. diff --git a/src/thirdparty/freetype2/include/freetype/ftlist.h b/src/thirdparty/freetype2/include/freetype/ftlist.h index 4782892d1..14958b0ff 100644 --- a/src/thirdparty/freetype2/include/freetype/ftlist.h +++ b/src/thirdparty/freetype2/include/freetype/ftlist.h @@ -4,7 +4,7 @@ * * Generic list support for FreeType (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -28,8 +28,7 @@ #define FTLIST_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftlogging.h b/src/thirdparty/freetype2/include/freetype/ftlogging.h new file mode 100644 index 000000000..d15517113 --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/ftlogging.h @@ -0,0 +1,184 @@ +/**************************************************************************** + * + * ftlogging.h + * + * Additional debugging APIs. + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTLOGGING_H_ +#define FTLOGGING_H_ + + +#include +#include FT_CONFIG_CONFIG_H + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @section: + * debugging_apis + * + * @title: + * External Debugging APIs + * + * @abstract: + * Public APIs to control the `FT_DEBUG_LOGGING` macro. + * + * @description: + * This section contains the declarations of public functions that + * enables fine control of what the `FT_DEBUG_LOGGING` macro outputs. + * + */ + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Level + * + * @description: + * Change the levels of tracing components of FreeType at run time. + * + * @input: + * tracing_level :: + * New tracing value. + * + * @example: + * The following call makes FreeType trace everything but the 'memory' + * component. + * + * ``` + * FT_Trace_Set_Level( "any:7 memory:0" ); + * ``` + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Level( const char* tracing_level ); + + + /************************************************************************** + * + * @function: + * FT_Trace_Set_Default_Level + * + * @description: + * Reset tracing value of FreeType's components to the default value + * (i.e., to the value of the `FT2_DEBUG` environment value or to NULL + * if `FT2_DEBUG` is not set). + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Trace_Set_Default_Level( void ); + + + /************************************************************************** + * + * @functype: + * FT_Custom_Log_Handler + * + * @description: + * A function typedef that is used to handle the logging of tracing and + * debug messages on a file system. + * + * @input: + * ft_component :: + * The name of `FT_COMPONENT` from which the current debug or error + * message is produced. + * + * fmt :: + * Actual debug or tracing message. + * + * args:: + * Arguments of debug or tracing messages. + * + * @since: + * 2.11 + * + */ + typedef void + (*FT_Custom_Log_Handler)( const char* ft_component, + const char* fmt, + va_list args ); + + + /************************************************************************** + * + * @function: + * FT_Set_Log_Handler + * + * @description: + * A function to set a custom log handler. + * + * @input: + * handler :: + * New logging function. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ); + + + /************************************************************************** + * + * @function: + * FT_Set_Default_Log_Handler + * + * @description: + * A function to undo the effect of @FT_Set_Log_Handler, resetting the + * log handler to FreeType's built-in version. + * + * @note: + * This function does nothing if compilation option `FT_DEBUG_LOGGING` + * isn't set. + * + * @since: + * 2.11 + * + */ + FT_EXPORT( void ) + FT_Set_Default_Log_Handler( void ); + + /* */ + + +FT_END_HEADER + +#endif /* FTLOGGING_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/include/freetype/ftlzw.h b/src/thirdparty/freetype2/include/freetype/ftlzw.h index fd22968f5..de14bcc67 100644 --- a/src/thirdparty/freetype2/include/freetype/ftlzw.h +++ b/src/thirdparty/freetype2/include/freetype/ftlzw.h @@ -4,7 +4,7 @@ * * LZW-compressed stream support. * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTLZW_H_ #define FTLZW_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -43,6 +42,16 @@ FT_BEGIN_HEADER * Using LZW-compressed font files. * * @description: + * 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. + * + * The stream implementation is very basic and resets the decompression + * process each time seeking backwards is needed within the stream, + * which significantly undermines the performance. + * * This section contains the declaration of LZW-specific functions. * */ @@ -73,15 +82,6 @@ FT_BEGIN_HEADER * **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. */ diff --git a/src/thirdparty/freetype2/include/freetype/ftmac.h b/src/thirdparty/freetype2/include/freetype/ftmac.h index 92b9f3dc0..c5ac49101 100644 --- a/src/thirdparty/freetype2/include/freetype/ftmac.h +++ b/src/thirdparty/freetype2/include/freetype/ftmac.h @@ -4,7 +4,7 @@ * * Additional Mac-specific API. * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,7 +29,6 @@ #define FTMAC_H_ -#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/ftmm.h b/src/thirdparty/freetype2/include/freetype/ftmm.h index f2e16b640..ff0bbab59 100644 --- a/src/thirdparty/freetype2/include/freetype/ftmm.h +++ b/src/thirdparty/freetype2/include/freetype/ftmm.h @@ -2,9 +2,9 @@ * * ftmm.h * - * FreeType Multiple Master font interface (specification). + * FreeType variation font interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,13 @@ #ifndef FTMM_H_ #define FTMM_H_ +#include -#include -#include FT_TYPE1_TABLES_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 @@ -33,22 +37,104 @@ FT_BEGIN_HEADER * multiple_masters * * @title: - * Multiple Masters + * OpenType Font Variations, TrueType GX, and Adobe MM Fonts * * @abstract: - * How to manage Multiple Masters fonts. + * How to manage variable fonts with multiple design axes. * * @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. + * The following types and functions manage OpenType Font Variations, + * Adobe Multiple Master (MM) fonts, and Apple TrueType GX fonts. These + * formats have in common that they allow the selection of specific + * design instances by setting design coordinates for one or more axes + * like font weight or width. * - * Besides Adobe MM fonts, the interface supports Apple's TrueType GX and - * OpenType variation fonts. Some of the routines only work with Adobe - * MM fonts, others will work with all three types. They are similar - * enough that a consistent interface makes sense. + * For historical reasons there are two interfaces. The first, older one + * can be used with Adobe MM fonts only, and the second, newer one is a + * unified interface that handles all three font formats. However, some + * differences remain and are documented accordingly; in particular, + * Adobe MM fonts don't have named instances (see below). + * + * For Adobe MM fonts, macro @FT_IS_SFNT returns false. For TrueType GX + * and OpenType Font Variations, it returns true. + * + * We use mostly the terminology of the OpenType standard. Here are some + * important technical terms. + * + * * A 'named instance' is a tuple of design coordinates that has a + * string ID (i.e., an index into the font's 'name' table) associated + * with it. The font can tell the user that, for example, + * [Weight=700,Width=110] is 'Bold'. Another name for 'named instance' + * is 'named style'. + * + * Adobe MM fonts don't have named instances. + * + * * The 'default instance' of a variation font is that instance for + * which the nth axis coordinate is equal to the nth default axis + * coordinate (i.e., `axis[n].def` as specified in the @FT_MM_Var + * structure), with~n covering all axes. In TrueType GX and OpenType + * Font Variations, the default instance is explicitly given. In Adobe + * MM fonts, the `WeightVector` entry as found in the font file is + * taken as the default instance. + * + * For TrueType GX and OpenType Font Variations, FreeType synthesizes + * a named instance for the default instance if the font does not + * contain such an entry. + * + * * 'Design coordinates' are the axis values found in a variation font + * file. Their meaning is specified by the font designer and the + * values are rather arbitrary. + * + * For example, the 'weight' axis in design coordinates might vary + * between 100 (thin) and 900 (heavy) in font~A, while font~B + * contains values between 400 (normal) and 800 (extra bold). + * + * * 'Normalized coordinates' are design coordinates mapped to a standard + * range; they are also called 'blend coordinates'. + * + * For TrueType GX and OpenType Font Variations, the range is [-1;1], + * with the minimum mapped to value~-1, the default mapped to + * value~0, and the maximum mapped to value~1, and all other + * coordinates mapped to intervening points. Please look up the + * [OpenType + * specification](https://learn.microsoft.com/en-us/typography/opentype/spec/otvaroverview) + * on how this mapping works in detail. + * + * For Adobe MM fonts, this standard range is [0;1], with the minimum + * mapped to value~0 and the maximum mapped to value~1, and all other + * coordinates mapped to intervening points. Please look up [Adobe + * TechNote + * #5015](https://adobe-type-tools.github.io/font-tech-notes/pdfs/5015.Type1_Supp.pdf) + * on how this mapping works in detail. + * + * Assuming that the two fonts in the previous example are OpenType + * Font Variations, both font~A's [100;900] and font~B's [400;800] + * coordinate ranges get mapped to [-1;1]. + */ + + + /************************************************************************** + * + * @enum: + * T1_MAX_MM_XXX + * + * @description: + * Adobe MM font limits as defined in their specifications. + * + * @values: + * T1_MAX_MM_AXIS :: + * The maximum number of Adobe MM font axes. + * + * T1_MAX_MM_DESIGNS :: + * The maximum number of Adobe MM font designs. + * + * T1_MAX_MM_MAP_POINTS :: + * The maximum number of elements in a design map. * */ +#define T1_MAX_MM_AXIS 4 +#define T1_MAX_MM_DESIGNS 16 +#define T1_MAX_MM_MAP_POINTS 20 /************************************************************************** @@ -57,11 +143,10 @@ FT_BEGIN_HEADER * FT_MM_Axis * * @description: - * A structure to model a given axis in design space for Multiple Masters - * fonts. + * A structure to model a given axis in design space for Adobe MM fonts. * - * This structure can't be used for TrueType GX or OpenType variation - * fonts. + * This structure can't be used with TrueType GX or OpenType Font + * Variations. * * @fields: * name :: @@ -88,17 +173,17 @@ FT_BEGIN_HEADER * FT_Multi_Master * * @description: - * A structure to model the axes and space of a Multiple Masters font. + * A structure to model the axes and space of an Adobe MM font. * - * This structure can't be used for TrueType GX or OpenType variation - * fonts. + * This structure can't be used with TrueType GX or OpenType Font + * Variations. * * @fields: * num_axis :: * Number of axes. Cannot exceed~4. * * num_designs :: - * Number of designs; should be normally 2^num_axis even though the + * 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. * @@ -120,13 +205,13 @@ FT_BEGIN_HEADER * FT_Var_Axis * * @description: - * A structure to model a given axis in design space for Multiple - * Masters, TrueType GX, and OpenType variation fonts. + * A structure to model a given axis in design space for Adobe MM fonts, + * TrueType GX, and OpenType Font Variations. * * @fields: * name :: * The axis's name. Not always meaningful for TrueType GX or OpenType - * variation fonts. + * Font Variations. * * minimum :: * The axis's minimum design coordinate. @@ -140,18 +225,18 @@ FT_BEGIN_HEADER * * tag :: * The axis's tag (the equivalent to 'name' for TrueType GX and - * OpenType variation fonts). FreeType provides default values for + * OpenType Font Variations). FreeType provides default values for * Adobe MM fonts if possible. * * strid :: * The axis name entry in the font's 'name' table. This is another * (and often better) version of the 'name' field for TrueType GX or - * OpenType variation fonts. Not meaningful for Adobe MM fonts. + * OpenType Font Variations. Not meaningful for Adobe MM fonts. * * @note: * The fields `minimum`, `def`, and `maximum` are 16.16 fractional values - * for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the - * values are integers. + * for TrueType GX and OpenType Font Variations. For Adobe MM fonts, the + * values are whole numbers (i.e., the fractional part is zero). */ typedef struct FT_Var_Axis_ { @@ -174,7 +259,7 @@ FT_BEGIN_HEADER * * @description: * A structure to model a named instance in a TrueType GX or OpenType - * variation font. + * Font Variations. * * This structure can't be used for Adobe MM fonts. * @@ -184,11 +269,11 @@ FT_BEGIN_HEADER * entry for each axis. * * strid :: - * The entry in 'name' table identifying this instance. + * An index into the 'name' table identifying this instance. * * psid :: - * The entry in 'name' table identifying a PostScript name for this - * instance. Value 0xFFFF indicates a missing entry. + * An index into the 'name' table identifying a PostScript name for + * this instance. Value 0xFFFF indicates a missing entry. */ typedef struct FT_Var_Named_Style_ { @@ -205,39 +290,33 @@ FT_BEGIN_HEADER * FT_MM_Var * * @description: - * A structure to model the axes and space of an Adobe MM, TrueType GX, - * or OpenType variation font. + * A structure to model the axes and space of Adobe MM fonts, TrueType + * GX, or OpenType Font Variations. * * Some fields are specific to one format and not to the others. * * @fields: * num_axis :: * The number of axes. The maximum value is~4 for Adobe MM fonts; no - * limit in TrueType GX or OpenType variation fonts. + * limit in TrueType GX or OpenType Font Variations. * * num_designs :: - * The number of designs; should be normally 2^num_axis for Adobe MM - * fonts. Not meaningful for TrueType GX or OpenType variation fonts + * The number of designs; should be normally `2^num_axis` for Adobe MM + * fonts. Not meaningful for TrueType GX or OpenType Font Variations * (where every glyph could have a different number of designs). * * num_namedstyles :: - * The number of named styles; a 'named style' is a tuple of design - * coordinates that has a string ID (in the 'name' table) associated - * with it. The font can tell the user that, for example, - * [Weight=1.5,Width=1.1] is 'Bold'. Another name for 'named style' is - * 'named instance'. - * - * For Adobe Multiple Masters fonts, this value is always zero because - * the format does not support named styles. + * The number of named instances. For Adobe MM fonts, this value is + * always zero. * * axis :: - * An axis descriptor table. TrueType GX and OpenType variation fonts + * An axis descriptor table. TrueType GX and OpenType Font Variations * contain slightly more data than Adobe MM fonts. Memory management * of this pointer is done internally by FreeType. * * namedstyle :: - * A named style (instance) table. Only meaningful for TrueType GX and - * OpenType variation fonts. Memory management of this pointer is done + * An array of named instances. Only meaningful for TrueType GX and + * OpenType Font Variations. Memory management of this pointer is done * internally by FreeType. */ typedef struct FT_MM_Var_ @@ -259,8 +338,8 @@ FT_BEGIN_HEADER * @description: * Retrieve a variation descriptor of a given Adobe MM font. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @input: * face :: @@ -268,7 +347,7 @@ FT_BEGIN_HEADER * * @output: * amaster :: - * The Multiple Masters descriptor. + * The Adobe MM font's variation descriptor. * * @return: * FreeType error code. 0~means success. @@ -335,8 +414,8 @@ FT_BEGIN_HEADER * For Adobe MM fonts, choose an interpolated font design through design * coordinates. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -360,8 +439,8 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. */ FT_EXPORT( FT_Error ) FT_Set_MM_Design_Coordinates( FT_Face face, @@ -396,6 +475,10 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType Font Variations. For Adobe MM fonts, the values are supposed + * to be whole numbers (i.e., the fractional part is zero). + * * [Since 2.8.1] To reset all axes to the default values, call the * function with `num_coords` set to zero and `coords` set to `NULL`. * [Since 2.9] 'Default values' means the currently selected named @@ -403,8 +486,14 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. + * + * [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit + * in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns + * true) if any of the provided coordinates is different from the face's + * default value for the corresponding axis, that is, the set up face is + * not at its default position. */ FT_EXPORT( FT_Error ) FT_Set_Var_Design_Coordinates( FT_Face face, @@ -433,11 +522,16 @@ FT_BEGIN_HEADER * * @output: * coords :: - * The design coordinates array. + * The design coordinates array, which must be allocated by the user. * * @return: * FreeType error code. 0~means success. * + * @note: + * The design coordinates are 16.16 fractional values for TrueType GX and + * OpenType Font Variations. For Adobe MM fonts, the values are whole + * numbers (i.e., the fractional part is zero). + * * @since: * 2.7.1 */ @@ -453,8 +547,7 @@ FT_BEGIN_HEADER * FT_Set_MM_Blend_Coordinates * * @description: - * Choose an interpolated font design through normalized blend - * coordinates. + * Choose an interpolated font design through normalized coordinates. * * This function works with all supported variation formats. * @@ -469,9 +562,10 @@ FT_BEGIN_HEADER * the number of axes, use default values for the remaining axes. * * coords :: - * The design coordinates array (each element must be between 0 and 1.0 - * for Adobe MM fonts, and between -1.0 and 1.0 for TrueType GX and - * OpenType variation fonts). + * The normalized coordinates array. Each element is a 16.16 + * fractional value and must be between 0 and 1.0 for Adobe MM fonts, + * and between -1.0 and 1.0 for TrueType GX and OpenType Font + * Variations. * * @return: * FreeType error code. 0~means success. @@ -484,8 +578,14 @@ FT_BEGIN_HEADER * * [Since 2.9] If `num_coords` is larger than zero, this function sets * the @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field - * (i.e., @FT_IS_VARIATION will return true). If `num_coords` is zero, - * this bit flag gets unset. + * (i.e., @FT_IS_VARIATION returns true). If `num_coords` is zero, this + * bit flag gets unset. + * + * [Since 2.14] This function also sets the @FT_FACE_FLAG_VARIATION bit + * in @FT_Face's `face_flags` field (i.e., @FT_IS_VARIATION returns + * true) if any of the provided coordinates is different from the face's + * default value for the corresponding axis, that is, the set up face is + * not at its default position. */ FT_EXPORT( FT_Error ) FT_Set_MM_Blend_Coordinates( FT_Face face, @@ -499,8 +599,8 @@ FT_BEGIN_HEADER * FT_Get_MM_Blend_Coordinates * * @description: - * Get the normalized blend coordinates of the currently selected - * interpolated font. + * Get the normalized coordinates of the currently selected interpolated + * font. * * This function works with all supported variation formats. * @@ -509,14 +609,14 @@ FT_BEGIN_HEADER * A handle to the source face. * * num_coords :: - * The number of normalized blend coordinates to retrieve. If it is - * larger than the number of axes, set the excess values to~0.5 for - * Adobe MM fonts, and to~0 for TrueType GX and OpenType variation - * fonts. + * The number of normalized coordinates to retrieve. If it is larger + * than the number of axes, set the excess values to~0.5 for Adobe MM + * fonts, and to~0 for TrueType GX and OpenType Font Variations. * * @output: * coords :: - * The normalized blend coordinates array. + * The normalized coordinates array (as 16.16 fractional values), which + * must be allocated by the user. * * @return: * FreeType error code. 0~means success. @@ -570,8 +670,8 @@ FT_BEGIN_HEADER * For Adobe MM fonts, choose an interpolated font design by directly * setting the weight vector. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -590,14 +690,16 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * Adobe Multiple Master fonts limit the number of designs, and thus the - * length of the weight vector to~16. + * Adobe MM fonts limit the number of designs, and thus the length of the + * weight vector, to 16~elements. * - * If `len` is zero and `weightvector` is `NULL`, the weight vector array - * is reset to the default values. + * If `len` is larger than zero, this function sets the + * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e., + * @FT_IS_VARIATION returns true). If `len` is zero, this bit flag is + * unset and the weight vector array is reset to the default values. * * The Adobe documentation also states that the values in the - * WeightVector array must total 1.0 +/-~0.001. In practice this does + * `WeightVector` array must total 1.0 +/-~0.001. In practice this does * not seem to be enforced, so is not enforced here, either. * * @since: @@ -617,8 +719,8 @@ FT_BEGIN_HEADER * @description: * For Adobe MM fonts, retrieve the current weight vector of the font. * - * This function can't be used with TrueType GX or OpenType variation - * fonts. + * This function can't be used with TrueType GX or OpenType Font + * Variations. * * @inout: * face :: @@ -635,14 +737,14 @@ FT_BEGIN_HEADER * * @output: * weightvector :: - * An array to be filled. + * An array to be filled; it must be allocated by the user. * * @return: * FreeType error code. 0~means success. * * @note: - * Adobe Multiple Master fonts limit the number of designs, and thus the - * length of the WeightVector to~16. + * Adobe MM fonts limit the number of designs, and thus the length of the + * weight vector, to~16 elements. * * @since: * 2.10 @@ -718,8 +820,8 @@ FT_BEGIN_HEADER * A handle to the source face. * * instance_index :: - * The index of the requested instance, starting with value 1. If set - * to value 0, FreeType switches to font access without a named + * The index of the requested instance, starting with value~1. If set + * to value~0, FreeType switches to font access without a named * instance. * * @return: @@ -729,11 +831,11 @@ FT_BEGIN_HEADER * The function uses the value of `instance_index` to set bits 16-30 of * the face's `face_index` field. It also resets any variation applied * to the font, and the @FT_FACE_FLAG_VARIATION bit of the face's - * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION will - * return false). + * `face_flags` field gets reset to zero (i.e., @FT_IS_VARIATION returns + * false). * - * For Adobe MM fonts (which don't have named instances) this function - * simply resets the current face to the default instance. + * For Adobe MM fonts, this function resets the current face to the + * default instance. * * @since: * 2.9 @@ -742,6 +844,41 @@ FT_BEGIN_HEADER FT_Set_Named_Instance( FT_Face face, FT_UInt instance_index ); + + /************************************************************************** + * + * @function: + * FT_Get_Default_Named_Instance + * + * @description: + * Retrieve the index of the default named instance, to be used with + * @FT_Set_Named_Instance. + * + * FreeType synthesizes a named instance for the default instance if the + * font does not contain such an entry. + * + * @input: + * face :: + * A handle to the source face. + * + * @output: + * instance_index :: + * The index of the default named instance. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * For Adobe MM fonts, this function always returns zero for + * `instance_index`. + * + * @since: + * 2.13.1 + */ + FT_EXPORT( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + /* */ diff --git a/src/thirdparty/freetype2/include/freetype/ftmodapi.h b/src/thirdparty/freetype2/include/freetype/ftmodapi.h index 8d039c4f3..2669e4a03 100644 --- a/src/thirdparty/freetype2/include/freetype/ftmodapi.h +++ b/src/thirdparty/freetype2/include/freetype/ftmodapi.h @@ -4,7 +4,7 @@ * * FreeType modules public interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTMODAPI_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -46,10 +45,12 @@ FT_BEGIN_HEADER * * @description: * The definitions below are used to manage modules within FreeType. - * Modules can be added, upgraded, and removed at runtime. Additionally, - * some module properties can be controlled also. + * Internal and external modules can be added, upgraded, and removed at + * runtime. For example, an alternative renderer or proprietary font + * driver can be registered and prioritized. Additionally, some module + * properties can also be controlled. * - * Here is a list of possible values of the `module_name` field in the + * Here is a list of existing values of the `module_name` field in the * @FT_Module_Class structure. * * ``` @@ -65,7 +66,7 @@ FT_BEGIN_HEADER * psnames * raster1 * sfnt - * smooth, smooth-lcd, smooth-lcdv + * smooth * truetype * type1 * type42 @@ -87,6 +88,7 @@ FT_BEGIN_HEADER * FT_Remove_Module * FT_Add_Default_Modules * + * FT_FACE_DRIVER_NAME * FT_Property_Set * FT_Property_Get * FT_Set_Default_Properties @@ -329,6 +331,27 @@ FT_BEGIN_HEADER FT_Module module ); + /************************************************************************** + * + * @macro: + * FT_FACE_DRIVER_NAME + * + * @description: + * A macro that retrieves the name of a font driver from a face object. + * + * @note: + * The font driver name is a valid `module_name` for @FT_Property_Set + * and @FT_Property_Get. This is not the same as @FT_Get_Font_Format. + * + * @since: + * 2.11 + * + */ +#define FT_FACE_DRIVER_NAME( face ) \ + ( ( *FT_REINTERPRET_CAST( FT_Module_Class**, \ + ( face )->driver ) )->module_name ) + + /************************************************************************** * * @function: @@ -486,8 +509,7 @@ FT_BEGIN_HEADER * * ``` * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ - * cff:no-stem-darkening=1 \ - * autofitter:warping=1 + * cff:no-stem-darkening=0 * ``` * * @inout: diff --git a/src/thirdparty/freetype2/include/freetype/ftmoderr.h b/src/thirdparty/freetype2/include/freetype/ftmoderr.h index e16993572..8e2ef2f01 100644 --- a/src/thirdparty/freetype2/include/freetype/ftmoderr.h +++ b/src/thirdparty/freetype2/include/freetype/ftmoderr.h @@ -4,7 +4,7 @@ * * FreeType module error offsets (specification). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -94,7 +94,7 @@ * const char* mod_err_msg * } ft_mod_errors[] = * - * #include FT_MODULE_ERRORS_H + * #include * ``` * */ @@ -171,6 +171,7 @@ FT_MODERRDEF( Type42, 0x1400, "Type 42 module" ) FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) FT_MODERRDEF( GXvalid, 0x1600, "GX validation module" ) + FT_MODERRDEF( Sdf, 0x1700, "Signed distance field raster module" ) #ifdef FT_MODERR_END_LIST diff --git a/src/thirdparty/freetype2/include/freetype/ftotval.h b/src/thirdparty/freetype2/include/freetype/ftotval.h index c034f4895..f1cd22acc 100644 --- a/src/thirdparty/freetype2/include/freetype/ftotval.h +++ b/src/thirdparty/freetype2/include/freetype/ftotval.h @@ -4,7 +4,7 @@ * * FreeType API for validating OpenType tables (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -30,8 +30,7 @@ #ifndef FTOTVAL_H_ #define FTOTVAL_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftoutln.h b/src/thirdparty/freetype2/include/freetype/ftoutln.h index b72327b70..2545ca848 100644 --- a/src/thirdparty/freetype2/include/freetype/ftoutln.h +++ b/src/thirdparty/freetype2/include/freetype/ftoutln.h @@ -5,7 +5,7 @@ * Support for the FT_Outline type used to store glyph shapes of * most scalable font formats (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,7 @@ #define FTOUTLN_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -110,14 +109,16 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * A contour that contains a single point only is represented by a 'move - * to' operation followed by 'line to' to the same point. In most cases, - * it is best to filter this out before using the outline for stroking - * purposes (otherwise it would result in a visible dot when round caps - * are used). + * Degenerate contours, segments, and Bezier arcs may be reported. In + * most cases, it is best to filter these out before using the outline + * for stroking or other path modification purposes (which may cause + * degenerate segments to become non-degenerate and visible, like when + * stroke caps are used or the path is otherwise outset). Some glyph + * outlines may contain deliberate degenerate single points for mark + * attachement. * * Similarly, the function returns success for an empty outline also - * (doing nothing, this is, not calling any emitter); if necessary, you + * (doing nothing, that is, not calling any emitter); if necessary, you * should filter this out, too. */ FT_EXPORT( FT_Error ) @@ -483,19 +484,13 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * This advanced function uses @FT_Raster_Params as an argument, - * allowing FreeType rasterizer to be used for direct composition, - * translucency, etc. You should know how to set up @FT_Raster_Params - * for this function to work. - * + * This advanced function uses @FT_Raster_Params as an argument. * 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. - * - * The gray-level rasterizer always uses 256 gray levels. If you want - * less gray levels, you have to provide your own span callback. See the - * @FT_RASTER_FLAG_DIRECT value of the `flags` field in the - * @FT_Raster_Params structure for more details. + * actually ignored. Either `params.target` must point to preallocated + * bitmap, or @FT_RASTER_FLAG_DIRECT must be set in `params.flags` + * allowing FreeType rasterizer to be used for direct composition, + * translucency, etc. See @FT_Raster_Params for more details. */ FT_EXPORT( FT_Error ) FT_Outline_Render( FT_Library library, diff --git a/src/thirdparty/freetype2/include/freetype/ftparams.h b/src/thirdparty/freetype2/include/freetype/ftparams.h index c374ee2f2..2c09db168 100644 --- a/src/thirdparty/freetype2/include/freetype/ftparams.h +++ b/src/thirdparty/freetype2/include/freetype/ftparams.h @@ -4,7 +4,7 @@ * * FreeType API for possible FT_Parameter tags (specification only). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTPARAMS_H_ #define FTPARAMS_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -113,6 +112,21 @@ FT_BEGIN_HEADER FT_MAKE_TAG( 'i', 'n', 'c', 'r' ) + /************************************************************************** + * + * @enum: + * FT_PARAM_TAG_IGNORE_SBIX + * + * @description: + * A tag for @FT_Parameter to make @FT_Open_Face ignore an 'sbix' table + * while loading a font. Use this if @FT_FACE_FLAG_SBIX is set and you + * want to access the outline glyphs in the font. + * + */ +#define FT_PARAM_TAG_IGNORE_SBIX \ + FT_MAKE_TAG( 'i', 's', 'b', 'x' ) + + /************************************************************************** * * @enum: diff --git a/src/thirdparty/freetype2/include/freetype/ftpfr.h b/src/thirdparty/freetype2/include/freetype/ftpfr.h index b4eca76eb..399b5ca3c 100644 --- a/src/thirdparty/freetype2/include/freetype/ftpfr.h +++ b/src/thirdparty/freetype2/include/freetype/ftpfr.h @@ -4,7 +4,7 @@ * * FreeType API for accessing PFR-specific data (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTPFR_H_ #define FTPFR_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -162,7 +161,7 @@ FT_BEGIN_HEADER * * @note: * You can use the `x_scale` or `y_scale` results of @FT_Get_PFR_Metrics - * to convert the advance to device subpixels (i.e., 1/64th of pixels). + * to convert the advance to device subpixels (i.e., 1/64 of pixels). */ FT_EXPORT( FT_Error ) FT_Get_PFR_Advance( FT_Face face, diff --git a/src/thirdparty/freetype2/include/freetype/ftrender.h b/src/thirdparty/freetype2/include/freetype/ftrender.h index a01c77427..cc3102073 100644 --- a/src/thirdparty/freetype2/include/freetype/ftrender.h +++ b/src/thirdparty/freetype2/include/freetype/ftrender.h @@ -4,7 +4,7 @@ * * FreeType renderer modules public interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define FTRENDER_H_ -#include -#include FT_MODULE_H -#include FT_GLYPH_H +#include +#include FT_BEGIN_HEADER @@ -159,7 +158,7 @@ FT_BEGIN_HEADER FT_Renderer_GetCBoxFunc get_glyph_cbox; FT_Renderer_SetModeFunc set_mode; - FT_Raster_Funcs* raster_class; + const FT_Raster_Funcs* raster_class; } FT_Renderer_Class; diff --git a/src/thirdparty/freetype2/include/freetype/ftsizes.h b/src/thirdparty/freetype2/include/freetype/ftsizes.h index 6c63cef2b..fdb89f24c 100644 --- a/src/thirdparty/freetype2/include/freetype/ftsizes.h +++ b/src/thirdparty/freetype2/include/freetype/ftsizes.h @@ -4,7 +4,7 @@ * * FreeType size objects management (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,8 +29,7 @@ #define FTSIZES_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftsnames.h b/src/thirdparty/freetype2/include/freetype/ftsnames.h index 4d43602a4..99728574d 100644 --- a/src/thirdparty/freetype2/include/freetype/ftsnames.h +++ b/src/thirdparty/freetype2/include/freetype/ftsnames.h @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,9 +23,8 @@ #define FTSNAMES_H_ -#include -#include FT_FREETYPE_H -#include FT_PARAMETER_TAGS_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/ftstroke.h b/src/thirdparty/freetype2/include/freetype/ftstroke.h index 01a9c1811..2c4761c76 100644 --- a/src/thirdparty/freetype2/include/freetype/ftstroke.h +++ b/src/thirdparty/freetype2/include/freetype/ftstroke.h @@ -4,7 +4,7 @@ * * FreeType path stroker (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,8 @@ #ifndef FTSTROKE_H_ #define FTSTROKE_H_ -#include -#include FT_OUTLINE_H -#include FT_GLYPH_H +#include +#include FT_BEGIN_HEADER @@ -44,7 +43,7 @@ FT_BEGIN_HEADER * 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 + * displayed with a colored (and anti-aliased) border around their * shape. * * @order: @@ -114,22 +113,19 @@ FT_BEGIN_HEADER * FT_STROKER_LINEJOIN_MITER_FIXED :: * Used to render mitered line joins, with fixed bevels if the miter * limit is exceeded. The outer edges of the strokes for the two - * segments are extended until they meet at an angle. If the segments - * meet at too sharp an angle (such that the miter would extend from - * the intersection of the segments a distance greater than the product - * of the miter limit value and the border radius), then a bevel join - * (see above) is used instead. This prevents long spikes being - * created. `FT_STROKER_LINEJOIN_MITER_FIXED` generates a miter line - * join as used in PostScript and PDF. + * segments are extended until they meet at an angle. A bevel join + * (see above) is used if the segments meet at too sharp an angle and + * the outer edges meet beyond a distance corresponding to the meter + * limit. This prevents long spikes being created. + * `FT_STROKER_LINEJOIN_MITER_FIXED` generates a miter line join as + * used in PostScript and PDF. * * FT_STROKER_LINEJOIN_MITER_VARIABLE :: * FT_STROKER_LINEJOIN_MITER :: * Used to render mitered line joins, with variable bevels if the miter - * limit is exceeded. The intersection of the strokes is clipped at a - * line perpendicular to the bisector of the angle between the strokes, - * at the distance from the intersection of the segments equal to the - * product of the miter limit value and the border radius. This - * prevents long spikes being created. + * limit is exceeded. The intersection of the strokes is clipped + * perpendicularly to the bisector, at a distance corresponding to + * the miter limit. This prevents long spikes being created. * `FT_STROKER_LINEJOIN_MITER_VARIABLE` generates a mitered line join * as used in XPS. `FT_STROKER_LINEJOIN_MITER` is an alias for * `FT_STROKER_LINEJOIN_MITER_VARIABLE`, retained for backward @@ -296,12 +292,17 @@ FT_BEGIN_HEADER * The line join style. * * miter_limit :: - * The miter limit for the `FT_STROKER_LINEJOIN_MITER_FIXED` and - * `FT_STROKER_LINEJOIN_MITER_VARIABLE` line join styles, expressed as - * 16.16 fixed-point value. + * The maximum reciprocal sine of half-angle at the miter join, + * expressed as 16.16 fixed-point value. * * @note: - * The radius is expressed in the same units as the outline coordinates. + * The `radius` is expressed in the same units as the outline + * coordinates. + * + * The `miter_limit` multiplied by the `radius` gives the maximum size + * of a miter spike, at which it is clipped for + * @FT_STROKER_LINEJOIN_MITER_VARIABLE or replaced with a bevel join for + * @FT_STROKER_LINEJOIN_MITER_FIXED. * * This function calls @FT_Stroker_Rewind automatically. */ diff --git a/src/thirdparty/freetype2/include/freetype/ftsynth.h b/src/thirdparty/freetype2/include/freetype/ftsynth.h index 8754f97ce..93499a4b4 100644 --- a/src/thirdparty/freetype2/include/freetype/ftsynth.h +++ b/src/thirdparty/freetype2/include/freetype/ftsynth.h @@ -5,7 +5,7 @@ * FreeType synthesizing code for emboldening and slanting * (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -45,8 +45,7 @@ #define FTSYNTH_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -69,10 +68,31 @@ FT_BEGIN_HEADER FT_EXPORT( void ) FT_GlyphSlot_Embolden( FT_GlyphSlot slot ); - /* Slant an outline glyph to the right by about 12 degrees. */ + /* Precisely adjust the glyph weight either horizontally or vertically. */ + /* The `xdelta` and `ydelta` values are fractions of the face Em size */ + /* (in fixed-point format). Considering that a regular face would have */ + /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should */ + /* be very noticeable. To increase or decrease the weight, use positive */ + /* or negative values, respectively. */ + FT_EXPORT( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ); + + + /* Slant an outline glyph to the right by about 12 degrees. */ FT_EXPORT( void ) FT_GlyphSlot_Oblique( FT_GlyphSlot slot ); + /* Slant an outline glyph by a given sine of an angle. You can apply */ + /* slant along either x- or y-axis by choosing a corresponding non-zero */ + /* argument. If both slants are non-zero, some affine transformation */ + /* will result. */ + FT_EXPORT( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ); + /* */ diff --git a/src/thirdparty/freetype2/include/freetype/ftsystem.h b/src/thirdparty/freetype2/include/freetype/ftsystem.h index 889a6ba17..1de9f8e60 100644 --- a/src/thirdparty/freetype2/include/freetype/ftsystem.h +++ b/src/thirdparty/freetype2/include/freetype/ftsystem.h @@ -4,7 +4,7 @@ * * FreeType low-level system interface definition (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define FTSYSTEM_H_ -#include FT_BEGIN_HEADER @@ -230,7 +229,7 @@ FT_BEGIN_HEADER * A handle to the source stream. * * offset :: - * The offset of read in stream (always from start). + * The offset from the start of the stream to seek to. * * buffer :: * The address of the read buffer. @@ -239,11 +238,9 @@ FT_BEGIN_HEADER * 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. A non-zero return value then indicates an error. + * If count >~0, return the number of bytes effectively read by the + * stream (after seeking to `offset`). If count ==~0, return the status + * of the seek operation (non-zero indicates an error). * */ typedef unsigned long diff --git a/src/thirdparty/freetype2/include/freetype/fttrigon.h b/src/thirdparty/freetype2/include/freetype/fttrigon.h index 37e1412fd..ed7bd06a7 100644 --- a/src/thirdparty/freetype2/include/freetype/fttrigon.h +++ b/src/thirdparty/freetype2/include/freetype/fttrigon.h @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (specification). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef FTTRIGON_H_ #define FTTRIGON_H_ -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" diff --git a/src/thirdparty/freetype2/include/freetype/fttypes.h b/src/thirdparty/freetype2/include/freetype/fttypes.h index 10571505a..e207c5ebe 100644 --- a/src/thirdparty/freetype2/include/freetype/fttypes.h +++ b/src/thirdparty/freetype2/include/freetype/fttypes.h @@ -4,7 +4,7 @@ * * FreeType simple types definitions (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,8 +22,8 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_SYSTEM_H -#include FT_IMAGE_H +#include +#include #include @@ -45,7 +45,10 @@ FT_BEGIN_HEADER * @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. + * font-specific structures are defined in a different section. Note + * that FreeType does not use floating-point data types. Fractional + * values are represented by fixed-point integers, with lower bits + * storing the fractional part. * * @order: * FT_Byte @@ -413,7 +416,7 @@ FT_BEGIN_HEADER typedef struct FT_Data_ { const FT_Byte* pointer; - FT_Int length; + FT_UInt length; } FT_Data; @@ -479,18 +482,17 @@ FT_BEGIN_HEADER * * @description: * This macro converts four-letter tags that are used to label TrueType - * tables into an unsigned long, to be used within FreeType. + * tables into an `FT_Tag` type, to be used within FreeType. * * @note: * The produced values **must** be 32-bit integers. Don't redefine this * macro. */ -#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ - (FT_Tag) \ - ( ( (FT_ULong)_x1 << 24 ) | \ - ( (FT_ULong)_x2 << 16 ) | \ - ( (FT_ULong)_x3 << 8 ) | \ - (FT_ULong)_x4 ) +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( FT_STATIC_BYTE_CAST( FT_Tag, _x1 ) << 24 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x2 ) << 16 ) | \ + ( FT_STATIC_BYTE_CAST( FT_Tag, _x3 ) << 8 ) | \ + FT_STATIC_BYTE_CAST( FT_Tag, _x4 ) ) /*************************************************************************/ @@ -588,7 +590,7 @@ FT_BEGIN_HEADER #define FT_IS_EMPTY( list ) ( (list).head == 0 ) -#define FT_BOOL( x ) ( (FT_Bool)( (x) != 0 ) ) +#define FT_BOOL( x ) FT_STATIC_CAST( FT_Bool, (x) != 0 ) /* concatenate C tokens */ #define FT_ERR_XCAT( x, y ) x ## y diff --git a/src/thirdparty/freetype2/include/freetype/ftwinfnt.h b/src/thirdparty/freetype2/include/freetype/ftwinfnt.h index a2fba903d..78609d578 100644 --- a/src/thirdparty/freetype2/include/freetype/ftwinfnt.h +++ b/src/thirdparty/freetype2/include/freetype/ftwinfnt.h @@ -4,7 +4,7 @@ * * FreeType API for accessing Windows fnt-specific data. * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef FTWINFNT_H_ #define FTWINFNT_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -56,7 +55,7 @@ FT_BEGIN_HEADER * FT_WinFNT_ID_XXX * * @description: - * A list of valid values for the `charset` byte in @FT_WinFNT_HeaderRec. + * 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/Public/' in the * `MAPPINGS/VENDORS/MICSFT/WINDOWS` subdirectory. 'cp1361' is roughly a @@ -94,8 +93,7 @@ FT_BEGIN_HEADER * second default codepage that most international versions of Windows * have. It is one of the OEM codepages from * - * https://docs.microsoft.com/en-us/windows/desktop/intl/code-page-identifiers - * , + * https://learn.microsoft.com/windows/win32/intl/code-page-identifiers , * * and is used for the 'DOS boxes', to support legacy applications. A * German Windows version for example usually uses ANSI codepage 1252 diff --git a/src/thirdparty/freetype2/include/freetype/internal/autohint.h b/src/thirdparty/freetype2/include/freetype/internal/autohint.h index f64c28bb2..987e704e9 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/autohint.h +++ b/src/thirdparty/freetype2/include/freetype/internal/autohint.h @@ -4,7 +4,7 @@ * * High-level 'autohint' module-specific interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -70,8 +70,7 @@ */ -#include -#include FT_FREETYPE_H +#include FT_BEGIN_HEADER @@ -208,6 +207,9 @@ FT_BEGIN_HEADER } FT_AutoHinter_InterfaceRec, *FT_AutoHinter_Interface; +#define FT_DECLARE_AUTOHINTER_INTERFACE( class_ ) \ + FT_CALLBACK_TABLE const FT_AutoHinter_InterfaceRec class_; + #define FT_DEFINE_AUTOHINTER_INTERFACE( \ class_, \ reset_face_, \ diff --git a/src/thirdparty/freetype2/include/freetype/internal/cffotypes.h b/src/thirdparty/freetype2/include/freetype/internal/cffotypes.h index b26893eab..26ee43bb9 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/cffotypes.h +++ b/src/thirdparty/freetype2/include/freetype/internal/cffotypes.h @@ -4,7 +4,7 @@ * * Basic OpenType/CFF object type definitions (specification). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,12 +19,11 @@ #ifndef CFFOTYPES_H_ #define CFFOTYPES_H_ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_CFF_TYPES_H -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include +#include +#include +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/cfftypes.h b/src/thirdparty/freetype2/include/freetype/internal/cfftypes.h index 2fc905ec7..62335db48 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/cfftypes.h +++ b/src/thirdparty/freetype2/include/freetype/internal/cfftypes.h @@ -5,7 +5,7 @@ * Basic OpenType/CFF type definitions and interface (specification * only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,13 +21,12 @@ #define CFFTYPES_H_ -#include -#include FT_FREETYPE_H -#include FT_TYPE1_TABLES_H -#include FT_INTERNAL_SERVICE_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include +#include +#include +#include +#include +#include FT_BEGIN_HEADER @@ -249,10 +248,10 @@ FT_BEGIN_HEADER 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_values[14]; + FT_Fixed other_blues[10]; + FT_Fixed family_blues[14]; + FT_Fixed family_other_blues[10]; FT_Fixed blue_scale; FT_Pos blue_shift; @@ -316,7 +315,7 @@ FT_BEGIN_HEADER /* The normal stack then points to these values instead of the DICT */ /* because all other operators in Private DICT clear the stack. */ /* `blend_stack' could be cleared at each operator other than blend. */ - /* Blended values are stored as 5-byte fixed point values. */ + /* Blended values are stored as 5-byte fixed-point values. */ FT_Byte* blend_stack; /* base of stack allocation */ FT_Byte* blend_top; /* first empty slot */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/compiler-macros.h b/src/thirdparty/freetype2/include/freetype/internal/compiler-macros.h new file mode 100644 index 000000000..e6d0166d8 --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/internal/compiler-macros.h @@ -0,0 +1,343 @@ +/**************************************************************************** + * + * internal/compiler-macros.h + * + * Compiler-specific macro definitions used internally by FreeType. + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 INTERNAL_COMPILER_MACROS_H_ +#define INTERNAL_COMPILER_MACROS_H_ + +#include + +FT_BEGIN_HEADER + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Fix compiler warning with sgi compiler. */ +#if defined( __sgi ) && !defined( __GNUC__ ) +# if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 ) +# pragma set woff 3505 +# endif +#endif + + /* Newer compilers warn for fall-through case statements. */ +#ifndef FALL_THROUGH +# if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \ + ( defined( __cplusplus ) && __cplusplus > 201402L ) +# define FALL_THROUGH [[__fallthrough__]] +# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \ + ( defined( __clang__ ) && \ + ( defined( __apple_build_version__ ) \ + ? __apple_build_version__ >= 12000000 \ + : __clang_major__ >= 10 ) ) +# define FALL_THROUGH __attribute__(( __fallthrough__ )) +# else +# define FALL_THROUGH ( (void)0 ) +# endif +#endif + + /* + * When defining a macro that expands to a non-trivial C statement, use + * FT_BEGIN_STMNT and FT_END_STMNT to enclose the macro's body. This + * ensures there are no surprises when the macro is invoked in conditional + * branches. + * + * Example: + * + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + */ +#define FT_BEGIN_STMNT do { +#define FT_END_STMNT } while ( 0 ) + + /* + * FT_DUMMY_STMNT expands to an empty C statement. Useful for + * conditionally defined statement macros. + * + * Example: + * + * #ifdef BUILD_CONFIG_LOGGING + * #define LOG( ... ) \ + * FT_BEGIN_STMNT \ + * if ( logging_enabled ) \ + * log( __VA_ARGS__ ); \ + * FT_END_STMNT + * #else + * # define LOG( ... ) FT_DUMMY_STMNT + * #endif + */ +#define FT_DUMMY_STMNT FT_BEGIN_STMNT FT_END_STMNT + +#ifdef __UINTPTR_TYPE__ + /* + * GCC and Clang both provide a `__UINTPTR_TYPE__` that can be used to + * avoid a dependency on `stdint.h`. + */ +# define FT_UINT_TO_POINTER( x ) (void *)(__UINTPTR_TYPE__)(x) +#elif defined( _WIN64 ) + /* only 64bit Windows uses the LLP64 data model, i.e., */ + /* 32-bit integers, 64-bit pointers. */ +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned __int64)(x) +#else +# define FT_UINT_TO_POINTER( x ) (void *)(unsigned long)(x) +#endif + + /* + * Use `FT_TYPEOF( type )` to cast a value to `type`. This is useful to + * suppress signedness compilation warnings in macros. + * + * Example: + * + * #define PAD_( x, n ) ( (x) & ~FT_TYPEOF( x )( (n) - 1 ) ) + * + * (The `typeof` condition is taken from gnulib's `intprops.h` header + * file.) + */ +#if ( ( defined( __GNUC__ ) && __GNUC__ >= 2 ) || \ + ( defined( __IBMC__ ) && __IBMC__ >= 1210 && \ + defined( __IBM__TYPEOF__ ) ) || \ + ( defined( __SUNPRO_C ) && __SUNPRO_C >= 0x5110 && !__STDC__ ) ) +#define FT_TYPEOF( type ) ( __typeof__ ( type ) ) +#else +#define FT_TYPEOF( type ) /* empty */ +#endif + + /* + * Mark a function declaration as internal to the library. This ensures + * that it will not be exposed by default to client code, and helps + * generate smaller and faster code on ELF-based platforms. Place this + * before a function declaration. + */ + + /* Visual C, MinGW, Cygwin */ +#if defined( _WIN32 ) || defined( __CYGWIN__ ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ + + /* gcc, clang */ +#elif ( defined( __GNUC__ ) && __GNUC__ >= 4 ) || defined( __clang__ ) +#define FT_INTERNAL_FUNCTION_ATTRIBUTE \ + __attribute__(( visibility( "hidden" ) )) + + /* Sun */ +#elif defined( __SUNPRO_C ) && __SUNPRO_C >= 0x550 +#define FT_INTERNAL_FUNCTION_ATTRIBUTE __hidden + +#else +#define FT_INTERNAL_FUNCTION_ATTRIBUTE /* empty */ +#endif + + /* + * FreeType supports compilation of its C sources with a C++ compiler (in + * C++ mode); this introduces a number of subtle issues. + * + * The main one is that a C++ function declaration and its definition must + * have the same 'linkage'. Because all FreeType headers declare their + * functions with C linkage (i.e., within an `extern "C" { ... }` block + * due to the magic of FT_BEGIN_HEADER and FT_END_HEADER), their + * definition in FreeType sources should also be prefixed with `extern + * "C"` when compiled in C++ mode. + * + * The `FT_FUNCTION_DECLARATION` and `FT_FUNCTION_DEFINITION` macros are + * provided to deal with this case, as well as `FT_CALLBACK_DEF` and its + * siblings below. + */ + + /* + * `FT_FUNCTION_DECLARATION( type )` can be used to write a C function + * declaration to ensure it will have C linkage when the library is built + * with a C++ compiler. The parameter is the function's return type, so a + * declaration would look like + * + * FT_FUNCTION_DECLARATION( int ) + * foo( int x ); + * + * NOTE: This requires that all uses are inside of `FT_BEGIN_HEADER ... + * FT_END_HEADER` blocks, which guarantees that the declarations have C + * linkage when the headers are included by C++ sources. + * + * NOTE: Do not use directly. Use `FT_LOCAL`, `FT_BASE`, and `FT_EXPORT` + * instead. + */ +#define FT_FUNCTION_DECLARATION( x ) extern x + + /* + * Same as `FT_FUNCTION_DECLARATION`, but for function definitions instead. + * + * NOTE: Do not use directly. Use `FT_LOCAL_DEF`, `FT_BASE_DEF`, and + * `FT_EXPORT_DEF` instead. + */ +#ifdef __cplusplus +#define FT_FUNCTION_DEFINITION( x ) extern "C" x +#else +#define FT_FUNCTION_DEFINITION( x ) x +#endif + + /* + * Use `FT_LOCAL` and `FT_LOCAL_DEF` to declare and define, respectively, + * an internal FreeType function that is only used by the sources of a + * single `src/module/` directory. This ensures that the functions are + * turned into static ones at build time, resulting in smaller and faster + * code. + */ +#ifdef FT_MAKE_OPTION_SINGLE_OBJECT + +#define FT_LOCAL( x ) static x +#define FT_LOCAL_DEF( x ) static x + +#else + +#define FT_LOCAL( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_LOCAL_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */ + + /* + * Use `FT_LOCAL_ARRAY` and `FT_LOCAL_ARRAY_DEF` to declare and define, + * respectively, a constant array that must be accessed from several + * sources in the same `src/module/` sub-directory, and which are internal + * to the library. + */ +#define FT_LOCAL_ARRAY( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + extern const x +#define FT_LOCAL_ARRAY_DEF( x ) FT_FUNCTION_DEFINITION( const x ) + + /* + * `Use FT_BASE` and `FT_BASE_DEF` to declare and define, respectively, an + * internal library function that is used by more than a single module. + */ +#define FT_BASE( x ) FT_INTERNAL_FUNCTION_ATTRIBUTE \ + FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + + /* + * NOTE: Conditionally define `FT_EXPORT_VAR` due to its definition in + * `src/smooth/ftgrays.h` to make the header more portable. + */ +#ifndef FT_EXPORT_VAR +#define FT_EXPORT_VAR( x ) FT_FUNCTION_DECLARATION( x ) +#endif + + /* + * When compiling FreeType as a DLL or DSO with hidden visibility, + * some systems/compilers need a special attribute 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. + * + * To export a variable, use `FT_EXPORT_VAR`. + */ + + /* See `freetype/config/public-macros.h` for the `FT_EXPORT` definition */ +#define FT_EXPORT_DEF( x ) FT_FUNCTION_DEFINITION( x ) + + /* + * 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, + * located in the same source code file as the structure that uses + * it. FT_COMPARE_DEF, in addition, ensures the `cdecl` calling + * convention on x86, required by the C library function `qsort`. + * + * FT_BASE_CALLBACK and FT_BASE_CALLBACK_DEF are used to declare + * and define a callback function, respectively, in a similar way + * as FT_BASE and FT_BASE_DEF work. + * + * 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. + */ +#ifdef __cplusplus +#define FT_CALLBACK_DEF( x ) extern "C" x +#else +#define FT_CALLBACK_DEF( x ) static x +#endif + +#if defined( __GNUC__ ) && defined( __i386__ ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __attribute__(( cdecl )) +#elif defined( _MSC_VER ) && defined( _M_IX86 ) +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __cdecl +#elif defined( __WATCOMC__ ) && __WATCOMC__ >= 1240 +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) __watcall +#else +#define FT_COMPARE_DEF( x ) FT_CALLBACK_DEF( x ) +#endif + +#define FT_BASE_CALLBACK( x ) FT_FUNCTION_DECLARATION( x ) +#define FT_BASE_CALLBACK_DEF( x ) FT_FUNCTION_DEFINITION( x ) + +#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 /* INTERNAL_COMPILER_MACROS_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftcalc.h b/src/thirdparty/freetype2/include/freetype/internal/ftcalc.h index 1811fcd1e..16a732224 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftcalc.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftcalc.h @@ -4,7 +4,7 @@ * * Arithmetic computations (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,24 +20,94 @@ #define FTCALC_H_ -#include -#include FT_FREETYPE_H +#include +#include "compiler-macros.h" FT_BEGIN_HEADER + /* + * The following macros have two purposes. + * + * - Tag places where overflow is expected and harmless. + * + * - Avoid run-time undefined behavior sanitizer errors. + * + * Use with care! + */ +#define ADD_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) +#define SUB_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) +#define MUL_INT( a, b ) \ + (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) +#define NEG_INT( a ) \ + (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) + +#define ADD_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) +#define SUB_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) +#define MUL_LONG( a, b ) \ + (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) +#define NEG_LONG( a ) \ + (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) + +#define ADD_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) +#define SUB_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) +#define MUL_INT32( a, b ) \ + (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) +#define NEG_INT32( a ) \ + (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) + +#ifdef FT_INT64 + +#define ADD_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) +#define SUB_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) +#define MUL_INT64( a, b ) \ + (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) +#define NEG_INT64( a ) \ + (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) + +#endif /* FT_INT64 */ + + /************************************************************************** * * FT_MulDiv() and FT_MulFix() are declared in freetype.h. * */ -#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER - /* Provide assembler fragments for performance-critical functions. */ - /* These must be defined `static __inline__' with GCC. */ +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX -#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ +#ifdef FT_INT64 + + static inline FT_Long + FT_MulFix_64( FT_Long a, + FT_Long b ) + { + FT_Int64 ab = MUL_INT64( a, b ); + + + ab = ADD_INT64( ab, 0x8000 + ( ab >> 63 ) ); /* rounding phase */ + + return (FT_Long)( ab >> 16 ); + } + + +#define FT_MulFix( a, b ) FT_MulFix_64( a, b ) + +#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER ) + /* Provide 32-bit assembler fragments for optimized FT_MulFix. */ + /* These must be defined `static __inline__' or similar. */ + +#if defined( __arm__ ) && \ + ( defined( __thumb2__ ) || !defined( __thumb__ ) ) #define FT_MULFIX_ASSEMBLER FT_MulFix_arm @@ -49,6 +119,7 @@ FT_BEGIN_HEADER { FT_Int32 t, t2; +#if defined( __CC_ARM ) || defined( __ARMCC__ ) /* RVCT */ __asm { @@ -60,28 +131,8 @@ FT_BEGIN_HEADER mov a, t2, lsr #16 /* a = t2 >> 16 */ orr a, a, t, lsl #16 /* a |= t << 16 */ } - return a; - } - -#endif /* __CC_ARM || __ARMCC__ */ - - -#ifdef __GNUC__ - -#if defined( __arm__ ) && \ - ( !defined( __thumb__ ) || defined( __thumb2__ ) ) && \ - !( defined( __CC_ARM ) || defined( __ARMCC__ ) ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_arm - - /* documentation is in freetype.h */ - - static __inline__ FT_Int32 - FT_MulFix_arm( FT_Int32 a, - FT_Int32 b ) - { - FT_Int32 t, t2; +#elif defined( __GNUC__ ) __asm__ __volatile__ ( "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */ @@ -98,26 +149,25 @@ FT_BEGIN_HEADER : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); + +#endif + return a; } -#endif /* __arm__ && */ - /* ( __thumb2__ || !__thumb__ ) && */ - /* !( __CC_ARM || __ARMCC__ ) */ - - -#if defined( __i386__ ) +#elif defined( __i386__ ) || defined( _M_IX86 ) #define FT_MULFIX_ASSEMBLER FT_MulFix_i386 /* documentation is in freetype.h */ - static __inline__ FT_Int32 + static __inline FT_Int32 FT_MulFix_i386( FT_Int32 a, FT_Int32 b ) { FT_Int32 result; +#if defined( __GNUC__ ) __asm__ __volatile__ ( "imul %%edx\n" @@ -132,27 +182,8 @@ FT_BEGIN_HEADER : "=a"(result), "=d"(b) : "a"(a), "d"(b) : "%ecx", "cc" ); - return result; - } -#endif /* i386 */ - -#endif /* __GNUC__ */ - - -#ifdef _MSC_VER /* Visual C++ */ - -#ifdef _M_IX86 - -#define FT_MULFIX_ASSEMBLER FT_MulFix_i386 - - /* documentation is in freetype.h */ - - static __inline FT_Int32 - FT_MulFix_i386( FT_Int32 a, - FT_Int32 b ) - { - FT_Int32 result; +#elif defined( _MSC_VER ) __asm { @@ -169,81 +200,21 @@ FT_BEGIN_HEADER add eax, edx mov result, eax } + +#endif + return result; } -#endif /* _M_IX86 */ +#endif /* __i386__ || _M_IX86 */ -#endif /* _MSC_VER */ - - -#if defined( __GNUC__ ) && defined( __x86_64__ ) - -#define FT_MULFIX_ASSEMBLER FT_MulFix_x86_64 - - static __inline__ FT_Int32 - FT_MulFix_x86_64( FT_Int32 a, - FT_Int32 b ) - { - /* Temporarily disable the warning that C90 doesn't support */ - /* `long long'. */ -#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wlong-long" -#endif - -#if 1 - /* Technically not an assembly fragment, but GCC does a really good */ - /* job at inlining it and generating good machine code for it. */ - long long ret, tmp; - - - ret = (long long)a * b; - tmp = ret >> 63; - ret += 0x8000 + tmp; - - return (FT_Int32)( ret >> 16 ); -#else - - /* For some reason, GCC 4.6 on Ubuntu 12.04 generates invalid machine */ - /* code from the lines below. The main issue is that `wide_a' is not */ - /* properly initialized by sign-extending `a'. Instead, the generated */ - /* machine code assumes that the register that contains `a' on input */ - /* can be used directly as a 64-bit value, which is wrong most of the */ - /* time. */ - long long wide_a = (long long)a; - long long wide_b = (long long)b; - long long result; - - - __asm__ __volatile__ ( - "imul %2, %1\n" - "mov %1, %0\n" - "sar $63, %0\n" - "lea 0x8000(%1, %0), %0\n" - "sar $16, %0\n" - : "=&r"(result), "=&r"(wide_a) - : "r"(wide_b) - : "cc" ); - - return (FT_Int32)result; -#endif - -#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) -#pragma GCC diagnostic pop -#endif - } - -#endif /* __GNUC__ && __x86_64__ */ - -#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ - - -#ifdef FT_CONFIG_OPTION_INLINE_MULFIX #ifdef FT_MULFIX_ASSEMBLER #define FT_MulFix( a, b ) FT_MULFIX_ASSEMBLER( (FT_Int32)(a), (FT_Int32)(b) ) #endif -#endif + +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + +#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */ /************************************************************************** @@ -298,9 +269,9 @@ FT_BEGIN_HEADER * Based on geometric considerations we use the following inequality to * identify a degenerate matrix. * - * 50 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2 + * 32 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2 * - * Value 50 is heuristic. + * Value 32 is heuristic. */ FT_BASE( FT_Bool ) FT_Matrix_Check( const FT_Matrix* matrix ); @@ -359,8 +330,8 @@ FT_BEGIN_HEADER #ifndef FT_CONFIG_OPTION_NO_ASSEMBLER -#if defined( __GNUC__ ) && \ - ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) +#if defined( __clang__ ) || ( defined( __GNUC__ ) && \ + ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 4 ) ) ) #if FT_SIZEOF_INT == 4 @@ -370,12 +341,25 @@ FT_BEGIN_HEADER #define FT_MSB( x ) ( 31 - __builtin_clzl( x ) ) -#endif /* __GNUC__ */ +#endif +#elif defined( _MSC_VER ) && _MSC_VER >= 1400 -#elif defined( _MSC_VER ) && ( _MSC_VER >= 1400 ) +#if defined( _WIN32_WCE ) -#if FT_SIZEOF_INT == 4 +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_ARM64 ) || defined( _M_ARM ) || defined( _M_ARM64EC ) + +#include +#pragma intrinsic( _CountLeadingZeros ) + +#define FT_MSB( x ) ( 31 - _CountLeadingZeros( x ) ) + +#elif defined( _M_IX86 ) || defined( _M_AMD64 ) || defined( _M_IA64 ) #include #pragma intrinsic( _BitScanReverse ) @@ -391,15 +375,50 @@ FT_BEGIN_HEADER return (FT_Int32)where; } -#define FT_MSB( x ) ( FT_MSB_i386( x ) ) +#define FT_MSB( x ) FT_MSB_i386( x ) #endif -#endif /* _MSC_VER */ +#elif defined( __WATCOMC__ ) && defined( __386__ ) + extern __inline FT_Int32 + FT_MSB_i386( FT_UInt32 x ); + +#pragma aux FT_MSB_i386 = \ + "bsr eax, eax" \ + __parm [__eax] __nomemory \ + __value [__eax] \ + __modify __exact [__eax] __nomemory; + +#define FT_MSB( x ) FT_MSB_i386( x ) + +#elif defined( __CC_ARM ) + +#define FT_MSB( x ) ( 31 - __clz( x ) ) + +#elif defined( __SunOS_5_11 ) + +#include + +#define FT_MSB( x ) ( fls( x ) - 1 ) + +#elif defined( __DECC ) || defined( __DECCXX ) + +#include + +#define FT_MSB( x ) (FT_Int)( 63 - _leadz( x ) ) + +#elif defined( _CRAYC ) + +#include + +#define FT_MSB( x ) (FT_Int)( 31 - _leadz32( x ) ) + +#endif /* FT_MSB macro definitions */ #endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ + #ifndef FT_MSB FT_BASE( FT_Int ) @@ -417,8 +436,6 @@ FT_BEGIN_HEADER FT_Fixed y ); -#if 0 - /************************************************************************** * * @function: @@ -435,12 +452,11 @@ FT_BEGIN_HEADER * The result of 'sqrt(x)'. * * @note: - * This function is not very fast. + * This function is slow and should be avoided. Consider @FT_Hypot or + * @FT_Vector_NormLen instead. */ - FT_BASE( FT_Int32 ) - FT_SqrtFixed( FT_Int32 x ); - -#endif /* 0 */ + FT_BASE( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 x ); #define INT_TO_F26DOT6( x ) ( (FT_Long)(x) * 64 ) /* << 6 */ @@ -449,57 +465,7 @@ FT_BEGIN_HEADER #define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) * 4 ) /* << 2 */ #define FIXED_TO_INT( x ) ( FT_RoundFix( x ) >> 16 ) -#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \ - : ( -( ( 32 - (x) ) & -64 ) ) ) - - /* - * The following macros have two purposes. - * - * - Tag places where overflow is expected and harmless. - * - * - Avoid run-time sanitizer errors. - * - * Use with care! - */ -#define ADD_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) + (FT_UInt)(b) ) -#define SUB_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) - (FT_UInt)(b) ) -#define MUL_INT( a, b ) \ - (FT_Int)( (FT_UInt)(a) * (FT_UInt)(b) ) -#define NEG_INT( a ) \ - (FT_Int)( (FT_UInt)0 - (FT_UInt)(a) ) - -#define ADD_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) + (FT_ULong)(b) ) -#define SUB_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) - (FT_ULong)(b) ) -#define MUL_LONG( a, b ) \ - (FT_Long)( (FT_ULong)(a) * (FT_ULong)(b) ) -#define NEG_LONG( a ) \ - (FT_Long)( (FT_ULong)0 - (FT_ULong)(a) ) - -#define ADD_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) + (FT_UInt32)(b) ) -#define SUB_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) - (FT_UInt32)(b) ) -#define MUL_INT32( a, b ) \ - (FT_Int32)( (FT_UInt32)(a) * (FT_UInt32)(b) ) -#define NEG_INT32( a ) \ - (FT_Int32)( (FT_UInt32)0 - (FT_UInt32)(a) ) - -#ifdef FT_LONG64 - -#define ADD_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) + (FT_UInt64)(b) ) -#define SUB_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) - (FT_UInt64)(b) ) -#define MUL_INT64( a, b ) \ - (FT_Int64)( (FT_UInt64)(a) * (FT_UInt64)(b) ) -#define NEG_INT64( a ) \ - (FT_Int64)( (FT_UInt64)0 - (FT_UInt64)(a) ) - -#endif /* FT_LONG64 */ +#define ROUND_F26DOT6( x ) ( ( (x) + 32 - ( x < 0 ) ) & -64 ) FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftdebug.h b/src/thirdparty/freetype2/include/freetype/internal/ftdebug.h index 54a9673af..d7facf40d 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftdebug.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftdebug.h @@ -4,7 +4,7 @@ * * Debugging and logging component (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,11 +27,28 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_FREETYPE_H +#include + +#include "compiler-macros.h" + +#ifdef FT_DEBUG_LOGGING +#define DLG_STATIC +#include +#include + +#include +#endif /* FT_DEBUG_LOGGING */ FT_BEGIN_HEADER + /* force the definition of FT_DEBUG_LEVEL_TRACE if FT_DEBUG_LOGGING is */ + /* already defined. */ + /* */ +#ifdef FT_DEBUG_LOGGING +#undef FT_DEBUG_LEVEL_TRACE +#define FT_DEBUG_LEVEL_TRACE +#endif /* force the definition of FT_DEBUG_LEVEL_ERROR if FT_DEBUG_LEVEL_TRACE */ /* is already defined; this simplifies the following #ifdefs */ @@ -56,7 +73,7 @@ FT_BEGIN_HEADER /* defining the enumeration */ typedef enum FT_Trace_ { -#include FT_INTERNAL_TRACE_H +#include trace_count } FT_Trace; @@ -80,20 +97,66 @@ FT_BEGIN_HEADER * Each component must define the macro FT_COMPONENT to a valid FT_Trace * value before using any TRACE macro. * + * To get consistent logging output, there should be no newline character + * (i.e., '\n') or a single trailing one in the message string of + * `FT_TRACEx` and `FT_ERROR`. */ + + /************************************************************************* + * + * If FT_DEBUG_LOGGING is enabled, tracing messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, tracing messages are sent to + * `FT_Message` (defined in ftdebug.c). + */ +#ifdef FT_DEBUG_LOGGING + + /* we need two macros to convert the names of `FT_COMPONENT` to a string */ +#define FT_LOGGING_TAG( x ) FT_LOGGING_TAG_( x ) +#define FT_LOGGING_TAG_( x ) #x + + /* we need two macros to convert the component and the trace level */ + /* to a string that combines them */ +#define FT_LOGGING_TAGX( x, y ) FT_LOGGING_TAGX_( x, y ) +#define FT_LOGGING_TAGX_( x, y ) #x ":" #y + + +#define FT_LOG( level, varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAGX( FT_COMPONENT, level ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + { \ + if ( custom_output_handler != NULL ) \ + FT_Logging_Callback varformat; \ + else \ + dlg_trace varformat; \ + } \ + ft_remove_tag( dlg_tag ); \ + } while( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_LOG( level, varformat ) \ + do \ + { \ + if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ + FT_Message varformat; \ + } while ( 0 ) + +#endif /* !FT_DEBUG_LOGGING */ + + #ifdef FT_DEBUG_LEVEL_TRACE /* we need two macros here to make cpp expand `FT_COMPONENT' */ #define FT_TRACE_COMP( x ) FT_TRACE_COMP_( x ) #define FT_TRACE_COMP_( x ) trace_ ## x -#define FT_TRACE( level, varformat ) \ - do \ - { \ - if ( ft_trace_levels[FT_TRACE_COMP( FT_COMPONENT )] >= level ) \ - FT_Message varformat; \ - } while ( 0 ) +#define FT_TRACE( level, varformat ) FT_LOG( level, varformat ) #else /* !FT_DEBUG_LEVEL_TRACE */ @@ -202,7 +265,32 @@ FT_BEGIN_HEADER #ifdef FT_DEBUG_LEVEL_ERROR -#define FT_ERROR( varformat ) FT_Message varformat + /************************************************************************** + * + * If FT_DEBUG_LOGGING is enabled, error messages are sent to dlg's API. + * If FT_DEBUG_LOGGING is disabled, error messages are sent to `FT_Message` + * (defined in ftdebug.c). + * + */ +#ifdef FT_DEBUG_LOGGING + +#define FT_ERROR( varformat ) \ + do \ + { \ + const char* dlg_tag = FT_LOGGING_TAG( FT_COMPONENT ); \ + \ + \ + ft_add_tag( dlg_tag ); \ + dlg_trace varformat; \ + ft_remove_tag( dlg_tag ); \ + } while ( 0 ) + +#else /* !FT_DEBUG_LOGGING */ + +#define FT_ERROR( varformat ) FT_Message varformat + +#endif /* !FT_DEBUG_LOGGING */ + #else /* !FT_DEBUG_LEVEL_ERROR */ @@ -275,6 +363,77 @@ FT_BEGIN_HEADER FT_BASE( void ) ft_debug_init( void ); + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * 'dlg' uses output handlers to control how and where log messages are + * printed. Therefore we need to define a default output handler for + * FreeType. + */ + FT_BASE( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ); + + + /************************************************************************** + * + * 1. `ft_default_log_handler` stores the function pointer that is used + * internally by FreeType to print logs to a file. + * + * 2. `custom_output_handler` stores the function pointer to the callback + * function provided by the user. + * + * It is defined in `ftdebug.c`. + */ + extern dlg_handler ft_default_log_handler; + extern FT_Custom_Log_Handler custom_output_handler; + + + /************************************************************************** + * + * If FT_DEBUG_LOGGING macro is enabled, FreeType needs to initialize and + * un-initialize `FILE*`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_logging_init( void ); + + FT_BASE( void ) + ft_logging_deinit( void ); + + + /************************************************************************** + * + * For printing the name of `FT_COMPONENT` along with the actual log we + * need to add a tag with the name of `FT_COMPONENT`. + * + * These functions are defined in `ftdebug.c`. + */ + FT_BASE( void ) + ft_add_tag( const char* tag ); + + FT_BASE( void ) + ft_remove_tag( const char* tag ); + + + /************************************************************************** + * + * A function to print log data using a custom callback logging function + * (which is set using `FT_Set_Log_Handler`). + * + * This function is defined in `ftdebug.c`. + */ + FT_BASE( void ) + FT_Logging_Callback( const char* fmt, + ... ); + +#endif /* FT_DEBUG_LOGGING */ + + FT_END_HEADER #endif /* FTDEBUG_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftdrv.h b/src/thirdparty/freetype2/include/freetype/internal/ftdrv.h index 09e846e1c..24be4dad3 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftdrv.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftdrv.h @@ -4,7 +4,7 @@ * * FreeType internal font driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,9 @@ #define FTDRV_H_ -#include -#include FT_MODULE_H +#include +#include "compiler-macros.h" FT_BEGIN_HEADER @@ -157,6 +157,7 @@ FT_BEGIN_HEADER * 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`, can be set * to 0 to indicate a default behaviour. diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftgloadr.h b/src/thirdparty/freetype2/include/freetype/internal/ftgloadr.h index 770871d81..8f2a54c01 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftgloadr.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftgloadr.h @@ -4,7 +4,7 @@ * * The FreeType glyph loader (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,9 @@ #define FTGLOADR_H_ -#include -#include FT_FREETYPE_H +#include +#include "compiler-macros.h" FT_BEGIN_HEADER @@ -138,8 +138,6 @@ FT_BEGIN_HEADER FT_BASE( void ) FT_GlyphLoader_Add( FT_GlyphLoader loader ); - /* */ - FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/fthash.h b/src/thirdparty/freetype2/include/freetype/internal/fthash.h index 249188040..642d21e21 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/fthash.h +++ b/src/thirdparty/freetype2/include/freetype/internal/fthash.h @@ -43,8 +43,7 @@ #define FTHASH_H_ -#include -#include FT_FREETYPE_H +#include FT_BEGIN_HEADER @@ -118,6 +117,18 @@ FT_BEGIN_HEADER FT_Hash hash, FT_Memory memory ); + FT_Error + ft_hash_str_insert_no_overwrite( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ); + + FT_Error + ft_hash_num_insert_no_overwrite( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ); + size_t* ft_hash_str_lookup( const char* key, FT_Hash hash ); @@ -126,6 +137,17 @@ FT_BEGIN_HEADER ft_hash_num_lookup( FT_Int num, FT_Hash hash ); + FT_Bool + ft_hash_num_iterator( FT_UInt *idx, + FT_Int *key, + size_t *value, + FT_Hash hash ); + + FT_Bool + ft_hash_str_iterator( FT_UInt *idx, + const char* *key, + size_t *value, + FT_Hash hash ); FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftmemory.h b/src/thirdparty/freetype2/include/freetype/internal/ftmemory.h index 78bd3bc22..c75c33f28 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftmemory.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftmemory.h @@ -4,7 +4,7 @@ * * The FreeType memory management macros (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -22,8 +22,9 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_TYPES_H +#include +#include "compiler-macros.h" FT_BEGIN_HEADER @@ -57,6 +58,14 @@ FT_BEGIN_HEADER /*************************************************************************/ + /* The calculation `NULL + n' is undefined in C. Even if the resulting */ + /* pointer doesn't get dereferenced, this causes warnings with */ + /* sanitizers. */ + /* */ + /* We thus provide a macro that should be used if `base' can be NULL. */ +#define FT_OFFSET( base, count ) ( (base) ? (base) + (count) : NULL ) + + /* * C++ refuses to handle statements like p = (void*)anything, with `p' a * typed pointer. Since we don't have a `typeof' operator in standard C++, @@ -87,15 +96,15 @@ extern "C++" #ifdef FT_DEBUG_MEMORY - FT_BASE( const char* ) _ft_debug_file; - FT_BASE( long ) _ft_debug_lineno; + 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__, \ +#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__, \ +#define FT_ASSIGNP_INNER( p, exp ) ( ft_debug_file_ = __FILE__, \ + ft_debug_lineno_ = __LINE__, \ FT_ASSIGNP( p, exp ) ) #else /* !FT_DEBUG_MEMORY */ @@ -153,10 +162,10 @@ extern "C++" (FT_Long)(size), \ &error ) ) -#define FT_MEM_FREE( ptr ) \ - FT_BEGIN_STMNT \ - ft_mem_free( memory, (ptr) ); \ - (ptr) = NULL; \ +#define FT_MEM_FREE( ptr ) \ + FT_BEGIN_STMNT \ + FT_DEBUG_INNER( ft_mem_free( memory, (ptr) ) ); \ + (ptr) = NULL; \ FT_END_STMNT #define FT_MEM_NEW( ptr ) \ @@ -335,14 +344,13 @@ extern "C++" #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( 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_QNEW_ARRAY( ptr, count ) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW_ARRAY( ptr, count ) ) -#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ - FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY( ptr, curcnt, newcnt ) ) +#define FT_QRENEW_ARRAY( ptr, curcnt, newcnt ) \ + FT_MEM_SET_ERROR( FT_MEM_QRENEW_ARRAY( ptr, curcnt, newcnt ) ) FT_BASE( FT_Pointer ) @@ -363,8 +371,11 @@ extern "C++" #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_MEM_DUP( dst, address, size ) \ + FT_ASSIGNP_INNER( 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 ) ) @@ -381,8 +392,6 @@ extern "C++" #define FT_STRCPYN( dst, src, size ) \ ft_mem_strcpyn( (char*)dst, (const char*)(src), (FT_ULong)(size) ) - /* */ - FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftmmtypes.h b/src/thirdparty/freetype2/include/freetype/internal/ftmmtypes.h new file mode 100644 index 000000000..be3747bbf --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/internal/ftmmtypes.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * + * ftmmtypes.h + * + * OpenType Variations type definitions for internal use + * with the multi-masters service (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and + * Dominik Röttsches. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTMMTYPES_H_ +#define FTMMTYPES_H_ + +FT_BEGIN_HEADER + + + typedef FT_Int32 FT_ItemVarDelta; + + typedef struct GX_ItemVarDataRec_ + { + FT_UInt itemCount; /* Number of delta sets per item. */ + FT_UInt regionIdxCount; /* Number of region indices. */ + FT_UInt* regionIndices; /* Array of `regionCount` indices; */ + /* these index `varRegionList`. */ + FT_Byte* deltaSet; /* Array of `itemCount` deltas; */ + /* use `innerIndex` for this array. */ + FT_UShort wordDeltaCount; /* Number of the first 32-bit ints */ + /* or 16-bit ints of `deltaSet` */ + /* depending on `longWords`. */ + FT_Bool longWords; /* If true, `deltaSet` is a 32-bit */ + /* array followed by a 16-bit */ + /* array, otherwise a 16-bit array */ + /* followed by an 8-bit array. */ + } GX_ItemVarDataRec, *GX_ItemVarData; + + + /* contribution of one axis to a region */ + typedef struct GX_AxisCoordsRec_ + { + FT_Fixed startCoord; + FT_Fixed peakCoord; /* zero means no effect (factor = 1) */ + FT_Fixed endCoord; + + } GX_AxisCoordsRec, *GX_AxisCoords; + + + typedef struct GX_VarRegionRec_ + { + GX_AxisCoords axisList; /* array of axisCount records */ + + } GX_VarRegionRec, *GX_VarRegion; + + + /* item variation store */ + typedef struct GX_ItemVarStoreRec_ + { + FT_UInt dataCount; + GX_ItemVarData varData; /* array of dataCount records; */ + /* use `outerIndex' for this array */ + FT_UShort axisCount; + FT_UInt regionCount; /* total number of regions defined */ + GX_VarRegion varRegionList; + + } GX_ItemVarStoreRec, *GX_ItemVarStore; + + + typedef struct GX_DeltaSetIdxMapRec_ + { + FT_ULong mapCount; + FT_UInt* outerIndex; /* indices to item var data */ + FT_UInt* innerIndex; /* indices to delta set */ + + } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; + + +FT_END_HEADER + +#endif /* FTMMTYPES_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftobjs.h b/src/thirdparty/freetype2/include/freetype/internal/ftobjs.h index 0c1d3e5bf..3db2fe28f 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftobjs.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftobjs.h @@ -4,7 +4,7 @@ * * The FreeType private base classes (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,21 +26,21 @@ #ifndef FTOBJS_H_ #define FTOBJS_H_ -#include -#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 -#include FT_INTERNAL_CALC_H +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef FT_CONFIG_OPTION_INCREMENTAL -#include FT_INCREMENTAL_H +#include #endif +#include "compiler-macros.h" FT_BEGIN_HEADER @@ -226,8 +226,8 @@ FT_BEGIN_HEADER } FT_CMap_ClassRec; -#define FT_DECLARE_CMAP_CLASS( class_ ) \ - FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; +#define FT_DECLARE_CMAP_CLASS( class_ ) \ + FT_CALLBACK_TABLE const FT_CMap_ClassRec class_; #define FT_DEFINE_CMAP_CLASS( \ class_, \ @@ -275,6 +275,28 @@ FT_BEGIN_HEADER FT_GlyphSlot slot, FT_Render_Mode mode ); + + /************************************************************************** + * + * @Function: + * find_unicode_charmap + * + * @Description: + * 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 (UCS-2 + * encoding.) + * + * If a unicode charmap is found, `face->charmap` is set to it. + * + * This function is called from `open_face`, from `FT_Select_Charmap(..., + * FT_ENCODING_UNICODE)`, and also from `afadjust.c` in the 'autofit' + * module. + */ + FT_BASE( FT_Error ) + find_unicode_charmap( FT_Face face ); + + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, @@ -418,7 +440,8 @@ FT_BEGIN_HEADER * initializing the glyph slot. */ -#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_BITMAP 0x1U +#define FT_GLYPH_OWN_GZIP_SVG 0x2U typedef struct FT_Slot_InternalRec_ { @@ -497,9 +520,9 @@ FT_BEGIN_HEADER */ typedef struct FT_ModuleRec_ { - FT_Module_Class* clazz; - FT_Library library; - FT_Memory memory; + const FT_Module_Class* clazz; + FT_Library library; + FT_Memory memory; } FT_ModuleRec; @@ -603,12 +626,6 @@ FT_BEGIN_HEADER #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 - /************************************************************************** * @@ -653,7 +670,7 @@ FT_BEGIN_HEADER FT_BASE( void ) FT_Done_GlyphSlot( FT_GlyphSlot slot ); - /* */ + /* */ #define FT_REQUEST_WIDTH( req ) \ ( (req)->horiResolution \ @@ -673,7 +690,7 @@ FT_BEGIN_HEADER /* Set the metrics according to a size request. */ - FT_BASE( void ) + FT_BASE( FT_Error ) FT_Request_Metrics( FT_Face face, FT_Size_Request req ); @@ -1057,6 +1074,9 @@ FT_BEGIN_HEADER * The struct will be allocated in the global scope (or the scope where * the macro is used). */ +#define FT_DECLARE_GLYPH( class_ ) \ + FT_CALLBACK_TABLE const FT_Glyph_Class class_; + #define FT_DEFINE_GLYPH( \ class_, \ size_, \ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftpsprop.h b/src/thirdparty/freetype2/include/freetype/internal/ftpsprop.h index 574837f6d..18a954d22 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftpsprop.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftpsprop.h @@ -4,7 +4,7 @@ * * Get and set properties of PostScript drivers (specification). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTPSPROP_H_ -#include -#include FT_FREETYPE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftrfork.h b/src/thirdparty/freetype2/include/freetype/internal/ftrfork.h index 75b3e531b..e077f98bf 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftrfork.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftrfork.h @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Masatake YAMATO and Redhat K.K. * * This file is part of the FreeType project, and may only be used, @@ -25,8 +25,7 @@ #define FTRFORK_H_ -#include -#include FT_INTERNAL_OBJECTS_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftserv.h b/src/thirdparty/freetype2/include/freetype/internal/ftserv.h index 8836cf3f1..ce11bba19 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftserv.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftserv.h @@ -4,7 +4,7 @@ * * The FreeType services (specification only). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -31,6 +31,7 @@ #ifndef FTSERV_H_ #define FTSERV_H_ +#include "compiler-macros.h" FT_BEGIN_HEADER @@ -486,33 +487,6 @@ FT_BEGIN_HEADER /* */ - /* - * The header files containing the services. - */ - -#define FT_SERVICE_BDF_H -#define FT_SERVICE_CFF_TABLE_LOAD_H -#define FT_SERVICE_CID_H -#define FT_SERVICE_FONT_FORMAT_H -#define FT_SERVICE_GLYPH_DICT_H -#define FT_SERVICE_GX_VALIDATE_H -#define FT_SERVICE_KERNING_H -#define FT_SERVICE_METRICS_VARIATIONS_H -#define FT_SERVICE_MULTIPLE_MASTERS_H -#define FT_SERVICE_OPENTYPE_VALIDATE_H -#define FT_SERVICE_PFR_H -#define FT_SERVICE_POSTSCRIPT_CMAPS_H -#define FT_SERVICE_POSTSCRIPT_INFO_H -#define FT_SERVICE_POSTSCRIPT_NAME_H -#define FT_SERVICE_PROPERTIES_H -#define FT_SERVICE_SFNT_H -#define FT_SERVICE_TRUETYPE_ENGINE_H -#define FT_SERVICE_TRUETYPE_GLYF_H -#define FT_SERVICE_TT_CMAP_H -#define FT_SERVICE_WINFNT_H - - /* */ - FT_END_HEADER #endif /* FTSERV_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftstream.h b/src/thirdparty/freetype2/include/freetype/internal/ftstream.h index a579a039b..20c1dd7c4 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftstream.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftstream.h @@ -4,7 +4,7 @@ * * Stream handling (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,8 @@ #include -#include FT_SYSTEM_H -#include FT_INTERNAL_OBJECTS_H +#include +#include FT_BEGIN_HEADER @@ -196,9 +196,9 @@ FT_BEGIN_HEADER FT_BYTE_U32( p, 2, 8 ) | \ FT_BYTE_U32( p, 3, 0 ) ) -#define FT_PEEK_OFF3( p ) FT_INT32( FT_BYTE_U32( p, 0, 16 ) | \ - FT_BYTE_U32( p, 1, 8 ) | \ - FT_BYTE_U32( p, 2, 0 ) ) +#define FT_PEEK_OFF3( p ) ( FT_INT32( FT_BYTE_U32( p, 0, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 2, 8 ) ) >> 8 ) #define FT_PEEK_UOFF3( p ) FT_UINT32( FT_BYTE_U32( p, 0, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ @@ -220,9 +220,9 @@ FT_BEGIN_HEADER FT_BYTE_U32( p, 1, 8 ) | \ FT_BYTE_U32( p, 0, 0 ) ) -#define FT_PEEK_OFF3_LE( p ) FT_INT32( 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_BYTE_U32( p, 2, 24 ) | \ + FT_BYTE_U32( p, 1, 16 ) | \ + FT_BYTE_U32( p, 0, 8 ) ) >> 8 ) #define FT_PEEK_UOFF3_LE( p ) FT_UINT32( FT_BYTE_U32( p, 2, 16 ) | \ FT_BYTE_U32( p, 1, 8 ) | \ @@ -238,42 +238,42 @@ FT_BEGIN_HEADER #define FT_NEXT_BYTE( buffer ) \ ( (unsigned char)*buffer++ ) -#define FT_NEXT_SHORT( buffer ) \ - ( (short)( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) ) +#define FT_NEXT_SHORT( buffer ) \ + ( buffer += 2, FT_PEEK_SHORT( buffer - 2 ) ) -#define FT_NEXT_USHORT( buffer ) \ - ( (unsigned short)( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) ) +#define FT_NEXT_USHORT( buffer ) \ + ( buffer += 2, FT_PEEK_USHORT( buffer - 2 ) ) -#define FT_NEXT_OFF3( buffer ) \ - ( (long)( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) ) +#define FT_NEXT_OFF3( buffer ) \ + ( buffer += 3, FT_PEEK_OFF3( buffer - 3 ) ) -#define FT_NEXT_UOFF3( buffer ) \ - ( (unsigned long)( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) ) +#define FT_NEXT_UOFF3( buffer ) \ + ( buffer += 3, FT_PEEK_UOFF3( buffer - 3 ) ) -#define FT_NEXT_LONG( buffer ) \ - ( (long)( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) ) +#define FT_NEXT_LONG( buffer ) \ + ( buffer += 4, FT_PEEK_LONG( buffer - 4 ) ) -#define FT_NEXT_ULONG( buffer ) \ - ( (unsigned long)( buffer += 4, FT_PEEK_ULONG( buffer - 4 ) ) ) +#define FT_NEXT_ULONG( buffer ) \ + ( 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_SHORT_LE( buffer ) \ + ( 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_USHORT_LE( buffer ) \ + ( 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_OFF3_LE( buffer ) \ + ( 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_UOFF3_LE( buffer ) \ + ( 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_LONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_LONG_LE( buffer - 4 ) ) -#define FT_NEXT_ULONG_LE( buffer ) \ - ( (unsigned long)( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) ) +#define FT_NEXT_ULONG_LE( buffer ) \ + ( buffer += 4, FT_PEEK_ULONG_LE( buffer - 4 ) ) /************************************************************************** @@ -305,20 +305,19 @@ FT_BEGIN_HEADER #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_GetUShort, FT_Short ) -#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UShort ) -#define FT_GET_OFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_Long ) -#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_ULong ) -#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Long ) -#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) -#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_ULong ) +#define FT_GET_CHAR() FT_GET_MACRO( FT_Stream_GetByte, FT_Char ) +#define FT_GET_BYTE() FT_GET_MACRO( FT_Stream_GetByte, FT_Byte ) +#define FT_GET_SHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_Int16 ) +#define FT_GET_USHORT() FT_GET_MACRO( FT_Stream_GetUShort, FT_UInt16 ) +#define FT_GET_UOFF3() FT_GET_MACRO( FT_Stream_GetUOffset, FT_UInt32 ) +#define FT_GET_LONG() FT_GET_MACRO( FT_Stream_GetULong, FT_Int32 ) +#define FT_GET_ULONG() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) +#define FT_GET_TAG4() FT_GET_MACRO( FT_Stream_GetULong, FT_UInt32 ) -#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Short ) -#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UShort ) -#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Long ) -#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_ULong ) +#define FT_GET_SHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_Int16 ) +#define FT_GET_USHORT_LE() FT_GET_MACRO( FT_Stream_GetUShortLE, FT_UInt16 ) +#define FT_GET_LONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_Int32 ) +#define FT_GET_ULONG_LE() FT_GET_MACRO( FT_Stream_GetULongLE, FT_UInt32 ) #endif @@ -333,19 +332,18 @@ FT_BEGIN_HEADER * `FT_STREAM_POS'. They use the full machinery to check whether a read is * valid. */ -#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_ReadUShort, FT_Short, var ) -#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UShort, var ) -#define FT_READ_OFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_Long, var ) -#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_ULong, var ) -#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Long, var ) -#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_ULong, var ) +#define FT_READ_BYTE( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Byte, var ) +#define FT_READ_CHAR( var ) FT_READ_MACRO( FT_Stream_ReadByte, FT_Char, var ) +#define FT_READ_SHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_Int16, var ) +#define FT_READ_USHORT( var ) FT_READ_MACRO( FT_Stream_ReadUShort, FT_UInt16, var ) +#define FT_READ_UOFF3( var ) FT_READ_MACRO( FT_Stream_ReadUOffset, FT_UInt32, var ) +#define FT_READ_LONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_Int32, var ) +#define FT_READ_ULONG( var ) FT_READ_MACRO( FT_Stream_ReadULong, FT_UInt32, var ) -#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Short, var ) -#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UShort, var ) -#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Long, var ) -#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_ULong, var ) +#define FT_READ_SHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_Int16, var ) +#define FT_READ_USHORT_LE( var ) FT_READ_MACRO( FT_Stream_ReadUShortLE, FT_UInt16, var ) +#define FT_READ_LONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_Int32, var ) +#define FT_READ_ULONG_LE( var ) FT_READ_MACRO( FT_Stream_ReadULongLE, FT_UInt32, var ) #ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM @@ -457,37 +455,37 @@ FT_BEGIN_HEADER /* read a byte from an entered frame */ - FT_BASE( FT_Char ) - FT_Stream_GetChar( FT_Stream stream ); + FT_BASE( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ); /* read a 16-bit big-endian unsigned integer from an entered frame */ - FT_BASE( FT_UShort ) + FT_BASE( FT_UInt16 ) FT_Stream_GetUShort( FT_Stream stream ); /* read a 24-bit big-endian unsigned integer from an entered frame */ - FT_BASE( FT_ULong ) + FT_BASE( FT_UInt32 ) FT_Stream_GetUOffset( FT_Stream stream ); /* read a 32-bit big-endian unsigned integer from an entered frame */ - FT_BASE( FT_ULong ) + FT_BASE( FT_UInt32 ) FT_Stream_GetULong( FT_Stream stream ); /* read a 16-bit little-endian unsigned integer from an entered frame */ - FT_BASE( FT_UShort ) + FT_BASE( FT_UInt16 ) FT_Stream_GetUShortLE( FT_Stream stream ); /* read a 32-bit little-endian unsigned integer from an entered frame */ - FT_BASE( FT_ULong ) + FT_BASE( FT_UInt32 ) FT_Stream_GetULongLE( FT_Stream stream ); /* read a byte from a stream */ - FT_BASE( FT_Char ) - FT_Stream_ReadChar( FT_Stream stream, + FT_BASE( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, FT_Error* error ); /* read a 16-bit big-endian unsigned integer from a stream */ - FT_BASE( FT_UShort ) + FT_BASE( FT_UInt16 ) FT_Stream_ReadUShort( FT_Stream stream, FT_Error* error ); @@ -497,17 +495,17 @@ FT_BEGIN_HEADER FT_Error* error ); /* read a 32-bit big-endian integer from a stream */ - FT_BASE( FT_ULong ) + FT_BASE( FT_UInt32 ) FT_Stream_ReadULong( FT_Stream stream, FT_Error* error ); /* read a 16-bit little-endian unsigned integer from a stream */ - FT_BASE( FT_UShort ) + FT_BASE( FT_UInt16 ) FT_Stream_ReadUShortLE( FT_Stream stream, FT_Error* error ); /* read a 32-bit little-endian unsigned integer from a stream */ - FT_BASE( FT_ULong ) + FT_BASE( FT_UInt32 ) FT_Stream_ReadULongLE( FT_Stream stream, FT_Error* error ); diff --git a/src/thirdparty/freetype2/include/freetype/internal/fttrace.h b/src/thirdparty/freetype2/include/freetype/internal/fttrace.h index f5f959804..3fd592800 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/fttrace.h +++ b/src/thirdparty/freetype2/include/freetype/internal/fttrace.h @@ -4,7 +4,7 @@ * * Tracing handling (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,6 +18,11 @@ /* definitions of trace levels for FreeType 2 */ + /* the maximum string length (if the argument to `FT_TRACE_DEF` */ + /* gets used as a string) plus one character for ':' plus */ + /* another one for the trace level */ +#define FT_MAX_TRACE_LEVEL_LENGTH (9 + 1 + 1) + /* the first level must always be `trace_any' */ FT_TRACE_DEF( any ) @@ -38,21 +43,29 @@ FT_TRACE_DEF( checksum ) /* bitmap checksum (ftobjs.c) */ FT_TRACE_DEF( mm ) /* MM interface (ftmm.c) */ FT_TRACE_DEF( psprops ) /* PS driver properties (ftpsprop.c) */ FT_TRACE_DEF( raccess ) /* resource fork accessor (ftrfork.c) */ -FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ -FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ FT_TRACE_DEF( synth ) /* bold/slant synthesizer (ftsynth.c) */ - /* Cache sub-system */ -FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ + /* rasterizers */ +FT_TRACE_DEF( raster ) /* monochrome rasterizer (ftraster.c) */ +FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */ + + /* ot-svg module */ +FT_TRACE_DEF( otsvg ) /* OT-SVG renderer (ftsvg.c) */ + + /* cache sub-system */ +FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */ /* SFNT driver components */ FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */ FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */ FT_TRACE_DEF( sfwoff ) /* WOFF format handler (sfwoff.c) */ +FT_TRACE_DEF( sfwoff2 ) /* WOFF2 format handler (sfwoff2.c) */ FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */ FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */ FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */ FT_TRACE_DEF( ttcpal ) /* color palette table (ttcpal.c) */ +FT_TRACE_DEF( ttgpos ) /* GPOS handler (ttgpos.c) */ +FT_TRACE_DEF( ttsvg ) /* OpenType SVG table (ttsvg.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) */ @@ -76,6 +89,7 @@ FT_TRACE_DEF( t1objs ) FT_TRACE_DEF( t1parse ) /* PostScript helper module `psaux' */ +FT_TRACE_DEF( afmparse ) FT_TRACE_DEF( cffdecode ) FT_TRACE_DEF( psconv ) FT_TRACE_DEF( psobjs ) @@ -145,13 +159,16 @@ FT_TRACE_DEF( gxvprop ) FT_TRACE_DEF( gxvtrak ) /* autofit components */ +FT_TRACE_DEF( afadjust ) FT_TRACE_DEF( afcjk ) FT_TRACE_DEF( afglobal ) FT_TRACE_DEF( afhints ) FT_TRACE_DEF( afmodule ) FT_TRACE_DEF( aflatin ) -FT_TRACE_DEF( aflatin2 ) FT_TRACE_DEF( afshaper ) -FT_TRACE_DEF( afwarp ) + + /* SDF components */ +FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */ +FT_TRACE_DEF( bsdf ) /* signed distance raster for bitmaps (ftbsdf.c) */ /* END */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/ftvalid.h b/src/thirdparty/freetype2/include/freetype/internal/ftvalid.h index 38aa06cc4..03a726c82 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/ftvalid.h +++ b/src/thirdparty/freetype2/include/freetype/internal/ftvalid.h @@ -4,7 +4,7 @@ * * FreeType validation support (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,9 @@ #define FTVALID_H_ #include -#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_setjmp and ft_longjmp */ +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_jmpbuf */ +#include "compiler-macros.h" FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/internal.h b/src/thirdparty/freetype2/include/freetype/internal/internal.h deleted file mode 100644 index 3c8830f7e..000000000 --- a/src/thirdparty/freetype2/include/freetype/internal/internal.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * - * internal.h - * - * Internal header files (specification only). - * - * Copyright (C) 1996-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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 -#define FT_INTERNAL_STREAM_H -#define FT_INTERNAL_MEMORY_H -#define FT_INTERNAL_DEBUG_H -#define FT_INTERNAL_CALC_H -#define FT_INTERNAL_HASH_H -#define FT_INTERNAL_DRIVER_H -#define FT_INTERNAL_TRACE_H -#define FT_INTERNAL_GLYPH_LOADER_H -#define FT_INTERNAL_SFNT_H -#define FT_INTERNAL_SERVICE_H -#define FT_INTERNAL_RFORK_H -#define FT_INTERNAL_VALIDATE_H - -#define FT_INTERNAL_TRUETYPE_TYPES_H -#define FT_INTERNAL_TYPE1_TYPES_H -#define FT_INTERNAL_WOFF_TYPES_H - -#define FT_INTERNAL_POSTSCRIPT_AUX_H -#define FT_INTERNAL_POSTSCRIPT_HINTS_H -#define FT_INTERNAL_POSTSCRIPT_PROPS_H - -#define FT_INTERNAL_AUTOHINT_H - -#define FT_INTERNAL_CFF_TYPES_H -#define FT_INTERNAL_CFF_OBJECTS_TYPES_H - - -#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. */ - /* In particular, the warning complains about stuff like `while(0)' */ - /* which is very useful in macro definitions. There is no benefit */ - /* in having it enabled. */ -#pragma warning( disable : 4127 ) - -#endif /* _MSC_VER */ - - -/* END */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/psaux.h b/src/thirdparty/freetype2/include/freetype/internal/psaux.h index f962a973d..344be0f19 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/psaux.h +++ b/src/thirdparty/freetype2/include/freetype/internal/psaux.h @@ -5,7 +5,7 @@ * Auxiliary functions and data structures related to PostScript fonts * (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,14 +21,13 @@ #define PSAUX_H_ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_HASH_H -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H -#include FT_INTERNAL_CFF_TYPES_H -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H +#include +#include +#include +#include +#include +#include +#include @@ -133,9 +132,6 @@ FT_BEGIN_HEADER * 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. * @@ -156,7 +152,6 @@ FT_BEGIN_HEADER FT_ULong init; FT_Int max_elems; - FT_Int num_elems; FT_Byte** elements; /* addresses of table elements */ FT_UInt* lengths; /* lengths of table elements */ @@ -230,6 +225,7 @@ FT_BEGIN_HEADER typedef enum T1_FieldLocation_ { + T1_FIELD_LOCATION_NONE = 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_LOCATION_FONT_DICT, T1_FIELD_LOCATION_FONT_EXTRA, @@ -254,6 +250,7 @@ FT_BEGIN_HEADER /* structure type used to model object fields */ typedef struct T1_FieldRec_ { + FT_UInt len; /* field identifier length */ const char* ident; /* field identifier */ T1_FieldLocation location; T1_FieldType type; /* type of field */ @@ -278,8 +275,9 @@ FT_BEGIN_HEADER #define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE( _fname ), \ 0, 0, \ @@ -288,6 +286,7 @@ FT_BEGIN_HEADER #define T1_NEW_CALLBACK_FIELD( _ident, _reader, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, T1_FIELD_TYPE_CALLBACK, \ (T1_Field_ParseFunc)_reader, \ 0, 0, \ @@ -297,8 +296,9 @@ FT_BEGIN_HEADER #define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _max, \ @@ -308,8 +308,9 @@ FT_BEGIN_HEADER #define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max, _dict ) \ { \ + sizeof ( _ident ) - 1, \ _ident, T1CODE, _type, \ - 0, \ + NULL, \ FT_FIELD_OFFSET( _fname ), \ FT_FIELD_SIZE_DELTA( _fname ), \ _max, 0, \ @@ -359,6 +360,13 @@ FT_BEGIN_HEADER #define T1_FIELD_CALLBACK( _ident, _name, _dict ) \ T1_NEW_CALLBACK_FIELD( _ident, _name, _dict ) +#define T1_FIELD_ZERO \ + { \ + 0, \ + NULL, T1_FIELD_LOCATION_NONE, T1_FIELD_TYPE_NONE, \ + NULL, 0, 0, 0, 0, 0 \ + } + /*************************************************************************/ /*************************************************************************/ diff --git a/src/thirdparty/freetype2/include/freetype/internal/pshints.h b/src/thirdparty/freetype2/include/freetype/internal/pshints.h index 699acea6f..96c5d84f0 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/pshints.h +++ b/src/thirdparty/freetype2/include/freetype/internal/pshints.h @@ -6,7 +6,7 @@ * recorders (specification only). These are used to support native * T1/T2 hints in the 'type1', 'cid', and 'cff' font drivers. * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,9 +22,8 @@ #define PSHINTS_H_ -#include -#include FT_FREETYPE_H -#include FT_TYPE1_TABLES_H +#include +#include FT_BEGIN_HEADER @@ -295,7 +294,7 @@ FT_BEGIN_HEADER * * @note: * On input, all points within the outline are in font coordinates. On - * output, they are in 1/64th of pixels. + * output, they are in 1/64 of pixels. * * The scaling transformation is taken from the 'globals' object which * must correspond to the same font as the glyph. @@ -608,7 +607,7 @@ FT_BEGIN_HEADER * * @note: * On input, all points within the outline are in font coordinates. On - * output, they are in 1/64th of pixels. + * output, they are in 1/64 of pixels. * * The scaling transformation is taken from the 'globals' object which * must correspond to the same font than the glyph. diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svbdf.h b/src/thirdparty/freetype2/include/freetype/internal/services/svbdf.h index e4786ed03..5bd51da23 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svbdf.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svbdf.h @@ -4,7 +4,7 @@ * * The FreeType BDF services (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVBDF_H_ #define SVBDF_H_ -#include FT_BDF_H -#include FT_INTERNAL_SERVICE_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svcfftl.h b/src/thirdparty/freetype2/include/freetype/internal/services/svcfftl.h index 6c621732d..c97bf84fb 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svcfftl.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svcfftl.h @@ -4,7 +4,7 @@ * * The FreeType CFF tables loader service (specification). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVCFFTL_H_ #define SVCFFTL_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_INTERNAL_CFF_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svcid.h b/src/thirdparty/freetype2/include/freetype/internal/services/svcid.h index 555a5af5b..748a8caf8 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svcid.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svcid.h @@ -4,7 +4,7 @@ * * The FreeType CID font services (specification). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVCID_H_ #define SVCID_H_ -#include FT_INTERNAL_SERVICE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svfntfmt.h b/src/thirdparty/freetype2/include/freetype/internal/services/svfntfmt.h index 6f4285ea8..690fdc2a2 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svfntfmt.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svfntfmt.h @@ -4,7 +4,7 @@ * * The FreeType font format service (specification only). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVFNTFMT_H_ #define SVFNTFMT_H_ -#include FT_INTERNAL_SERVICE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svgldict.h b/src/thirdparty/freetype2/include/freetype/internal/services/svgldict.h index 094962183..7128d6f3d 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svgldict.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svgldict.h @@ -4,7 +4,7 @@ * * The FreeType glyph dictionary services (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVGLDICT_H_ #define SVGLDICT_H_ -#include FT_INTERNAL_SERVICE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svgxval.h b/src/thirdparty/freetype2/include/freetype/internal/services/svgxval.h index 0bb76f314..1ca3e0a03 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svgxval.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svgxval.h @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -28,8 +28,8 @@ #ifndef SVGXVAL_H_ #define SVGXVAL_H_ -#include FT_GX_VALIDATE_H -#include FT_INTERNAL_VALIDATE_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svkern.h b/src/thirdparty/freetype2/include/freetype/internal/services/svkern.h index f992a327c..8a3d59bec 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svkern.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svkern.h @@ -4,7 +4,7 @@ * * The FreeType Kerning service (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVKERN_H_ #define SVKERN_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_TRUETYPE_TABLES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svmetric.h b/src/thirdparty/freetype2/include/freetype/internal/services/svmetric.h index d688bc7c6..4dde3a815 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svmetric.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svmetric.h @@ -4,7 +4,7 @@ * * The FreeType services for metrics variations (specification). * - * Copyright (C) 2016-2019 by + * Copyright (C) 2016-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVMETRIC_H_ #define SVMETRIC_H_ -#include FT_INTERNAL_SERVICE_H +#include FT_BEGIN_HEADER @@ -77,6 +77,9 @@ FT_BEGIN_HEADER typedef void (*FT_Metrics_Adjust_Func)( FT_Face face ); + typedef void + (*FT_Size_Reset_Func)( FT_Size size ); + FT_DEFINE_SERVICE( MetricsVariations ) { @@ -90,6 +93,7 @@ FT_BEGIN_HEADER FT_VOrg_Adjust_Func vorg_adjust; FT_Metrics_Adjust_Func metrics_adjust; + FT_Size_Reset_Func size_reset; }; @@ -101,7 +105,8 @@ FT_BEGIN_HEADER tsb_adjust_, \ bsb_adjust_, \ vorg_adjust_, \ - metrics_adjust_ ) \ + metrics_adjust_, \ + size_reset_ ) \ static const FT_Service_MetricsVariationsRec class_ = \ { \ hadvance_adjust_, \ @@ -111,7 +116,8 @@ FT_BEGIN_HEADER tsb_adjust_, \ bsb_adjust_, \ vorg_adjust_, \ - metrics_adjust_ \ + metrics_adjust_, \ + size_reset_ \ }; /* */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svmm.h b/src/thirdparty/freetype2/include/freetype/internal/services/svmm.h index 3652f2050..9be133e2d 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svmm.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svmm.h @@ -4,8 +4,8 @@ * * The FreeType Multiple Masters and GX var services (specification). * - * Copyright (C) 2003-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright (C) 2003-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, * modified, and distributed under the terms of the FreeType project @@ -19,7 +19,9 @@ #ifndef SVMM_H_ #define SVMM_H_ -#include FT_INTERNAL_SERVICE_H +#include +#include +#include FT_BEGIN_HEADER @@ -58,9 +60,9 @@ FT_BEGIN_HEADER /* use return value -1 to indicate that the new coordinates */ /* are equal to the current ones; no changes are thus needed */ typedef FT_Error - (*FT_Set_MM_Blend_Func)( FT_Face face, - FT_UInt num_coords, - FT_Long* coords ); + (*FT_Set_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); typedef FT_Error (*FT_Get_Var_Design_Func)( FT_Face face, @@ -68,13 +70,17 @@ FT_BEGIN_HEADER FT_Fixed* coords ); typedef FT_Error - (*FT_Set_Instance_Func)( FT_Face face, - FT_UInt instance_index ); + (*FT_Set_Named_Instance_Func)( FT_Face face, + FT_UInt instance_index ); typedef FT_Error - (*FT_Get_MM_Blend_Func)( FT_Face face, - FT_UInt num_coords, - FT_Long* coords ); + (*FT_Get_Default_Named_Instance_Func)( FT_Face face, + FT_UInt *instance_index ); + + typedef FT_Error + (*FT_Get_MM_Blend_Func)( FT_Face face, + FT_UInt num_coords, + FT_Fixed* coords ); typedef FT_Error (*FT_Get_Var_Blend_Func)( FT_Face face, @@ -84,7 +90,7 @@ FT_BEGIN_HEADER FT_MM_Var* *mm_var ); typedef void - (*FT_Done_Blend_Func)( FT_Face ); + (*FT_Done_Blend_Func)( FT_Face face ); typedef FT_Error (*FT_Set_MM_WeightVector_Func)( FT_Face face, @@ -96,53 +102,105 @@ FT_BEGIN_HEADER FT_UInt* len, FT_Fixed* weight_vector ); + typedef void + (*FT_Construct_PS_Name_Func)( FT_Face face ); + + typedef FT_Error + (*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + typedef FT_Error + (*FT_Var_Load_Item_Var_Store_Func)( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + typedef FT_ItemVarDelta + (*FT_Var_Get_Item_Delta_Func)( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + typedef void + (*FT_Var_Done_Item_Var_Store_Func)( FT_Face face, + GX_ItemVarStore itemStore ); + + typedef void + (*FT_Var_Done_Delta_Set_Idx_Map_Func)( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + 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_Blend_Func get_mm_blend; - FT_Get_MM_Var_Func get_mm_var; - FT_Set_Var_Design_Func set_var_design; - FT_Get_Var_Design_Func get_var_design; - FT_Set_Instance_Func set_instance; - FT_Set_MM_WeightVector_Func set_mm_weightvector; - FT_Get_MM_WeightVector_Func get_mm_weightvector; + 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_Blend_Func get_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + FT_Get_Var_Design_Func get_var_design; + FT_Set_Named_Instance_Func set_named_instance; + FT_Get_Default_Named_Instance_Func get_default_named_instance; + FT_Set_MM_WeightVector_Func set_mm_weightvector; + FT_Get_MM_WeightVector_Func get_mm_weightvector; /* for internal use; only needed for code sharing between modules */ - FT_Get_Var_Blend_Func get_var_blend; - FT_Done_Blend_Func done_blend; + FT_Construct_PS_Name_Func construct_ps_name; + FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map; + FT_Var_Load_Item_Var_Store_Func load_item_var_store; + FT_Var_Get_Item_Delta_Func get_item_delta; + FT_Var_Done_Item_Var_Store_Func done_item_var_store; + FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_idx_map; + FT_Get_Var_Blend_Func get_var_blend; + FT_Done_Blend_Func done_blend; }; -#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ - get_mm_, \ - set_mm_design_, \ - set_mm_blend_, \ - get_mm_blend_, \ - get_mm_var_, \ - set_var_design_, \ - get_var_design_, \ - set_instance_, \ - set_weightvector_, \ - get_weightvector_, \ - get_var_blend_, \ - done_blend_ ) \ - static const FT_Service_MultiMastersRec class_ = \ - { \ - get_mm_, \ - set_mm_design_, \ - set_mm_blend_, \ - get_mm_blend_, \ - get_mm_var_, \ - set_var_design_, \ - get_var_design_, \ - set_instance_, \ - set_weightvector_, \ - get_weightvector_, \ - get_var_blend_, \ - done_blend_ \ +#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ ) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_named_instance_, \ + get_default_named_instance_, \ + set_mm_weightvector_, \ + get_mm_weightvector_, \ + \ + construct_ps_name_, \ + load_delta_set_idx_map_, \ + load_item_var_store_, \ + get_item_delta_, \ + done_item_var_store_, \ + done_delta_set_idx_map_, \ + get_var_blend_, \ + done_blend_ \ }; /* */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svotval.h b/src/thirdparty/freetype2/include/freetype/internal/services/svotval.h index cab4c6efb..933e5de98 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svotval.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svotval.h @@ -4,7 +4,7 @@ * * The FreeType OpenType validation service (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVOTVAL_H_ #define SVOTVAL_H_ -#include FT_OPENTYPE_VALIDATE_H -#include FT_INTERNAL_VALIDATE_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svpfr.h b/src/thirdparty/freetype2/include/freetype/internal/services/svpfr.h index fd01d614d..c81b6a68a 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svpfr.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svpfr.h @@ -4,7 +4,7 @@ * * Internal PFR service functions (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVPFR_H_ #define SVPFR_H_ -#include FT_PFR_H -#include FT_INTERNAL_SERVICE_H +#include +#include FT_BEGIN_HEADER @@ -56,7 +56,6 @@ FT_BEGIN_HEADER }; - /* */ FT_END_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svpostnm.h b/src/thirdparty/freetype2/include/freetype/internal/services/svpostnm.h index 18e3843cb..33864ebc3 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svpostnm.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svpostnm.h @@ -4,7 +4,7 @@ * * The FreeType PostScript name services (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVPOSTNM_H_ #define SVPOSTNM_H_ -#include FT_INTERNAL_SERVICE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svprop.h b/src/thirdparty/freetype2/include/freetype/internal/services/svprop.h index e48d0151e..0eb79c885 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svprop.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svprop.h @@ -4,7 +4,7 @@ * * The FreeType property service (specification). * - * Copyright (C) 2012-2019 by + * Copyright (C) 2012-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svpscmap.h b/src/thirdparty/freetype2/include/freetype/internal/services/svpscmap.h index dfac3bafa..8f85d1215 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svpscmap.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svpscmap.h @@ -4,7 +4,7 @@ * * The FreeType PostScript charmap service (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef SVPSCMAP_H_ #define SVPSCMAP_H_ -#include FT_INTERNAL_OBJECTS_H +#include FT_BEGIN_HEADER @@ -97,7 +97,7 @@ FT_BEGIN_HEADER (*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes, FT_UInt32 unicode ); - typedef FT_UInt32 + typedef FT_UInt (*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes, FT_UInt32 *unicode ); diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svpsinfo.h b/src/thirdparty/freetype2/include/freetype/internal/services/svpsinfo.h index fb4e0e3fa..83de04478 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svpsinfo.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svpsinfo.h @@ -4,7 +4,7 @@ * * The FreeType PostScript info service (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVPSINFO_H_ #define SVPSINFO_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svsfnt.h b/src/thirdparty/freetype2/include/freetype/internal/services/svsfnt.h index 464aa209f..9bf5e3473 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svsfnt.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svsfnt.h @@ -4,7 +4,7 @@ * * The FreeType SFNT table loading service (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVSFNT_H_ #define SVSFNT_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_TRUETYPE_TABLES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svttcmap.h b/src/thirdparty/freetype2/include/freetype/internal/services/svttcmap.h index 0fcb81371..fc9b0aeb8 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svttcmap.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svttcmap.h @@ -4,7 +4,7 @@ * * The FreeType TrueType/sfnt cmap extra information service. * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * Masatake YAMATO, Redhat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -22,8 +22,8 @@ #ifndef SVTTCMAP_H_ #define SVTTCMAP_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_TRUETYPE_TABLES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svtteng.h b/src/thirdparty/freetype2/include/freetype/internal/services/svtteng.h index a852f5c6f..979e9ea10 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svtteng.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svtteng.h @@ -4,7 +4,7 @@ * * The FreeType TrueType engine query service (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVTTENG_H_ #define SVTTENG_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_MODULE_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svttglyf.h b/src/thirdparty/freetype2/include/freetype/internal/services/svttglyf.h index c8798771f..e4f54c100 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svttglyf.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svttglyf.h @@ -4,7 +4,7 @@ * * The FreeType TrueType glyph service. * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, @@ -18,8 +18,8 @@ #ifndef SVTTGLYF_H_ #define SVTTGLYF_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_TRUETYPE_TABLES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/services/svwinfnt.h b/src/thirdparty/freetype2/include/freetype/internal/services/svwinfnt.h index 38ee02096..ff887ffdc 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/services/svwinfnt.h +++ b/src/thirdparty/freetype2/include/freetype/internal/services/svwinfnt.h @@ -4,7 +4,7 @@ * * The FreeType Windows FNT/FONT service (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,8 @@ #ifndef SVWINFNT_H_ #define SVWINFNT_H_ -#include FT_INTERNAL_SERVICE_H -#include FT_WINFONTS_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/include/freetype/internal/sfnt.h b/src/thirdparty/freetype2/include/freetype/internal/sfnt.h index b19241c30..adba21788 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/sfnt.h +++ b/src/thirdparty/freetype2/include/freetype/internal/sfnt.h @@ -4,7 +4,7 @@ * * High-level 'sfnt' driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define SFNT_H_ -#include -#include FT_INTERNAL_DRIVER_H -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_INTERNAL_WOFF_TYPES_H +#include +#include +#include FT_BEGIN_HEADER @@ -312,6 +311,33 @@ FT_BEGIN_HEADER TT_SBit_MetricsRec *ametrics ); + /************************************************************************** + * + * @functype: + * TT_Load_Svg_Doc_Func + * + * @description: + * Scan the SVG document list to find the document containing the glyph + * that has the ID 'glyph*XXX*', where *XXX* is the value of + * `glyph_index` as a decimal integer. + * + * @inout: + * glyph :: + * The glyph slot from which pointers to the SVG document list is to be + * grabbed. The results are stored back in the slot. + * + * @input: + * glyph_index :: + * The index of the glyph that is to be looked up. + * + * @return: + * FreeType error code. 0 means success. + */ + typedef FT_Error + (*TT_Load_Svg_Doc_Func)( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + + /************************************************************************** * * @functype: @@ -525,6 +551,170 @@ FT_BEGIN_HEADER FT_LayerIterator* iterator ); + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_Paint_Func + * + * @description: + * Find the root @FT_OpaquePaint object for a given glyph ID. + * + * @input: + * face :: + * The target face object. + * + * base_glyph :: + * The glyph index the colored glyph layers are associated with. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object. + * + * @return: + * Value~1 if everything is OK. If no color glyph is found, or the root + * paint could not be retrieved, value~0 gets returned. In case of an + * error, value~0 is returned also. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_Paint_Func )( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Color_Glyph_ClipBox_Func + * + * @description: + * Search for a 'COLR' v1 clip box for the specified `base_glyph` and + * fill the `clip_box` parameter with the 'COLR' v1 'ClipBox' information + * if one is found. + * + * @input: + * face :: + * A handle to the parent face object. + * + * base_glyph :: + * The glyph index for which to retrieve the clip box. + * + * @output: + * clip_box :: + * The clip box for the requested `base_glyph` if one is found. The + * clip box is computed taking scale and transformations configured on + * the @FT_Face into account. @FT_ClipBox contains @FT_Vector values + * in 26.6 format. + * + * @note: + * To retrieve the clip box in font units, reset scale to units-per-em + * and remove transforms configured using @FT_Set_Transform. + * + * @return: + * Value~1 if a ClipBox is found. If no clip box is found or an + * error occurred, value~0 is returned. + */ + typedef FT_Bool + ( *TT_Get_Color_Glyph_ClipBox_Func )( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Layers_Func + * + * @description: + * Access the layers of a `PaintColrLayers` table. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * The @FT_LayerIterator from an @FT_PaintColrLayers object, for which + * the layers are to be retrieved. The internal state of the iterator + * is incremented after one call to this function for retrieving one + * layer. + * + * @output: + * paint :: + * The root @FT_OpaquePaint object referencing the actual paint table. + * + * @return: + * Value~1 if everything is OK. Value~0 gets returned when the paint + * object can not be retrieved or any other error occurs. + */ + typedef FT_Bool + ( *TT_Get_Paint_Layers_Func )( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint *paint ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Colorline_Stops_Func + * + * @description: + * Get the gradient and solid fill information for a given glyph. + * + * @input: + * face :: + * The target face object. + * + * @inout: + * iterator :: + * An @FT_ColorStopIterator object. For the first call you should set + * `iterator->p` to `NULL`. For all following calls, simply use the + * same object again. + * + * @output: + * color_stop :: + * Color index and alpha value for the retrieved color stop. + * + * @return: + * Value~1 if everything is OK. If there are no more color stops, + * value~0 gets returned. In case of an error, value~0 is returned + * also. + */ + typedef FT_Bool + ( *TT_Get_Colorline_Stops_Func )( TT_Face face, + FT_ColorStop *color_stop, + FT_ColorStopIterator* iterator ); + + + /************************************************************************** + * + * @functype: + * TT_Get_Paint_Func + * + * @description: + * Get the paint details for a given @FT_OpaquePaint object. + * + * @input: + * face :: + * The target face object. + * + * opaque_paint :: + * The @FT_OpaquePaint object. + * + * @output: + * paint :: + * An @FT_COLR_Paint object holding the details on `opaque_paint`. + * + * @return: + * Value~1 if everything is OK. Value~0 if no details can be found for + * this paint or any other error occurred. + */ + typedef FT_Bool + ( *TT_Get_Paint_Func )( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint *paint ); + + /************************************************************************** * * @functype: @@ -618,7 +808,7 @@ FT_BEGIN_HEADER * corresponding (1,0) Apple entry. * * @return: - * 1 if there is either a win or apple entry (or both), 0 otheriwse. + * 1 if there is either a win or apple entry (or both), 0 otherwise. */ typedef FT_Bool (*TT_Get_Name_ID_Func)( TT_Face face, @@ -710,73 +900,86 @@ FT_BEGIN_HEADER */ typedef struct SFNT_Interface_ { - TT_Loader_GotoTableFunc goto_table; + 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_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; + TT_Load_Any_Func load_any; /* 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_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; + TT_Load_Table_Func load_name; + TT_Free_Table_Func free_name; /* this field was called `load_kerning' up to version 2.1.10 */ - TT_Load_Table_Func load_kern; + TT_Load_Table_Func load_kern; - TT_Load_Table_Func load_gasp; - TT_Load_Table_Func load_pclt; + TT_Load_Table_Func load_gpos; + 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; + TT_Load_Table_Func load_bhed; - TT_Load_SBit_Image_Func load_sbit_image; + TT_Load_SBit_Image_Func load_sbit_image; /* see `ttpost.h' */ - TT_Get_PS_Name_Func get_psname; - TT_Free_Table_Func free_psnames; + TT_Get_PS_Name_Func get_psname; + TT_Free_Table_Func free_psnames; /* 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; + TT_Face_GetKerningFunc get_kerning; /* new elements introduced after version 2.1.10 */ + TT_Face_GetKerningFunc get_gpos_kerning; + /* 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_font_dir; + TT_Load_Metrics_Func load_hmtx; - TT_Load_Table_Func load_eblc; - TT_Free_Table_Func free_eblc; + 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_Load_Table_Func load_cpal; - TT_Load_Table_Func load_colr; - TT_Free_Table_Func free_cpal; - TT_Free_Table_Func free_colr; - TT_Set_Palette_Func set_palette; - TT_Get_Colr_Layer_Func get_colr_layer; - TT_Blend_Colr_Func colr_blend; + TT_Load_Table_Func load_cpal; + TT_Load_Table_Func load_colr; + TT_Free_Table_Func free_cpal; + TT_Free_Table_Func free_colr; + TT_Set_Palette_Func set_palette; + TT_Get_Colr_Layer_Func get_colr_layer; + TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint; + TT_Get_Color_Glyph_ClipBox_Func get_color_glyph_clipbox; + TT_Get_Paint_Layers_Func get_paint_layers; + TT_Get_Colorline_Stops_Func get_colorline_stops; + TT_Get_Paint_Func get_paint; + TT_Blend_Colr_Func colr_blend; - TT_Get_Metrics_Func get_metrics; + TT_Get_Metrics_Func get_metrics; - TT_Get_Name_Func get_name; - TT_Get_Name_ID_Func get_name_id; + TT_Get_Name_Func get_name; + TT_Get_Name_ID_Func get_name_id; + + /* OpenType SVG Support */ + TT_Load_Table_Func load_svg; + TT_Free_Table_Func free_svg; + TT_Load_Svg_Doc_Func load_svg_doc; } SFNT_Interface; @@ -802,6 +1005,7 @@ FT_BEGIN_HEADER load_name_, \ free_name_, \ load_kern_, \ + load_gpos_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ @@ -809,6 +1013,7 @@ FT_BEGIN_HEADER get_psname_, \ free_psnames_, \ get_kerning_, \ + get_gpos_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ @@ -821,10 +1026,18 @@ FT_BEGIN_HEADER free_colr_, \ set_palette_, \ get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ colr_blend_, \ get_metrics_, \ get_name_, \ - get_name_id_ ) \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ ) \ static const SFNT_Interface class_ = \ { \ goto_table_, \ @@ -842,6 +1055,7 @@ FT_BEGIN_HEADER load_name_, \ free_name_, \ load_kern_, \ + load_gpos_, \ load_gasp_, \ load_pclt_, \ load_bhed_, \ @@ -849,6 +1063,7 @@ FT_BEGIN_HEADER get_psname_, \ free_psnames_, \ get_kerning_, \ + get_gpos_kerning_, \ load_font_dir_, \ load_hmtx_, \ load_eblc_, \ @@ -861,10 +1076,18 @@ FT_BEGIN_HEADER free_colr_, \ set_palette_, \ get_colr_layer_, \ + get_colr_glyph_paint_, \ + get_color_glyph_clipbox, \ + get_paint_layers_, \ + get_colorline_stops_, \ + get_paint_, \ colr_blend_, \ get_metrics_, \ get_name_, \ - get_name_id_ \ + get_name_id_, \ + load_svg_, \ + free_svg_, \ + load_svg_doc_ \ }; diff --git a/src/thirdparty/freetype2/include/freetype/internal/svginterface.h b/src/thirdparty/freetype2/include/freetype/internal/svginterface.h new file mode 100644 index 000000000..20c73b2fb --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/internal/svginterface.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * svginterface.h + * + * Interface of ot-svg module (specification only). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 SVGINTERFACE_H_ +#define SVGINTERFACE_H_ + +#include +#include + + +FT_BEGIN_HEADER + + typedef FT_Error + (*Preset_Bitmap_Func)( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ); + + typedef struct SVG_Interface_ + { + Preset_Bitmap_Func preset_slot; + + } SVG_Interface; + + typedef SVG_Interface* SVG_Service; + +FT_END_HEADER + +#endif /* SVGINTERFACE_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/include/freetype/internal/t1types.h b/src/thirdparty/freetype2/include/freetype/internal/t1types.h index d94c8c128..5b26e4620 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/t1types.h +++ b/src/thirdparty/freetype2/include/freetype/internal/t1types.h @@ -5,7 +5,7 @@ * Basic Type1/Type2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,12 +21,11 @@ #define T1TYPES_H_ -#include -#include FT_TYPE1_TABLES_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H -#include FT_INTERNAL_SERVICE_H -#include FT_INTERNAL_HASH_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include +#include +#include +#include +#include FT_BEGIN_HEADER @@ -138,6 +137,54 @@ FT_BEGIN_HEADER } CID_SubrsRec, *CID_Subrs; + /* 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; + + /* backward 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; + + + /* backward compatible definition */ + typedef PS_BlendRec T1_Blend; + + /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ @@ -173,8 +220,8 @@ FT_BEGIN_HEADER { FT_Bool IsCIDFont; FT_BBox FontBBox; - FT_Fixed Ascender; - FT_Fixed Descender; + FT_Fixed Ascender; /* optional, mind the zero */ + FT_Fixed Descender; /* optional, mind the zero */ AFM_TrackKern TrackKerns; /* free if non-NULL */ FT_UInt NumTrackKern; AFM_KernPair KernPairs; /* free if non-NULL */ @@ -202,30 +249,30 @@ FT_BEGIN_HEADER 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]; + FT_FaceRec root; + T1_FontRec type1; + const void* psnames; + const void* psaux; + const void* afm_data; + FT_CharMapRec charmaprecs[2]; + FT_CharMap charmaps[2]; /* support for Multiple Masters fonts */ - PS_Blend blend; + 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; + 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_Long* buildchar; + FT_UInt len_buildchar; + FT_Long* buildchar; /* since version 2.1 - interface to PostScript hinter */ - const void* pshinter; + const void* pshinter; } T1_FaceRec; diff --git a/src/thirdparty/freetype2/include/freetype/internal/tttypes.h b/src/thirdparty/freetype2/include/freetype/internal/tttypes.h index 23db240e7..d0e5eee89 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/tttypes.h +++ b/src/thirdparty/freetype2/include/freetype/internal/tttypes.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType type definitions and interface (specification * only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,13 +21,13 @@ #define TTTYPES_H_ -#include -#include FT_TRUETYPE_TABLES_H -#include FT_INTERNAL_OBJECTS_H -#include FT_COLOR_H +#include +#include +#include +#include "freetype/fttypes.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H +#include #endif @@ -780,13 +780,15 @@ FT_BEGIN_HEADER /************************************************************************** * * @struct: - * TT_Post_20Rec + * TT_Post_NamesRec * * @description: - * Postscript names sub-table, format 2.0. Stores the PS name of each - * glyph in the font face. + * Postscript names table, either format 2.0 or 2.5. * * @fields: + * loaded :: + * A flag to indicate whether the PS names are loaded. + * * num_glyphs :: * The number of named glyphs in the table. * @@ -799,68 +801,13 @@ FT_BEGIN_HEADER * glyph_names :: * The PS names not in Mac Encoding. */ - typedef struct TT_Post_20Rec_ + typedef struct TT_Post_NamesRec_ { + FT_Bool loaded; 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; + FT_Byte** glyph_names; } TT_Post_NamesRec, *TT_Post_Names; @@ -983,8 +930,8 @@ FT_BEGIN_HEADER * 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). + * The TT_Face structure is also used for CFF support; see file + * `cffotypes.h`. */ typedef struct TT_FaceRec_* TT_Face; @@ -1254,12 +1201,16 @@ FT_BEGIN_HEADER * mm :: * A pointer to the Multiple Masters service. * - * var :: - * A pointer to the Metrics Variations service. + * tt_var :: + * A pointer to the Metrics Variations service for the "truetype" + * driver. * - * hdmx :: - * The face's horizontal device metrics ('hdmx' table). This table is - * optional in TrueType/OpenType fonts. + * face_var :: + * A pointer to the Metrics Variations service for this `TT_Face`'s + * driver. + * + * psaux :: + * A pointer to the PostScript Auxiliary service. * * gasp :: * The grid-fitting and scaling properties table ('gasp'). This table @@ -1325,10 +1276,6 @@ FT_BEGIN_HEADER * * If varied by the `CVAR' table, non-integer values are possible. * - * interpreter :: - * A pointer to the TrueType bytecode interpreters field is also used - * to hook the debugger in 'ttdebug'. - * * extra :: * Reserved for third-party font drivers. * @@ -1365,6 +1312,12 @@ FT_BEGIN_HEADER * var_postscript_prefix_len :: * The length of the `var_postscript_prefix` string. * + * var_default_named_instance :: + * The index of the default named instance. + * + * non_var_style_name :: + * The non-variation style name, used as a backup. + * * horz_metrics_size :: * The size of the 'hmtx' table. * @@ -1373,7 +1326,7 @@ FT_BEGIN_HEADER * * 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. + * one more than the number of glyphs. Ignored for Type 2 fonts. * * glyph_locations :: * An array of longs. These are offsets to glyph data within the @@ -1391,8 +1344,8 @@ FT_BEGIN_HEADER * hdmx_record_size :: * The size of a single hdmx record. * - * hdmx_record_sizes :: - * An array holding the ppem sizes available in the 'hdmx' table. + * hdmx_records :: + * A array of pointers to the 'hdmx' table records sorted by ppem. * * sbit_table :: * A pointer to the font's embedded bitmap location table. @@ -1411,14 +1364,6 @@ FT_BEGIN_HEADER * A mapping between the strike indices exposed by the API and the * indices used in the font's sbit table. * - * cpal :: - * A pointer to data related to the 'CPAL' table. `NULL` if the table - * is not available. - * - * colr :: - * A pointer to data related to the 'COLR' table. `NULL` if the table - * is not available. - * * kern_table :: * A pointer to the 'kern' table. * @@ -1446,19 +1391,23 @@ FT_BEGIN_HEADER * vert_metrics_offset :: * The file offset of the 'vmtx' table. * - * sph_found_func_flags :: - * Flags identifying special bytecode functions (used by the v38 - * implementation of the bytecode interpreter). - * - * sph_compatibility_mode :: - * This flag is set if we are in ClearType backward compatibility mode - * (used by the v38 implementation of the bytecode interpreter). - * * ebdt_start :: * The file offset of the sbit data table (CBDT, bdat, etc.). * * ebdt_size :: * The size of the sbit data table. + * + * cpal :: + * A pointer to data related to the 'CPAL' table. `NULL` if the table + * is not available. + * + * colr :: + * A pointer to data related to the 'COLR' table. `NULL` if the table + * is not available. + * + * svg :: + * A pointer to data related to the 'SVG' table. `NULL` if the table + * is not available. */ typedef struct TT_FaceRec_ { @@ -1509,8 +1458,14 @@ FT_BEGIN_HEADER void* mm; /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ - /* used to handle the HVAR, VVAR, and MVAR OpenType tables */ - void* var; + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the */ + /* "truetype" driver */ + void* tt_var; + + /* a typeless pointer to the FT_Service_MetricsVariationsRec table */ + /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */ + /* TT_Face's driver */ + void* face_var; /* since 2.13.1 */ #endif /* a typeless pointer to the PostScript Aux service */ @@ -1562,10 +1517,6 @@ FT_BEGIN_HEADER FT_ULong cvt_size; FT_Int32* cvt; - /* A pointer to the bytecode interpreter to use. This is also */ - /* used to hook the debugger for the `ttdebug' utility. */ - TT_Interpreter interpreter; - /************************************************************************ * @@ -1592,6 +1543,9 @@ FT_BEGIN_HEADER const char* var_postscript_prefix; /* since 2.7.2 */ FT_UInt var_postscript_prefix_len; /* since 2.7.2 */ + FT_UInt var_default_named_instance; /* since 2.13.1 */ + + const char* non_var_style_name; /* since 2.13.1 */ #endif /* since version 2.2 */ @@ -1599,14 +1553,14 @@ FT_BEGIN_HEADER FT_ULong horz_metrics_size; FT_ULong vert_metrics_size; - FT_ULong num_locations; /* in broken TTF, gid > 0xFFFF */ + FT_ULong num_locations; /* up to 0xFFFF + 1 */ 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** hdmx_records; FT_Byte* sbit_table; FT_ULong sbit_table_size; @@ -1628,13 +1582,6 @@ FT_BEGIN_HEADER FT_ULong horz_metrics_offset; FT_ULong vert_metrics_offset; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* since 2.4.12 */ - FT_ULong sph_found_func_flags; /* special functions found */ - /* for this face */ - FT_Bool sph_compatibility_mode; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* since 2.7 */ FT_ULong ebdt_start; /* either `CBDT', `EBDT', or `bdat' */ @@ -1645,6 +1592,18 @@ FT_BEGIN_HEADER void* cpal; void* colr; + /* since 2.12 */ + void* svg; + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + /* since 2.13.3 */ + FT_Byte* gpos_table; + /* since 2.14 */ + /* This is actually an array of GPOS lookup subtables. */ + FT_UInt32* gpos_lookups_kerning; + FT_UInt num_gpos_lookups_kerning; +#endif + } TT_FaceRec; @@ -1658,15 +1617,6 @@ FT_BEGIN_HEADER * coordinates. * * @fields: - * memory :: - * A handle to the memory manager. - * - * max_points :: - * The maximum 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. * @@ -1690,11 +1640,8 @@ FT_BEGIN_HEADER */ typedef struct TT_GlyphZoneRec_ { - FT_Memory memory; - FT_UShort max_points; - FT_Short max_contours; FT_UShort n_points; /* number of points in zone */ - FT_Short n_contours; /* number of contours */ + FT_UShort n_contours; /* number of contours */ FT_Vector* org; /* original point coordinates */ FT_Vector* cur; /* current point coordinates */ @@ -1735,7 +1682,7 @@ FT_BEGIN_HEADER FT_UInt glyph_index; FT_Stream stream; - FT_Int byte_len; + FT_UInt byte_len; FT_Short n_contours; FT_BBox bbox; @@ -1751,7 +1698,6 @@ FT_BEGIN_HEADER TT_GlyphZoneRec zone; TT_ExecContext exec; - FT_Byte* instructions; FT_ULong ins_pos; /* for possible extensibility in other formats */ @@ -1770,6 +1716,9 @@ FT_BEGIN_HEADER /* since version 2.6.2 */ FT_ListRec composites; + /* since version 2.11.2 */ + FT_Byte* widthp; + } TT_LoaderRec; diff --git a/src/thirdparty/freetype2/include/freetype/internal/wofftypes.h b/src/thirdparty/freetype2/include/freetype/internal/wofftypes.h index ba55bf883..7d5b7df0f 100644 --- a/src/thirdparty/freetype2/include/freetype/internal/wofftypes.h +++ b/src/thirdparty/freetype2/include/freetype/internal/wofftypes.h @@ -5,7 +5,7 @@ * Basic WOFF/WOFF2 type definitions and interface (specification * only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,9 +21,8 @@ #define WOFFTYPES_H_ -#include -#include FT_TRUETYPE_TABLES_H -#include FT_INTERNAL_OBJECTS_H +#include +#include FT_BEGIN_HEADER @@ -93,7 +92,7 @@ FT_BEGIN_HEADER */ typedef struct WOFF_TableRec_ { - FT_ULong Tag; /* table ID */ + FT_Tag Tag; /* table ID */ FT_ULong Offset; /* table file offset */ FT_ULong CompLength; /* compressed table length */ FT_ULong OrigLength; /* uncompressed table length */ @@ -104,6 +103,207 @@ FT_BEGIN_HEADER } WOFF_TableRec, *WOFF_Table; + /************************************************************************** + * + * @struct: + * WOFF2_TtcFontRec + * + * @description: + * Metadata for a TTC font entry in WOFF2. + * + * @fields: + * flavor :: + * TTC font flavor. + * + * num_tables :: + * Number of tables in TTC, indicating number of elements in + * `table_indices`. + * + * table_indices :: + * Array of table indices for each TTC font. + */ + typedef struct WOFF2_TtcFontRec_ + { + FT_ULong flavor; + FT_UShort num_tables; + FT_UShort* table_indices; + + } WOFF2_TtcFontRec, *WOFF2_TtcFont; + + + /************************************************************************** + * + * @struct: + * WOFF2_HeaderRec + * + * @description: + * WOFF2 file format header. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#woff20Header + * + * @note: + * We don't care about the fields `reserved`, `majorVersion` and + * `minorVersion`, so they are not included. The `totalSfntSize` field + * does not necessarily represent the actual size of the uncompressed + * SFNT font stream, so that is used as a reference value instead. + */ + typedef struct WOFF2_HeaderRec_ + { + FT_ULong signature; + FT_ULong flavor; + FT_ULong length; + FT_UShort num_tables; + FT_ULong totalSfntSize; + FT_ULong totalCompressedSize; + FT_ULong metaOffset; + FT_ULong metaLength; + FT_ULong metaOrigLength; + FT_ULong privOffset; + FT_ULong privLength; + + FT_ULong uncompressed_size; /* uncompressed brotli stream size */ + FT_ULong compressed_offset; /* compressed stream offset */ + FT_ULong header_version; /* version of original TTC Header */ + FT_UShort num_fonts; /* number of fonts in TTC */ + FT_ULong actual_sfnt_size; /* actual size of sfnt stream */ + + WOFF2_TtcFont ttc_fonts; /* metadata for fonts in a TTC */ + + } WOFF2_HeaderRec, *WOFF2_Header; + + + /************************************************************************** + * + * @struct: + * WOFF2_TableRec + * + * @description: + * This structure describes a given table of a WOFF2 font. + * + * @fields: + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + */ + typedef struct WOFF2_TableRec_ + { + FT_Byte FlagByte; /* table type and flags */ + FT_Tag Tag; /* table file offset */ + FT_ULong dst_length; /* uncompressed table length */ + FT_ULong TransformLength; /* transformed length */ + + FT_ULong flags; /* calculated flags */ + FT_ULong src_offset; /* compressed table offset */ + FT_ULong src_length; /* compressed table length */ + FT_ULong dst_offset; /* uncompressed table offset */ + + } WOFF2_TableRec, *WOFF2_Table; + + + /************************************************************************** + * + * @struct: + * WOFF2_InfoRec + * + * @description: + * Metadata for WOFF2 font that may be required for reconstruction of + * sfnt tables. + * + * @fields: + * header_checksum :: + * Checksum of SFNT offset table. + * + * num_glyphs :: + * Number of glyphs in the font. + * + * num_hmetrics :: + * `numberOfHMetrics` field in the 'hhea' table. + * + * x_mins :: + * `xMin` values of glyph bounding box. + * + * glyf_table :: + * A pointer to the `glyf' table record. + * + * loca_table :: + * A pointer to the `loca' table record. + * + * head_table :: + * A pointer to the `head' table record. + */ + typedef struct WOFF2_InfoRec_ + { + FT_ULong header_checksum; + FT_UShort num_glyphs; + FT_UShort num_hmetrics; + FT_Short* x_mins; + + WOFF2_Table glyf_table; + WOFF2_Table loca_table; + WOFF2_Table head_table; + + } WOFF2_InfoRec, *WOFF2_Info; + + + /************************************************************************** + * + * @struct: + * WOFF2_SubstreamRec + * + * @description: + * This structure stores information about a substream in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * start :: + * Beginning of the substream relative to uncompressed table stream. + * + * offset :: + * Offset of the substream relative to uncompressed table stream. + * + * size :: + * Size of the substream. + */ + typedef struct WOFF2_SubstreamRec_ + { + FT_ULong start; + FT_ULong offset; + FT_ULong size; + + } WOFF2_SubstreamRec, *WOFF2_Substream; + + + /************************************************************************** + * + * @struct: + * WOFF2_PointRec + * + * @description: + * This structure stores information about a point in the transformed + * 'glyf' table in a WOFF2 stream. + * + * @fields: + * x :: + * x-coordinate of point. + * + * y :: + * y-coordinate of point. + * + * on_curve :: + * Set if point is on-curve. + */ + typedef struct WOFF2_PointRec_ + { + FT_Int x; + FT_Int y; + FT_Bool on_curve; + + } WOFF2_PointRec, *WOFF2_Point; + + FT_END_HEADER #endif /* WOFFTYPES_H_ */ diff --git a/src/thirdparty/freetype2/include/freetype/otsvg.h b/src/thirdparty/freetype2/include/freetype/otsvg.h new file mode 100644 index 000000000..326bbcd01 --- /dev/null +++ b/src/thirdparty/freetype2/include/freetype/otsvg.h @@ -0,0 +1,336 @@ +/**************************************************************************** + * + * otsvg.h + * + * Interface for OT-SVG support related things (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 OTSVG_H_ +#define OTSVG_H_ + +#include + +#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: + * svg_fonts + * + * @title: + * OpenType SVG Fonts + * + * @abstract: + * OT-SVG API between FreeType and an external SVG rendering library. + * + * @description: + * This section describes the four hooks necessary to render SVG + * 'documents' that are contained in an OpenType font's 'SVG~' table. + * + * For more information on the implementation, see our standard hooks + * based on 'librsvg' in the [FreeType Demo + * Programs](https://gitlab.freedesktop.org/freetype/freetype-demos) + * repository. + * + */ + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Init_Func + * + * @description: + * A callback that is called when the first OT-SVG glyph is rendered in + * the lifetime of an @FT_Library object. In a typical implementation, + * one would want to allocate a structure and point the `data_pointer` + * to it and perform any library initializations that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Init_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Free_Func + * + * @description: + * A callback that is called when the `ot-svg` module is being freed. + * It is only called if the init hook was called earlier. This means + * that neither the init nor the free hook is called if no OT-SVG glyph + * is rendered. + * + * In a typical implementation, one would want to free any state + * structure that was allocated in the init hook and perform any + * library-related closure that might be needed. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @since: + * 2.12 + */ + typedef void + (*SVG_Lib_Free_Func)( FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Render_Func + * + * @description: + * A callback that is called to render an OT-SVG glyph. This callback + * hook is called right after the preset hook @SVG_Lib_Preset_Slot_Func + * has been called with `cache` set to `TRUE`. The data necessary to + * render is available through the handle @FT_SVG_Document, which is set + * in the `other` field of @FT_GlyphSlotRec. + * + * The render hook is expected to render the SVG glyph to the bitmap + * buffer that is allocated already at `slot->bitmap.buffer`. It also + * sets the `num_grays` value as well as `slot->format`. + * + * @input: + * slot :: + * The slot to render. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Render_Func)( FT_GlyphSlot slot, + FT_Pointer *data_pointer ); + + + /************************************************************************** + * + * @functype: + * SVG_Lib_Preset_Slot_Func + * + * @description: + * A callback that is called to preset the glyph slot. It is called from + * two places. + * + * 1. When `FT_Load_Glyph` needs to preset the glyph slot. + * + * 2. Right before the `svg` module calls the render callback hook. + * + * When it is the former, the argument `cache` is set to `FALSE`. When + * it is the latter, the argument `cache` is set to `TRUE`. This + * distinction has been made because many calculations that are necessary + * for presetting a glyph slot are the same needed later for the render + * callback hook. Thus, if `cache` is `TRUE`, the hook can _cache_ those + * calculations in a memory block referenced by the state pointer. + * + * This hook is expected to preset the slot by setting parameters such as + * `bitmap_left`, `bitmap_top`, `width`, `rows`, `pitch`, and + * `pixel_mode`. It is also expected to set all the metrics for the slot + * including the vertical advance if it is not already set. Typically, + * fonts have horizontal advances but not vertical ones. If those are + * available, they had already been set, otherwise they have to be + * estimated and set manually. The hook must take into account the + * transformations that have been set, and translate the transformation + * matrices into the SVG coordinate system, as the original matrix is + * intended for the TTF/CFF coordinate system. + * + * @input: + * slot :: + * The glyph slot that has the SVG document loaded. + * + * cache :: + * See description. + * + * @inout: + * data_pointer :: + * The SVG rendering module stores a pointer variable that can be used + * by clients to store any data that needs to be shared across + * different hooks. `data_pointer` is essentially a pointer to that + * pointer such that it can be written to as well as read from. + * + * @return: + * FreeType error code. 0 means success. + * + * @since: + * 2.12 + */ + typedef FT_Error + (*SVG_Lib_Preset_Slot_Func)( FT_GlyphSlot slot, + FT_Bool cache, + FT_Pointer *state ); + + + /************************************************************************** + * + * @struct: + * SVG_RendererHooks + * + * @description: + * A structure that stores the four hooks needed to render OT-SVG glyphs + * properly. The structure is publicly used to set the hooks via the + * @svg-hooks driver property. + * + * The behavior of each hook is described in its documentation. One + * thing to note is that the preset hook and the render hook often need + * to do the same operations; therefore, it's better to cache the + * intermediate data in a state structure to avoid calculating it twice. + * For example, in the preset hook one can draw the glyph on a recorder + * surface and later create a bitmap surface from it in the render hook. + * + * All four hooks must be non-NULL. + * + * @fields: + * init_svg :: + * The initialization hook. + * + * free_svg :: + * The cleanup hook. + * + * render_hook :: + * The render hook. + * + * preset_slot :: + * The preset hook. + * + * @since: + * 2.12 + */ + typedef struct SVG_RendererHooks_ + { + SVG_Lib_Init_Func init_svg; + SVG_Lib_Free_Func free_svg; + SVG_Lib_Render_Func render_svg; + + SVG_Lib_Preset_Slot_Func preset_slot; + + } SVG_RendererHooks; + + + /************************************************************************** + * + * @struct: + * FT_SVG_DocumentRec + * + * @description: + * A structure that models one SVG document. + * + * @fields: + * svg_document :: + * A pointer to the SVG document. + * + * svg_document_length :: + * The length of `svg_document`. + * + * metrics :: + * A metrics object storing the size information. + * + * units_per_EM :: + * The size of the EM square. + * + * start_glyph_id :: + * The first glyph ID in the glyph range covered by this document. + * + * end_glyph_id :: + * The last glyph ID in the glyph range covered by this document. + * + * transform :: + * A 2x2 transformation matrix to apply to the glyph while rendering + * it. + * + * delta :: + * The translation to apply to the glyph while rendering. + * + * @note: + * When an @FT_GlyphSlot object `slot` is passed down to a renderer, the + * renderer can only access the `metrics` and `units_per_EM` fields via + * `slot->face`. However, when @FT_Glyph_To_Bitmap sets up a dummy + * object, it has no way to set a `face` object. Thus, metrics + * information and `units_per_EM` (which is necessary for OT-SVG) has to + * be stored separately. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_ + { + FT_Byte* svg_document; + FT_ULong svg_document_length; + + FT_Size_Metrics metrics; + FT_UShort units_per_EM; + + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_Matrix transform; + FT_Vector delta; + + } FT_SVG_DocumentRec; + + + /************************************************************************** + * + * @type: + * FT_SVG_Document + * + * @description: + * A handle to an @FT_SVG_DocumentRec object. + * + * @since: + * 2.12 + */ + typedef struct FT_SVG_DocumentRec_* FT_SVG_Document; + + +FT_END_HEADER + +#endif /* OTSVG_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/include/freetype/t1tables.h b/src/thirdparty/freetype2/include/freetype/t1tables.h index 645e64572..fc3c1706d 100644 --- a/src/thirdparty/freetype2/include/freetype/t1tables.h +++ b/src/thirdparty/freetype2/include/freetype/t1tables.h @@ -5,7 +5,7 @@ * Basic Type 1/Type 2 tables definitions and interface (specification * only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,7 @@ #define T1TABLES_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -270,64 +269,6 @@ FT_BEGIN_HEADER /* */ - /* 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; - - /* backward 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; - - - /* backward compatible definition */ - typedef PS_BlendRec T1_Blend; - - /************************************************************************** * * @struct: @@ -361,7 +302,7 @@ FT_BEGIN_HEADER FT_UInt num_subrs; FT_ULong subrmap_offset; - FT_Int sd_bytes; + FT_UInt sd_bytes; } CID_FaceDictRec; @@ -416,11 +357,11 @@ FT_BEGIN_HEADER FT_ULong xuid[16]; FT_ULong cidmap_offset; - FT_Int fd_bytes; - FT_Int gd_bytes; + FT_UInt fd_bytes; + FT_UInt gd_bytes; FT_ULong cid_count; - FT_Int num_dicts; + FT_UInt num_dicts; CID_FaceDict font_dicts; FT_ULong data_offset; @@ -454,22 +395,22 @@ FT_BEGIN_HEADER /************************************************************************** * * @function: - * FT_Has_PS_Glyph_Names + * 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. + * 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. + * 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 + * face :: + * face handle * * @return: - * Boolean. True if glyph names are reliable. + * Boolean. True if glyph names are reliable. * */ FT_EXPORT( FT_Int ) @@ -479,30 +420,40 @@ FT_BEGIN_HEADER /************************************************************************** * * @function: - * FT_Get_PS_Font_Info + * FT_Get_PS_Font_Info * * @description: - * Retrieve the @PS_FontInfoRec structure corresponding to a given - * PostScript font. + * Retrieve the @PS_FontInfoRec structure corresponding to a given + * PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * * @output: - * afont_info :: - * Output font info structure pointer. + * afont_info :: + * A pointer to a @PS_FontInfoRec object. * * @return: - * FreeType error code. 0~means success. + * FreeType error code. 0~means success. * * @note: - * String pointers within the @PS_FontInfoRec structure are owned by the - * face and don't need to be freed by the caller. Missing entries in - * the font's FontInfo dictionary are represented by `NULL` pointers. + * String pointers within the @PS_FontInfoRec structure are owned by the + * face and don't need to be freed by the caller. Missing entries in the + * font's FontInfo dictionary are represented by `NULL` pointers. * - * If the font's format is not PostScript-based, this function will - * return the `FT_Err_Invalid_Argument` error code. + * The following font formats support this feature: 'Type~1', 'Type~42', + * 'CFF', 'CID~Type~1'. For other font formats this function returns the + * `FT_Err_Invalid_Argument` error code. + * + * @example: + * ``` + * PS_FontInfoRec font_info; + * + * + * error = FT_Get_PS_Font_Info( face, &font_info ); + * ... + * ``` * */ FT_EXPORT( FT_Error ) @@ -513,29 +464,39 @@ FT_BEGIN_HEADER /************************************************************************** * * @function: - * FT_Get_PS_Font_Private + * FT_Get_PS_Font_Private * * @description: - * Retrieve the @PS_PrivateRec structure corresponding to a given - * PostScript font. + * Retrieve the @PS_PrivateRec structure corresponding to a given + * PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * * @output: - * afont_private :: - * Output private dictionary structure pointer. + * afont_private :: + * A pointer to a @PS_PrivateRec object. * * @return: - * FreeType error code. 0~means success. + * FreeType error code. 0~means success. * * @note: - * The string pointers within the @PS_PrivateRec structure are owned by - * the face and don't need to be freed by the caller. + * The string pointers within the @PS_PrivateRec 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 returns - * the `FT_Err_Invalid_Argument` error code. + * Only the 'Type~1' font format supports this feature. For other font + * formats this function returns the `FT_Err_Invalid_Argument` error + * code. + * + * @example: + * ``` + * PS_PrivateRec font_private; + * + * + * error = FT_Get_PS_Font_Private( face, &font_private ); + * ... + * ``` * */ FT_EXPORT( FT_Error ) @@ -694,67 +655,67 @@ FT_BEGIN_HEADER /************************************************************************** * * @function: - * FT_Get_PS_Font_Value + * FT_Get_PS_Font_Value * * @description: - * Retrieve the value for the supplied key from a PostScript font. + * Retrieve the value for the supplied key from a PostScript font. * * @input: - * face :: - * PostScript face handle. + * face :: + * PostScript face handle. * - * key :: - * An enumeration value representing the dictionary key to retrieve. + * key :: + * An enumeration value representing the dictionary key to retrieve. * - * idx :: - * For array values, this specifies the index to be returned. + * idx :: + * For array values, this specifies the index to be returned. * - * value :: - * A pointer to memory into which to write the value. + * value :: + * A pointer to memory into which to write the value. * - * valen_len :: - * The size, in bytes, of the memory supplied for the value. + * valen_len :: + * The size, in bytes, of the memory supplied for the value. * * @output: - * value :: - * The value matching the above key, if it exists. + * value :: + * The value matching the above key, if it exists. * * @return: - * The amount of memory (in bytes) required to hold the requested value - * (if it exists, -1 otherwise). + * The amount of memory (in bytes) required to hold the requested value + * (if it exists, -1 otherwise). * * @note: - * The values returned are not pointers into the internal structures of - * the face, but are 'fresh' copies, so that the memory containing them - * belongs to the calling application. This also enforces the - * 'read-only' nature of these values, i.e., this function cannot be - * used to manipulate the face. + * The values returned are not pointers into the internal structures of + * the face, but are 'fresh' copies, so that the memory containing them + * belongs to the calling application. This also enforces the + * 'read-only' nature of these values, i.e., this function cannot be + * used to manipulate the face. * - * `value` is a void pointer because the values returned can be of - * various types. + * `value` is a void pointer because the values returned can be of + * various types. * - * If either `value` is `NULL` or `value_len` is too small, just the - * required memory size for the requested entry is returned. + * If either `value` is `NULL` or `value_len` is too small, just the + * required memory size for the requested entry is returned. * - * The `idx` parameter is used, not only to retrieve elements of, for - * example, the FontMatrix or FontBBox, but also to retrieve name keys - * from the CharStrings dictionary, and the charstrings themselves. It - * is ignored for atomic values. + * The `idx` parameter is used, not only to retrieve elements of, for + * example, the FontMatrix or FontBBox, but also to retrieve name keys + * from the CharStrings dictionary, and the charstrings themselves. It + * is ignored for atomic values. * - * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To - * get the value as in the font stream, you need to divide by 65536000.0 - * (to remove the FT_Fixed scale, and the x1000 scale). + * `PS_DICT_BLUE_SCALE` returns a value that is scaled up by 1000. To + * get the value as in the font stream, you need to divide by 65536000.0 + * (to remove the FT_Fixed scale, and the x1000 scale). * - * IMPORTANT: Only key/value pairs read by the FreeType interpreter can - * be retrieved. So, for example, PostScript procedures such as NP, ND, - * and RD are not available. Arbitrary keys are, obviously, not be - * available either. + * IMPORTANT: Only key/value pairs read by the FreeType interpreter can + * be retrieved. So, for example, PostScript procedures such as NP, ND, + * and RD are not available. Arbitrary keys are, obviously, not be + * available either. * - * If the font's format is not PostScript-based, this function returns - * the `FT_Err_Invalid_Argument` error code. + * If the font's format is not PostScript-based, this function returns + * the `FT_Err_Invalid_Argument` error code. * * @since: - * 2.4.8 + * 2.4.8 * */ FT_EXPORT( FT_Long ) diff --git a/src/thirdparty/freetype2/include/freetype/ttnameid.h b/src/thirdparty/freetype2/include/freetype/ttnameid.h index cc677de75..3ef61091c 100644 --- a/src/thirdparty/freetype2/include/freetype/ttnameid.h +++ b/src/thirdparty/freetype2/include/freetype/ttnameid.h @@ -4,7 +4,7 @@ * * TrueType name ID definitions (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define TTNAMEID_H_ -#include FT_BEGIN_HEADER @@ -437,7 +436,7 @@ FT_BEGIN_HEADER * * The canonical source for Microsoft's IDs is * - * https://docs.microsoft.com/en-us/windows/desktop/Intl/language-identifier-constants-and-strings , + * https://learn.microsoft.com/windows/win32/intl/language-identifier-constants-and-strings , * * however, we only provide macros for language identifiers present in * the OpenType specification: Microsoft has abandoned the concept of @@ -592,7 +591,7 @@ FT_BEGIN_HEADER #define TT_MS_LANGID_MALAY_MALAYSIA 0x043E #define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083E #define TT_MS_LANGID_KAZAKH_KAZAKHSTAN 0x043F -#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic*/ 0x0440 +#define TT_MS_LANGID_KYRGYZ_KYRGYZSTAN /* Cyrillic */ 0x0440 #define TT_MS_LANGID_KISWAHILI_KENYA 0x0441 #define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442 #define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443 @@ -848,113 +847,113 @@ FT_BEGIN_HEADER /* --------------- */ /* Bit 0 Basic Latin */ -#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */ +#define TT_UCR_BASIC_LATIN (1UL << 0) /* U+0020-U+007E */ /* Bit 1 C1 Controls and Latin-1 Supplement */ -#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */ +#define TT_UCR_LATIN1_SUPPLEMENT (1UL << 1) /* U+0080-U+00FF */ /* Bit 2 Latin Extended-A */ -#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */ +#define TT_UCR_LATIN_EXTENDED_A (1UL << 2) /* U+0100-U+017F */ /* Bit 3 Latin Extended-B */ -#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */ +#define TT_UCR_LATIN_EXTENDED_B (1UL << 3) /* U+0180-U+024F */ /* Bit 4 IPA Extensions */ /* Phonetic Extensions */ /* Phonetic Extensions Supplement */ -#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */ +#define TT_UCR_IPA_EXTENSIONS (1UL << 4) /* U+0250-U+02AF */ /* U+1D00-U+1D7F */ /* U+1D80-U+1DBF */ /* Bit 5 Spacing Modifier Letters */ /* Modifier Tone Letters */ -#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */ +#define TT_UCR_SPACING_MODIFIER (1UL << 5) /* U+02B0-U+02FF */ /* U+A700-U+A71F */ /* Bit 6 Combining Diacritical Marks */ /* Combining Diacritical Marks Supplement */ -#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1L << 6) /* U+0300-U+036F */ +#define TT_UCR_COMBINING_DIACRITICAL_MARKS (1UL << 6) /* U+0300-U+036F */ /* U+1DC0-U+1DFF */ /* Bit 7 Greek and Coptic */ -#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */ +#define TT_UCR_GREEK (1UL << 7) /* U+0370-U+03FF */ /* Bit 8 Coptic */ -#define TT_UCR_COPTIC (1L << 8) /* U+2C80-U+2CFF */ +#define TT_UCR_COPTIC (1UL << 8) /* U+2C80-U+2CFF */ /* Bit 9 Cyrillic */ /* Cyrillic Supplement */ /* Cyrillic Extended-A */ /* Cyrillic Extended-B */ -#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */ +#define TT_UCR_CYRILLIC (1UL << 9) /* U+0400-U+04FF */ /* U+0500-U+052F */ /* U+2DE0-U+2DFF */ /* U+A640-U+A69F */ /* Bit 10 Armenian */ -#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */ +#define TT_UCR_ARMENIAN (1UL << 10) /* U+0530-U+058F */ /* Bit 11 Hebrew */ -#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */ +#define TT_UCR_HEBREW (1UL << 11) /* U+0590-U+05FF */ /* Bit 12 Vai */ -#define TT_UCR_VAI (1L << 12) /* U+A500-U+A63F */ +#define TT_UCR_VAI (1UL << 12) /* U+A500-U+A63F */ /* Bit 13 Arabic */ /* Arabic Supplement */ -#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */ +#define TT_UCR_ARABIC (1UL << 13) /* U+0600-U+06FF */ /* U+0750-U+077F */ /* Bit 14 NKo */ -#define TT_UCR_NKO (1L << 14) /* U+07C0-U+07FF */ +#define TT_UCR_NKO (1UL << 14) /* U+07C0-U+07FF */ /* 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 */ +#define TT_UCR_DEVANAGARI (1UL << 15) /* U+0900-U+097F */ + /* Bit 16 Bangla (Bengali) */ +#define TT_UCR_BENGALI (1UL << 16) /* U+0980-U+09FF */ /* Bit 17 Gurmukhi */ -#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */ +#define TT_UCR_GURMUKHI (1UL << 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 */ +#define TT_UCR_GUJARATI (1UL << 18) /* U+0A80-U+0AFF */ + /* Bit 19 Oriya (Odia) */ +#define TT_UCR_ORIYA (1UL << 19) /* U+0B00-U+0B7F */ /* Bit 20 Tamil */ -#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */ +#define TT_UCR_TAMIL (1UL << 20) /* U+0B80-U+0BFF */ /* Bit 21 Telugu */ -#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */ +#define TT_UCR_TELUGU (1UL << 21) /* U+0C00-U+0C7F */ /* Bit 22 Kannada */ -#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */ +#define TT_UCR_KANNADA (1UL << 22) /* U+0C80-U+0CFF */ /* Bit 23 Malayalam */ -#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */ +#define TT_UCR_MALAYALAM (1UL << 23) /* U+0D00-U+0D7F */ /* Bit 24 Thai */ -#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */ +#define TT_UCR_THAI (1UL << 24) /* U+0E00-U+0E7F */ /* Bit 25 Lao */ -#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */ +#define TT_UCR_LAO (1UL << 25) /* U+0E80-U+0EFF */ /* Bit 26 Georgian */ /* Georgian Supplement */ -#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */ +#define TT_UCR_GEORGIAN (1UL << 26) /* U+10A0-U+10FF */ /* U+2D00-U+2D2F */ /* Bit 27 Balinese */ -#define TT_UCR_BALINESE (1L << 27) /* U+1B00-U+1B7F */ +#define TT_UCR_BALINESE (1UL << 27) /* U+1B00-U+1B7F */ /* Bit 28 Hangul Jamo */ -#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */ +#define TT_UCR_HANGUL_JAMO (1UL << 28) /* U+1100-U+11FF */ /* Bit 29 Latin Extended Additional */ /* Latin Extended-C */ /* Latin Extended-D */ -#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */ +#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1UL << 29) /* U+1E00-U+1EFF */ /* U+2C60-U+2C7F */ /* U+A720-U+A7FF */ /* Bit 30 Greek Extended */ -#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */ +#define TT_UCR_GREEK_EXTENDED (1UL << 30) /* U+1F00-U+1FFF */ /* Bit 31 General Punctuation */ /* Supplemental Punctuation */ -#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */ +#define TT_UCR_GENERAL_PUNCTUATION (1UL << 31) /* U+2000-U+206F */ /* U+2E00-U+2E7F */ /* ulUnicodeRange2 */ /* --------------- */ /* Bit 32 Superscripts And Subscripts */ -#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */ +#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1UL << 0) /* U+2070-U+209F */ /* Bit 33 Currency Symbols */ -#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */ +#define TT_UCR_CURRENCY_SYMBOLS (1UL << 1) /* U+20A0-U+20CF */ /* Bit 34 Combining Diacritical Marks For Symbols */ #define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \ - (1L << 2) /* U+20D0-U+20FF */ + (1UL << 2) /* U+20D0-U+20FF */ /* Bit 35 Letterlike Symbols */ -#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */ +#define TT_UCR_LETTERLIKE_SYMBOLS (1UL << 3) /* U+2100-U+214F */ /* Bit 36 Number Forms */ -#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */ +#define TT_UCR_NUMBER_FORMS (1UL << 4) /* U+2150-U+218F */ /* Bit 37 Arrows */ /* Supplemental Arrows-A */ /* Supplemental Arrows-B */ /* Miscellaneous Symbols and Arrows */ -#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */ +#define TT_UCR_ARROWS (1UL << 5) /* U+2190-U+21FF */ /* U+27F0-U+27FF */ /* U+2900-U+297F */ /* U+2B00-U+2BFF */ @@ -962,52 +961,52 @@ FT_BEGIN_HEADER /* Supplemental Mathematical Operators */ /* Miscellaneous Mathematical Symbols-A */ /* Miscellaneous Mathematical Symbols-B */ -#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */ +#define TT_UCR_MATHEMATICAL_OPERATORS (1UL << 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 */ +#define TT_UCR_MISCELLANEOUS_TECHNICAL (1UL << 7) /* U+2300-U+23FF */ /* Bit 40 Control Pictures */ -#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */ +#define TT_UCR_CONTROL_PICTURES (1UL << 8) /* U+2400-U+243F */ /* Bit 41 Optical Character Recognition */ -#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */ +#define TT_UCR_OCR (1UL << 9) /* U+2440-U+245F */ /* Bit 42 Enclosed Alphanumerics */ -#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */ +#define TT_UCR_ENCLOSED_ALPHANUMERICS (1UL << 10) /* U+2460-U+24FF */ /* Bit 43 Box Drawing */ -#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */ +#define TT_UCR_BOX_DRAWING (1UL << 11) /* U+2500-U+257F */ /* Bit 44 Block Elements */ -#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */ +#define TT_UCR_BLOCK_ELEMENTS (1UL << 12) /* U+2580-U+259F */ /* Bit 45 Geometric Shapes */ -#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */ +#define TT_UCR_GEOMETRIC_SHAPES (1UL << 13) /* U+25A0-U+25FF */ /* Bit 46 Miscellaneous Symbols */ -#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */ +#define TT_UCR_MISCELLANEOUS_SYMBOLS (1UL << 14) /* U+2600-U+26FF */ /* Bit 47 Dingbats */ -#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */ +#define TT_UCR_DINGBATS (1UL << 15) /* U+2700-U+27BF */ /* Bit 48 CJK Symbols and Punctuation */ -#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */ +#define TT_UCR_CJK_SYMBOLS (1UL << 16) /* U+3000-U+303F */ /* Bit 49 Hiragana */ -#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */ +#define TT_UCR_HIRAGANA (1UL << 17) /* U+3040-U+309F */ /* Bit 50 Katakana */ /* Katakana Phonetic Extensions */ -#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */ +#define TT_UCR_KATAKANA (1UL << 18) /* U+30A0-U+30FF */ /* U+31F0-U+31FF */ /* Bit 51 Bopomofo */ /* Bopomofo Extended */ -#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */ +#define TT_UCR_BOPOMOFO (1UL << 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 */ +#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1UL << 20) /* U+3130-U+318F */ /* Bit 53 Phags-Pa */ -#define TT_UCR_CJK_MISC (1L << 21) /* U+A840-U+A87F */ -#define TT_UCR_KANBUN TT_UCR_CJK_MISC /* deprecated */ -#define TT_UCR_PHAGSPA +#define TT_UCR_PHAGSPA (1UL << 21) /* U+A840-U+A87F */ +#define TT_UCR_KANBUN TT_UCR_PHAGSPA /* deprecated */ +#define TT_UCR_CJK_MISC TT_UCR_PHAGSPA /* deprecated */ /* Bit 54 Enclosed CJK Letters and Months */ -#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */ +#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1UL << 22) /* U+3200-U+32FF */ /* Bit 55 CJK Compatibility */ -#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */ +#define TT_UCR_CJK_COMPATIBILITY (1UL << 23) /* U+3300-U+33FF */ /* Bit 56 Hangul Syllables */ -#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */ +#define TT_UCR_HANGUL (1UL << 24) /* U+AC00-U+D7A3 */ /* Bit 57 High Surrogates */ /* High Private Use Surrogates */ /* Low Surrogates */ @@ -1018,12 +1017,12 @@ FT_BEGIN_HEADER /* Basic Multilingual Plane that is */ /* supported by this font. So it really */ /* means >= U+10000. */ -#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */ +#define TT_UCR_SURROGATES (1UL << 25) /* U+D800-U+DB7F */ /* U+DB80-U+DBFF */ /* U+DC00-U+DFFF */ #define TT_UCR_NON_PLANE_0 TT_UCR_SURROGATES /* Bit 58 Phoenician */ -#define TT_UCR_PHOENICIAN (1L << 26) /*U+10900-U+1091F*/ +#define TT_UCR_PHOENICIAN (1UL << 26) /*U+10900-U+1091F*/ /* Bit 59 CJK Unified Ideographs */ /* CJK Radicals Supplement */ /* Kangxi Radicals */ @@ -1031,7 +1030,7 @@ FT_BEGIN_HEADER /* CJK Unified Ideographs Extension A */ /* CJK Unified Ideographs Extension B */ /* Kanbun */ -#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */ +#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1UL << 27) /* U+4E00-U+9FFF */ /* U+2E80-U+2EFF */ /* U+2F00-U+2FDF */ /* U+2FF0-U+2FFF */ @@ -1039,178 +1038,178 @@ FT_BEGIN_HEADER /*U+20000-U+2A6DF*/ /* U+3190-U+319F */ /* Bit 60 Private Use */ -#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */ +#define TT_UCR_PRIVATE_USE (1UL << 28) /* U+E000-U+F8FF */ /* Bit 61 CJK Strokes */ /* CJK Compatibility Ideographs */ /* CJK Compatibility Ideographs Supplement */ -#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+31C0-U+31EF */ +#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1UL << 29) /* U+31C0-U+31EF */ /* 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 */ +#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1UL << 30) /* U+FB00-U+FB4F */ /* Bit 63 Arabic Presentation Forms-A */ -#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1L << 31) /* U+FB50-U+FDFF */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_A (1UL << 31) /* U+FB50-U+FDFF */ /* ulUnicodeRange3 */ /* --------------- */ /* Bit 64 Combining Half Marks */ -#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */ +#define TT_UCR_COMBINING_HALF_MARKS (1UL << 0) /* U+FE20-U+FE2F */ /* Bit 65 Vertical forms */ /* CJK Compatibility Forms */ -#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE10-U+FE1F */ +#define TT_UCR_CJK_COMPATIBILITY_FORMS (1UL << 1) /* U+FE10-U+FE1F */ /* U+FE30-U+FE4F */ /* Bit 66 Small Form Variants */ -#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */ +#define TT_UCR_SMALL_FORM_VARIANTS (1UL << 2) /* U+FE50-U+FE6F */ /* Bit 67 Arabic Presentation Forms-B */ -#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1L << 3) /* U+FE70-U+FEFE */ +#define TT_UCR_ARABIC_PRESENTATION_FORMS_B (1UL << 3) /* U+FE70-U+FEFF */ /* Bit 68 Halfwidth and Fullwidth Forms */ -#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */ +#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1UL << 4) /* U+FF00-U+FFEF */ /* Bit 69 Specials */ -#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */ +#define TT_UCR_SPECIALS (1UL << 5) /* U+FFF0-U+FFFF */ /* Bit 70 Tibetan */ -#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */ +#define TT_UCR_TIBETAN (1UL << 6) /* U+0F00-U+0FFF */ /* Bit 71 Syriac */ -#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */ +#define TT_UCR_SYRIAC (1UL << 7) /* U+0700-U+074F */ /* Bit 72 Thaana */ -#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */ +#define TT_UCR_THAANA (1UL << 8) /* U+0780-U+07BF */ /* Bit 73 Sinhala */ -#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */ +#define TT_UCR_SINHALA (1UL << 9) /* U+0D80-U+0DFF */ /* Bit 74 Myanmar */ -#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */ +#define TT_UCR_MYANMAR (1UL << 10) /* U+1000-U+109F */ /* Bit 75 Ethiopic */ /* Ethiopic Supplement */ /* Ethiopic Extended */ -#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */ +#define TT_UCR_ETHIOPIC (1UL << 11) /* U+1200-U+137F */ /* U+1380-U+139F */ /* U+2D80-U+2DDF */ /* Bit 76 Cherokee */ -#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */ +#define TT_UCR_CHEROKEE (1UL << 12) /* U+13A0-U+13FF */ /* Bit 77 Unified Canadian Aboriginal Syllabics */ -#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */ +#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1UL << 13) /* U+1400-U+167F */ /* Bit 78 Ogham */ -#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */ +#define TT_UCR_OGHAM (1UL << 14) /* U+1680-U+169F */ /* Bit 79 Runic */ -#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */ +#define TT_UCR_RUNIC (1UL << 15) /* U+16A0-U+16FF */ /* Bit 80 Khmer */ /* Khmer Symbols */ -#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */ +#define TT_UCR_KHMER (1UL << 16) /* U+1780-U+17FF */ /* U+19E0-U+19FF */ /* Bit 81 Mongolian */ -#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */ +#define TT_UCR_MONGOLIAN (1UL << 17) /* U+1800-U+18AF */ /* Bit 82 Braille Patterns */ -#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */ +#define TT_UCR_BRAILLE (1UL << 18) /* U+2800-U+28FF */ /* Bit 83 Yi Syllables */ /* Yi Radicals */ -#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */ +#define TT_UCR_YI (1UL << 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 */ +#define TT_UCR_PHILIPPINE (1UL << 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*/ +#define TT_UCR_OLD_ITALIC (1UL << 21) /*U+10300-U+1032F*/ /* Bit 86 Gothic */ -#define TT_UCR_GOTHIC (1L << 22) /*U+10330-U+1034F*/ +#define TT_UCR_GOTHIC (1UL << 22) /*U+10330-U+1034F*/ /* Bit 87 Deseret */ -#define TT_UCR_DESERET (1L << 23) /*U+10400-U+1044F*/ +#define TT_UCR_DESERET (1UL << 23) /*U+10400-U+1044F*/ /* Bit 88 Byzantine Musical Symbols */ /* Musical Symbols */ /* Ancient Greek Musical Notation */ -#define TT_UCR_MUSICAL_SYMBOLS (1L << 24) /*U+1D000-U+1D0FF*/ +#define TT_UCR_MUSICAL_SYMBOLS (1UL << 24) /*U+1D000-U+1D0FF*/ /*U+1D100-U+1D1FF*/ /*U+1D200-U+1D24F*/ /* Bit 89 Mathematical Alphanumeric Symbols */ -#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1L << 25) /*U+1D400-U+1D7FF*/ +#define TT_UCR_MATH_ALPHANUMERIC_SYMBOLS (1UL << 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*/ +#define TT_UCR_PRIVATE_USE_SUPPLEMENTARY (1UL << 26) /*U+F0000-U+FFFFD*/ /*U+100000-U+10FFFD*/ /* Bit 91 Variation Selectors */ /* Variation Selectors Supplement */ -#define TT_UCR_VARIATION_SELECTORS (1L << 27) /* U+FE00-U+FE0F */ +#define TT_UCR_VARIATION_SELECTORS (1UL << 27) /* U+FE00-U+FE0F */ /*U+E0100-U+E01EF*/ /* Bit 92 Tags */ -#define TT_UCR_TAGS (1L << 28) /*U+E0000-U+E007F*/ +#define TT_UCR_TAGS (1UL << 28) /*U+E0000-U+E007F*/ /* Bit 93 Limbu */ -#define TT_UCR_LIMBU (1L << 29) /* U+1900-U+194F */ +#define TT_UCR_LIMBU (1UL << 29) /* U+1900-U+194F */ /* Bit 94 Tai Le */ -#define TT_UCR_TAI_LE (1L << 30) /* U+1950-U+197F */ +#define TT_UCR_TAI_LE (1UL << 30) /* U+1950-U+197F */ /* Bit 95 New Tai Lue */ -#define TT_UCR_NEW_TAI_LUE (1L << 31) /* U+1980-U+19DF */ +#define TT_UCR_NEW_TAI_LUE (1UL << 31) /* U+1980-U+19DF */ /* ulUnicodeRange4 */ /* --------------- */ /* Bit 96 Buginese */ -#define TT_UCR_BUGINESE (1L << 0) /* U+1A00-U+1A1F */ +#define TT_UCR_BUGINESE (1UL << 0) /* U+1A00-U+1A1F */ /* Bit 97 Glagolitic */ -#define TT_UCR_GLAGOLITIC (1L << 1) /* U+2C00-U+2C5F */ +#define TT_UCR_GLAGOLITIC (1UL << 1) /* U+2C00-U+2C5F */ /* Bit 98 Tifinagh */ -#define TT_UCR_TIFINAGH (1L << 2) /* U+2D30-U+2D7F */ +#define TT_UCR_TIFINAGH (1UL << 2) /* U+2D30-U+2D7F */ /* Bit 99 Yijing Hexagram Symbols */ -#define TT_UCR_YIJING (1L << 3) /* U+4DC0-U+4DFF */ +#define TT_UCR_YIJING (1UL << 3) /* U+4DC0-U+4DFF */ /* Bit 100 Syloti Nagri */ -#define TT_UCR_SYLOTI_NAGRI (1L << 4) /* U+A800-U+A82F */ +#define TT_UCR_SYLOTI_NAGRI (1UL << 4) /* U+A800-U+A82F */ /* Bit 101 Linear B Syllabary */ /* Linear B Ideograms */ /* Aegean Numbers */ -#define TT_UCR_LINEAR_B (1L << 5) /*U+10000-U+1007F*/ +#define TT_UCR_LINEAR_B (1UL << 5) /*U+10000-U+1007F*/ /*U+10080-U+100FF*/ /*U+10100-U+1013F*/ /* Bit 102 Ancient Greek Numbers */ -#define TT_UCR_ANCIENT_GREEK_NUMBERS (1L << 6) /*U+10140-U+1018F*/ +#define TT_UCR_ANCIENT_GREEK_NUMBERS (1UL << 6) /*U+10140-U+1018F*/ /* Bit 103 Ugaritic */ -#define TT_UCR_UGARITIC (1L << 7) /*U+10380-U+1039F*/ +#define TT_UCR_UGARITIC (1UL << 7) /*U+10380-U+1039F*/ /* Bit 104 Old Persian */ -#define TT_UCR_OLD_PERSIAN (1L << 8) /*U+103A0-U+103DF*/ +#define TT_UCR_OLD_PERSIAN (1UL << 8) /*U+103A0-U+103DF*/ /* Bit 105 Shavian */ -#define TT_UCR_SHAVIAN (1L << 9) /*U+10450-U+1047F*/ +#define TT_UCR_SHAVIAN (1UL << 9) /*U+10450-U+1047F*/ /* Bit 106 Osmanya */ -#define TT_UCR_OSMANYA (1L << 10) /*U+10480-U+104AF*/ +#define TT_UCR_OSMANYA (1UL << 10) /*U+10480-U+104AF*/ /* Bit 107 Cypriot Syllabary */ -#define TT_UCR_CYPRIOT_SYLLABARY (1L << 11) /*U+10800-U+1083F*/ +#define TT_UCR_CYPRIOT_SYLLABARY (1UL << 11) /*U+10800-U+1083F*/ /* Bit 108 Kharoshthi */ -#define TT_UCR_KHAROSHTHI (1L << 12) /*U+10A00-U+10A5F*/ +#define TT_UCR_KHAROSHTHI (1UL << 12) /*U+10A00-U+10A5F*/ /* Bit 109 Tai Xuan Jing Symbols */ -#define TT_UCR_TAI_XUAN_JING (1L << 13) /*U+1D300-U+1D35F*/ +#define TT_UCR_TAI_XUAN_JING (1UL << 13) /*U+1D300-U+1D35F*/ /* Bit 110 Cuneiform */ /* Cuneiform Numbers and Punctuation */ -#define TT_UCR_CUNEIFORM (1L << 14) /*U+12000-U+123FF*/ +#define TT_UCR_CUNEIFORM (1UL << 14) /*U+12000-U+123FF*/ /*U+12400-U+1247F*/ /* Bit 111 Counting Rod Numerals */ -#define TT_UCR_COUNTING_ROD_NUMERALS (1L << 15) /*U+1D360-U+1D37F*/ +#define TT_UCR_COUNTING_ROD_NUMERALS (1UL << 15) /*U+1D360-U+1D37F*/ /* Bit 112 Sundanese */ -#define TT_UCR_SUNDANESE (1L << 16) /* U+1B80-U+1BBF */ +#define TT_UCR_SUNDANESE (1UL << 16) /* U+1B80-U+1BBF */ /* Bit 113 Lepcha */ -#define TT_UCR_LEPCHA (1L << 17) /* U+1C00-U+1C4F */ +#define TT_UCR_LEPCHA (1UL << 17) /* U+1C00-U+1C4F */ /* Bit 114 Ol Chiki */ -#define TT_UCR_OL_CHIKI (1L << 18) /* U+1C50-U+1C7F */ +#define TT_UCR_OL_CHIKI (1UL << 18) /* U+1C50-U+1C7F */ /* Bit 115 Saurashtra */ -#define TT_UCR_SAURASHTRA (1L << 19) /* U+A880-U+A8DF */ +#define TT_UCR_SAURASHTRA (1UL << 19) /* U+A880-U+A8DF */ /* Bit 116 Kayah Li */ -#define TT_UCR_KAYAH_LI (1L << 20) /* U+A900-U+A92F */ +#define TT_UCR_KAYAH_LI (1UL << 20) /* U+A900-U+A92F */ /* Bit 117 Rejang */ -#define TT_UCR_REJANG (1L << 21) /* U+A930-U+A95F */ +#define TT_UCR_REJANG (1UL << 21) /* U+A930-U+A95F */ /* Bit 118 Cham */ -#define TT_UCR_CHAM (1L << 22) /* U+AA00-U+AA5F */ +#define TT_UCR_CHAM (1UL << 22) /* U+AA00-U+AA5F */ /* Bit 119 Ancient Symbols */ -#define TT_UCR_ANCIENT_SYMBOLS (1L << 23) /*U+10190-U+101CF*/ +#define TT_UCR_ANCIENT_SYMBOLS (1UL << 23) /*U+10190-U+101CF*/ /* Bit 120 Phaistos Disc */ -#define TT_UCR_PHAISTOS_DISC (1L << 24) /*U+101D0-U+101FF*/ +#define TT_UCR_PHAISTOS_DISC (1UL << 24) /*U+101D0-U+101FF*/ /* Bit 121 Carian */ /* Lycian */ /* Lydian */ -#define TT_UCR_OLD_ANATOLIAN (1L << 25) /*U+102A0-U+102DF*/ +#define TT_UCR_OLD_ANATOLIAN (1UL << 25) /*U+102A0-U+102DF*/ /*U+10280-U+1029F*/ /*U+10920-U+1093F*/ /* Bit 122 Domino Tiles */ /* Mahjong Tiles */ -#define TT_UCR_GAME_TILES (1L << 26) /*U+1F030-U+1F09F*/ +#define TT_UCR_GAME_TILES (1UL << 26) /*U+1F030-U+1F09F*/ /*U+1F000-U+1F02F*/ /* Bit 123-127 Reserved for process-internal usage */ diff --git a/src/thirdparty/freetype2/include/freetype/tttables.h b/src/thirdparty/freetype2/include/freetype/tttables.h index d04f81021..aa4336435 100644 --- a/src/thirdparty/freetype2/include/freetype/tttables.h +++ b/src/thirdparty/freetype2/include/freetype/tttables.h @@ -5,7 +5,7 @@ * Basic SFNT/TrueType tables definitions and interface * (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,7 @@ #define TTTABLES_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -193,7 +192,7 @@ FT_BEGIN_HEADER * A pointer into the 'hmtx' table. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `caret_Slope_Rise`, * `caret_Slope_Run`, and `caret_Offset`. @@ -311,7 +310,7 @@ FT_BEGIN_HEADER * A pointer into the 'vmtx' table. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `Ascender`, `Descender`, * `Line_Gap`, `caret_Slope_Rise`, `caret_Slope_Run`, and `caret_Offset`. @@ -360,7 +359,7 @@ FT_BEGIN_HEADER * table. In this case, the `version` field is always set to 0xFFFF. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `sCapHeight`, `sTypoAscender`, * `sTypoDescender`, `sTypoLineGap`, `sxHeight`, `usWinAscent`, @@ -425,8 +424,8 @@ FT_BEGIN_HEADER /* only version 5 and higher: */ - FT_UShort usLowerOpticalPointSize; /* in twips (1/20th points) */ - FT_UShort usUpperOpticalPointSize; /* in twips (1/20th points) */ + FT_UShort usLowerOpticalPointSize; /* in twips (1/20 points) */ + FT_UShort usUpperOpticalPointSize; /* in twips (1/20 points) */ } TT_OS2; @@ -443,7 +442,7 @@ FT_BEGIN_HEADER * them. * * @note: - * For an OpenType variation font, the values of the following fields can + * For OpenType Font Variations, the values of the following fields can * change after a call to @FT_Set_Var_Design_Coordinates (and friends) if * the font contains an 'MVAR' table: `underlinePosition` and * `underlineThickness`. @@ -706,6 +705,9 @@ FT_BEGIN_HEADER * definitions found in the @FT_TRUETYPE_TAGS_H file, or forge a new * one with @FT_MAKE_TAG. * + * [Since 2.14] Use value~1 if you want to access the table directory + * of the (currently selected) font. + * * offset :: * The starting offset in the table (or file if tag~==~0). * @@ -839,8 +841,9 @@ FT_BEGIN_HEADER * The target charmap. * * @return: - * The format of `charmap`. If `charmap` doesn't belong to an SFNT face, - * return -1. + * The format of `charmap`. If `charmap` doesn't belong to an SFNT face + * (including the synthetic Unicode charmap sometimes created by + * FreeType), return -1. */ FT_EXPORT( FT_Long ) FT_Get_CMap_Format( FT_CharMap charmap ); diff --git a/src/thirdparty/freetype2/include/freetype/tttags.h b/src/thirdparty/freetype2/include/freetype/tttags.h index bd0986eff..56bb0a3ee 100644 --- a/src/thirdparty/freetype2/include/freetype/tttags.h +++ b/src/thirdparty/freetype2/include/freetype/tttags.h @@ -4,7 +4,7 @@ * * Tags for TrueType and OpenType tables (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define TTAGS_H_ -#include -#include FT_FREETYPE_H +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -96,6 +95,7 @@ FT_BEGIN_HEADER #define TTAG_sbix FT_MAKE_TAG( 's', 'b', 'i', 'x' ) #define TTAG_sfnt FT_MAKE_TAG( 's', 'f', 'n', 't' ) #define TTAG_SING FT_MAKE_TAG( 'S', 'I', 'N', 'G' ) +#define TTAG_SVG FT_MAKE_TAG( 'S', 'V', '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', ' ' ) @@ -107,6 +107,7 @@ FT_BEGIN_HEADER #define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) #define TTAG_VVAR FT_MAKE_TAG( 'V', 'V', 'A', 'R' ) #define TTAG_wOFF FT_MAKE_TAG( 'w', 'O', 'F', 'F' ) +#define TTAG_wOF2 FT_MAKE_TAG( 'w', 'O', 'F', '2' ) /* used by "Keyboard.dfont" on legacy Mac OS X */ #define TTAG_0xA5kbd FT_MAKE_TAG( 0xA5, 'k', 'b', 'd' ) diff --git a/src/thirdparty/freetype2/include/ft2build.h b/src/thirdparty/freetype2/include/ft2build.h index e3f488794..3008aea7c 100644 --- a/src/thirdparty/freetype2/include/ft2build.h +++ b/src/thirdparty/freetype2/include/ft2build.h @@ -4,7 +4,7 @@ * * FreeType 2 build and setup macros. * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,16 +18,14 @@ /************************************************************************** * - * This is the 'entry point' for FreeType header file inclusions. It is - * the only header file which should be included directly; all other - * FreeType header files should be accessed with macro names (after - * including `ft2build.h`). + * This is the 'entry point' for FreeType header file inclusions, to be + * loaded before all other header files. * * A typical example is * * ``` * #include - * #include FT_FREETYPE_H + * #include * ``` * */ diff --git a/src/thirdparty/freetype2/src/autofit/afadjust.c b/src/thirdparty/freetype2/src/autofit/afadjust.c new file mode 100644 index 000000000..6637cacfc --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afadjust.c @@ -0,0 +1,1612 @@ +/**************************************************************************** + * + * afadjust.c + * + * Auto-fitter routines to adjust components based on charcode (body). + * + * Copyright (C) 2023-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Craig White . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 "afadjust.h" +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +# include "afgsub.h" +#endif + +#include +#include +#include +#include + +#define AF_ADJUSTMENT_DATABASE_LENGTH \ + ( sizeof ( adjustment_database ) / \ + sizeof ( adjustment_database[0] ) ) + +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + + + typedef struct AF_AdjustmentDatabaseEntry_ + { + FT_UInt32 codepoint; + FT_UInt32 flags; + + } AF_AdjustmentDatabaseEntry; + + + /* + All entries in this list must be sorted by ascending Unicode code + points. The table entries are 3 numbers consisting of: + + - Unicode code point. + - The vertical adjustment type. This should be a combination of the + AF_ADJUST_XXX and AF_IGNORE_XXX macros. + */ + static AF_AdjustmentDatabaseEntry adjustment_database[] = + { + /* C0 Controls and Basic Latin */ + { 0x21, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ! */ + { 0x51, AF_IGNORE_CAPITAL_BOTTOM } , /* Q */ + { 0x3F, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ? */ + { 0x69, AF_ADJUST_UP }, /* i */ + { 0x6A, AF_ADJUST_UP }, /* j */ +#if 0 + /* XXX TODO */ + { 0x7E, AF_ADJUST_TILDE_TOP }, /* ~ */ +#endif + + /* C1 Controls and Latin-1 Supplement */ + { 0xA1, AF_ADJUST_UP }, /* ¡ */ + { 0xA6, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ¦ */ + { 0xAA, AF_ADJUST_UP }, /* ª */ + { 0xBA, AF_ADJUST_UP }, /* º */ + { 0xBF, AF_ADJUST_UP }, /* ¿ */ + + { 0xC0, AF_ADJUST_UP }, /* À */ + { 0xC1, AF_ADJUST_UP }, /* Á */ + { 0xC2, AF_ADJUST_UP }, /* Â */ + { 0xC3, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ã */ + { 0xC4, AF_ADJUST_UP }, /* Ä */ + { 0xC5, AF_ADJUST_UP }, /* Å */ + { 0xC7, AF_IGNORE_CAPITAL_BOTTOM }, /* Ç */ + { 0xC8, AF_ADJUST_UP }, /* È */ + { 0xC9, AF_ADJUST_UP }, /* É */ + { 0xCA, AF_ADJUST_UP }, /* Ê */ + { 0xCB, AF_ADJUST_UP }, /* Ë */ + { 0xCC, AF_ADJUST_UP }, /* Ì */ + { 0xCD, AF_ADJUST_UP }, /* Í */ + { 0xCE, AF_ADJUST_UP }, /* Î */ + { 0xCF, AF_ADJUST_UP }, /* Ï */ + + { 0xD1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ñ */ + { 0xD2, AF_ADJUST_UP }, /* Ò */ + { 0xD3, AF_ADJUST_UP }, /* Ó */ + { 0xD4, AF_ADJUST_UP }, /* Ô */ + { 0xD5, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Õ */ + { 0xD6, AF_ADJUST_UP }, /* Ö */ + { 0xD8, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ø */ + { 0xD9, AF_ADJUST_UP }, /* Ù */ + { 0xDA, AF_ADJUST_UP }, /* Ú */ + { 0xDB, AF_ADJUST_UP }, /* Û */ + { 0xDC, AF_ADJUST_UP }, /* Ü */ + { 0xDD, AF_ADJUST_UP }, /* Ý */ + + { 0xE0, AF_ADJUST_UP }, /* à */ + { 0xE1, AF_ADJUST_UP }, /* á */ + { 0xE2, AF_ADJUST_UP }, /* â */ + { 0xE3, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ã */ + { 0xE4, AF_ADJUST_UP }, /* ä */ + { 0xE5, AF_ADJUST_UP }, /* å */ + { 0xE7, AF_IGNORE_SMALL_BOTTOM }, /* ç */ + { 0xE8, AF_ADJUST_UP }, /* è */ + { 0xE9, AF_ADJUST_UP }, /* é */ + { 0xEA, AF_ADJUST_UP }, /* ê */ + { 0xEB, AF_ADJUST_UP }, /* ë */ + { 0xEC, AF_ADJUST_UP }, /* ì */ + { 0xED, AF_ADJUST_UP }, /* í */ + { 0xEE, AF_ADJUST_UP }, /* î */ + { 0xEF, AF_ADJUST_UP }, /* ï */ + + { 0xF1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ñ */ + { 0xF2, AF_ADJUST_UP }, /* ò */ + { 0xF3, AF_ADJUST_UP }, /* ó */ + { 0xF4, AF_ADJUST_UP }, /* ô */ + { 0xF5, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* õ */ + { 0xF6, AF_ADJUST_UP }, /* ö */ + { 0xF8, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ø */ + { 0xF9, AF_ADJUST_UP }, /* ù */ + { 0xFA, AF_ADJUST_UP }, /* ú */ + { 0xFB, AF_ADJUST_UP }, /* û */ + { 0xFC, AF_ADJUST_UP }, /* ü */ + { 0xFD, AF_ADJUST_UP }, /* ý */ + { 0xFF, AF_ADJUST_UP }, /* ÿ */ + + /* Latin Extended-A */ + { 0x100, AF_ADJUST_UP }, /* Ā */ + { 0x101, AF_ADJUST_UP }, /* ā */ + { 0x102, AF_ADJUST_UP }, /* Ă */ + { 0x103, AF_ADJUST_UP }, /* ă */ + { 0x104, AF_IGNORE_CAPITAL_BOTTOM }, /* Ą */ + { 0x105, AF_IGNORE_SMALL_BOTTOM }, /* ą */ + { 0x106, AF_ADJUST_UP }, /* Ć */ + { 0x107, AF_ADJUST_UP }, /* ć */ + { 0x108, AF_ADJUST_UP }, /* Ĉ */ + { 0x109, AF_ADJUST_UP }, /* ĉ */ + { 0x10A, AF_ADJUST_UP }, /* Ċ */ + { 0x10B, AF_ADJUST_UP }, /* ċ */ + { 0x10C, AF_ADJUST_UP }, /* Č */ + { 0x10D, AF_ADJUST_UP }, /* č */ + { 0x10E, AF_ADJUST_UP }, /* Ď */ + + { 0x112, AF_ADJUST_UP }, /* Ē */ + { 0x113, AF_ADJUST_UP }, /* ē */ + { 0x114, AF_ADJUST_UP }, /* Ĕ */ + { 0x115, AF_ADJUST_UP }, /* ĕ */ + { 0x116, AF_ADJUST_UP }, /* Ė */ + { 0x117, AF_ADJUST_UP }, /* ė */ + { 0x118, AF_IGNORE_CAPITAL_BOTTOM }, /* Ę */ + { 0x119, AF_IGNORE_SMALL_BOTTOM }, /* ę */ + { 0x11A, AF_ADJUST_UP }, /* Ě */ + { 0x11B, AF_ADJUST_UP }, /* ě */ + { 0x11C, AF_ADJUST_UP }, /* Ĝ */ + { 0x11D, AF_ADJUST_UP }, /* ĝ */ + { 0x11E, AF_ADJUST_UP }, /* Ğ */ + { 0x11F, AF_ADJUST_UP }, /* ğ */ + + { 0x120, AF_ADJUST_UP }, /* Ġ */ + { 0x121, AF_ADJUST_UP }, /* ġ */ + { 0x122, AF_ADJUST_DOWN }, /* Ģ */ + { 0x123, AF_ADJUST_UP }, /* ģ */ + { 0x124, AF_ADJUST_UP }, /* Ĥ */ + { 0x125, AF_ADJUST_UP }, /* ĥ */ + { 0x128, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ĩ */ + { 0x129, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ĩ */ + { 0x12A, AF_ADJUST_UP }, /* Ī */ + { 0x12B, AF_ADJUST_UP }, /* ī */ + { 0x12C, AF_ADJUST_UP }, /* Ĭ */ + { 0x12D, AF_ADJUST_UP }, /* ĭ */ + { 0x12E, AF_IGNORE_CAPITAL_BOTTOM }, /* Į */ + { 0x12F, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* į */ + + { 0x130, AF_ADJUST_UP }, /* İ */ + { 0x133, AF_ADJUST_UP }, /* ij */ + { 0x134, AF_ADJUST_UP }, /* Ĵ */ + { 0x135, AF_ADJUST_UP }, /* ĵ */ + { 0x136, AF_ADJUST_DOWN }, /* Ķ */ + { 0x137, AF_ADJUST_DOWN }, /* ķ */ + { 0x139, AF_ADJUST_UP }, /* Ĺ */ + { 0x13A, AF_ADJUST_UP }, /* ĺ */ + { 0x13B, AF_ADJUST_DOWN }, /* Ļ */ + { 0x13C, AF_ADJUST_DOWN }, /* ļ */ + + { 0x143, AF_ADJUST_UP }, /* Ń */ + { 0x144, AF_ADJUST_UP }, /* ń */ + { 0x145, AF_ADJUST_DOWN }, /* Ņ */ + { 0x146, AF_ADJUST_DOWN }, /* ņ */ + { 0x147, AF_ADJUST_UP }, /* Ň */ + { 0x148, AF_ADJUST_UP }, /* ň */ + { 0x14C, AF_ADJUST_UP }, /* Ō */ + { 0x14D, AF_ADJUST_UP }, /* ō */ + { 0x14E, AF_ADJUST_UP }, /* Ŏ */ + { 0x14F, AF_ADJUST_UP }, /* ŏ */ + + { 0x150, AF_ADJUST_UP }, /* Ő */ + { 0x151, AF_ADJUST_UP }, /* ő */ + { 0x154, AF_ADJUST_UP }, /* Ŕ */ + { 0x155, AF_ADJUST_UP }, /* ŕ */ + { 0x156, AF_ADJUST_DOWN }, /* Ŗ */ + { 0x157, AF_ADJUST_DOWN }, /* ŗ */ + { 0x158, AF_ADJUST_UP }, /* Ř */ + { 0x159, AF_ADJUST_UP }, /* ř */ + { 0x15A, AF_ADJUST_UP }, /* Ś */ + { 0x15B, AF_ADJUST_UP }, /* ś */ + { 0x15C, AF_ADJUST_UP }, /* Ŝ */ + { 0x15D, AF_ADJUST_UP }, /* ŝ */ + { 0x15E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ş */ + { 0x15F, AF_IGNORE_SMALL_BOTTOM }, /* ş */ + + { 0x160, AF_ADJUST_UP }, /* Š */ + { 0x161, AF_ADJUST_UP }, /* š */ + { 0x162, AF_IGNORE_CAPITAL_BOTTOM }, /* Ţ */ + { 0x163, AF_IGNORE_SMALL_BOTTOM }, /* ţ */ + { 0x164, AF_ADJUST_UP }, /* Ť */ + { 0x168, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ũ */ + { 0x169, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ũ */ + { 0x16A, AF_ADJUST_UP }, /* Ū */ + { 0x16B, AF_ADJUST_UP }, /* ū */ + { 0x16C, AF_ADJUST_UP }, /* Ŭ */ + { 0x16D, AF_ADJUST_UP }, /* ŭ */ + { 0x16E, AF_ADJUST_UP }, /* Ů */ + { 0x16F, AF_ADJUST_UP }, /* ů */ + + { 0x170, AF_ADJUST_UP }, /* Ű */ + { 0x171, AF_ADJUST_UP }, /* ű */ + { 0x172, AF_IGNORE_CAPITAL_BOTTOM }, /* Ų */ + { 0x173, AF_IGNORE_SMALL_BOTTOM }, /* ų */ + { 0x174, AF_ADJUST_UP }, /* Ŵ */ + { 0x175, AF_ADJUST_UP }, /* ŵ */ + { 0x176, AF_ADJUST_UP }, /* Ŷ */ + { 0x177, AF_ADJUST_UP }, /* ŷ */ + { 0x178, AF_ADJUST_UP }, /* Ÿ */ + { 0x179, AF_ADJUST_UP }, /* Ź */ + { 0x17A, AF_ADJUST_UP }, /* ź */ + { 0x17B, AF_ADJUST_UP }, /* Ż */ + { 0x17C, AF_ADJUST_UP }, /* ż */ + { 0x17D, AF_ADJUST_UP }, /* Ž */ + { 0x17E, AF_ADJUST_UP }, /* ž */ + + /* Latin Extended-B */ + { 0x187, AF_IGNORE_CAPITAL_TOP }, /* Ƈ */ + { 0x188, AF_IGNORE_SMALL_TOP }, /* ƈ */ + + { 0x1A0, AF_IGNORE_CAPITAL_TOP }, /* Ơ */ + { 0x1A1, AF_IGNORE_SMALL_TOP }, /* ơ */ + { 0x1A5, AF_IGNORE_SMALL_TOP }, /* ƥ */ + { 0x1AB, AF_IGNORE_SMALL_BOTTOM }, /* ƫ */ + { 0x1AE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ʈ */ + { 0x1AF, AF_IGNORE_CAPITAL_TOP }, /* Ư */ + + { 0x1B0, AF_IGNORE_SMALL_TOP }, /* ư */ + { 0x1B4, AF_IGNORE_SMALL_TOP }, /* ƴ */ + + { 0x1C3, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ǃ */ + { 0x1C4, AF_ADJUST_UP }, /* DŽ */ +#if 0 + { 0x1C5, AF_ADJUST_UP }, /* Dž */ + { 0x1C6, AF_ADJUST_UP }, /* dž */ + { 0x1C8, AF_ADJUST_UP }, /* Lj */ + { 0x1C9, AF_ADJUST_UP }, /* lj */ + { 0x1CB, AF_ADJUST_UP }, /* Nj */ +#endif + { 0x1CC, AF_ADJUST_UP }, /* nj */ + { 0x1CD, AF_ADJUST_UP }, /* Ǎ */ + { 0x1CE, AF_ADJUST_UP }, /* ǎ */ + { 0x1CF, AF_ADJUST_UP }, /* Ǐ */ + + { 0x1D0, AF_ADJUST_UP }, /* ǐ */ + { 0x1D1, AF_ADJUST_UP }, /* Ǒ */ + { 0x1D2, AF_ADJUST_UP }, /* ǒ */ + { 0x1D3, AF_ADJUST_UP }, /* Ǔ */ + { 0x1D4, AF_ADJUST_UP }, /* ǔ */ + { 0x1D5, AF_ADJUST_UP2 }, /* Ǖ */ + { 0x1D6, AF_ADJUST_UP2 }, /* ǖ */ + { 0x1D7, AF_ADJUST_UP2 }, /* Ǘ */ + { 0x1D8, AF_ADJUST_UP2 }, /* ǘ */ + { 0x1D9, AF_ADJUST_UP2 }, /* Ǚ */ + { 0x1DA, AF_ADJUST_UP2 }, /* ǚ */ + { 0x1DB, AF_ADJUST_UP2 }, /* Ǜ */ + { 0x1DC, AF_ADJUST_UP2 }, /* ǜ */ + { 0x1DE, AF_ADJUST_UP2 }, /* Ǟ */ + { 0x1DF, AF_ADJUST_UP2 }, /* ǟ */ + + { 0x1E0, AF_ADJUST_UP2 }, /* Ǡ */ + { 0x1E1, AF_ADJUST_UP2 }, /* ǡ */ + { 0x1E2, AF_ADJUST_UP }, /* Ǣ */ + { 0x1E3, AF_ADJUST_UP }, /* ǣ */ + { 0x1E6, AF_ADJUST_UP }, /* Ǧ */ + { 0x1E7, AF_ADJUST_UP }, /* ǧ */ + { 0x1E8, AF_ADJUST_UP }, /* Ǩ */ + { 0x1E9, AF_ADJUST_UP }, /* ǩ */ + { 0x1EA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ǫ */ + { 0x1EB, AF_IGNORE_SMALL_BOTTOM }, /* ǫ */ + { 0x1EC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ǭ */ + { 0x1ED, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ǭ */ + { 0x1EE, AF_ADJUST_UP }, /* Ǯ */ + { 0x1EF, AF_ADJUST_UP }, /* ǯ */ + + { 0x1F0, AF_ADJUST_UP }, /* ǰ */ + { 0x1F4, AF_ADJUST_UP }, /* Ǵ */ + { 0x1F5, AF_ADJUST_UP }, /* ǵ */ + { 0x1F8, AF_ADJUST_UP }, /* Ǹ */ + { 0x1F9, AF_ADJUST_UP }, /* ǹ */ + { 0x1FA, AF_ADJUST_UP2 }, /* Ǻ */ + { 0x1FB, AF_ADJUST_UP2 }, /* ǻ */ + { 0x1FC, AF_ADJUST_UP }, /* Ǽ */ + { 0x1FD, AF_ADJUST_UP }, /* ǽ */ + { 0x1FE, AF_ADJUST_UP }, /* Ǿ */ + { 0x1FF, AF_ADJUST_UP }, /* ǿ */ + + { 0x200, AF_ADJUST_UP }, /* Ȁ */ + { 0x201, AF_ADJUST_UP }, /* ȁ */ + { 0x202, AF_ADJUST_UP }, /* Ȃ */ + { 0x203, AF_ADJUST_UP }, /* ȃ */ + { 0x204, AF_ADJUST_UP }, /* Ȅ */ + { 0x205, AF_ADJUST_UP }, /* ȅ */ + { 0x206, AF_ADJUST_UP }, /* Ȇ */ + { 0x207, AF_ADJUST_UP }, /* ȇ */ + { 0x208, AF_ADJUST_UP }, /* Ȉ */ + { 0x209, AF_ADJUST_UP }, /* ȉ */ + { 0x20A, AF_ADJUST_UP }, /* Ȋ */ + { 0x20B, AF_ADJUST_UP }, /* ȋ */ + { 0x20C, AF_ADJUST_UP }, /* Ȍ */ + { 0x20D, AF_ADJUST_UP }, /* ȍ */ + { 0x20E, AF_ADJUST_UP }, /* Ȏ */ + { 0x20F, AF_ADJUST_UP }, /* ȏ */ + + { 0x210, AF_ADJUST_UP }, /* Ȑ */ + { 0x211, AF_ADJUST_UP }, /* ȑ */ + { 0x212, AF_ADJUST_UP }, /* Ȓ */ + { 0x213, AF_ADJUST_UP }, /* ȓ */ + { 0x214, AF_ADJUST_UP }, /* Ȕ */ + { 0x215, AF_ADJUST_UP }, /* ȕ */ + { 0x216, AF_ADJUST_UP }, /* Ȗ */ + { 0x217, AF_ADJUST_UP }, /* ȗ */ + { 0x218, AF_ADJUST_DOWN }, /* Ș */ + { 0x219, AF_ADJUST_DOWN }, /* ș */ + { 0x21A, AF_ADJUST_DOWN }, /* Ț */ + { 0x21B, AF_ADJUST_DOWN }, /* ț */ + { 0x21E, AF_ADJUST_UP }, /* Ȟ */ + { 0x21F, AF_ADJUST_UP }, /* ȟ */ + + { 0x224, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȥ */ + { 0x225, AF_IGNORE_SMALL_BOTTOM }, /* ȥ */ + { 0x226, AF_ADJUST_UP }, /* Ȧ */ + { 0x227, AF_ADJUST_UP }, /* ȧ */ + { 0x228, AF_IGNORE_CAPITAL_BOTTOM }, /* Ȩ */ + { 0x229, AF_IGNORE_SMALL_BOTTOM }, /* ȩ */ + { 0x22A, AF_ADJUST_UP2 }, /* Ȫ */ + { 0x22B, AF_ADJUST_UP2 }, /* ȫ */ + { 0x22C, AF_ADJUST_UP2 }, /* Ȭ */ + { 0x22D, AF_ADJUST_UP2 }, /* ȭ */ + { 0x22E, AF_ADJUST_UP }, /* Ȯ */ + { 0x22F, AF_ADJUST_UP }, /* ȯ */ + + { 0x230, AF_ADJUST_UP2 }, /* Ȱ */ + { 0x231, AF_ADJUST_UP2 }, /* ȱ */ + { 0x232, AF_ADJUST_UP }, /* Ȳ */ + { 0x233, AF_ADJUST_UP }, /* ȳ */ + { 0x23A, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ⱥ */ + { 0x23B, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ȼ */ + { 0x23F, AF_IGNORE_SMALL_BOTTOM }, /* ȿ */ + + { 0x240, AF_IGNORE_SMALL_BOTTOM }, /* ɀ */ + { 0x249, AF_ADJUST_UP }, /* ɉ */ + + /* IPA Extensions */ + { 0x256, AF_IGNORE_SMALL_BOTTOM }, /* ɖ */ + + { 0x260, AF_IGNORE_SMALL_TOP }, /* ɠ */ + { 0x267, AF_IGNORE_SMALL_BOTTOM }, /* ɧ */ + { 0x268, AF_ADJUST_UP }, /* ɨ */ + + { 0x272, AF_IGNORE_SMALL_BOTTOM }, /* ɲ */ + { 0x273, AF_IGNORE_SMALL_BOTTOM }, /* ɳ */ + { 0x27B, AF_IGNORE_SMALL_BOTTOM }, /* ɻ */ + { 0x27D, AF_IGNORE_SMALL_BOTTOM }, /* ɽ */ + + { 0x282, AF_IGNORE_SMALL_BOTTOM }, /* ʂ */ + { 0x288, AF_IGNORE_SMALL_BOTTOM }, /* ʈ */ + + { 0x290, AF_IGNORE_SMALL_BOTTOM }, /* ʐ */ + { 0x29B, AF_IGNORE_SMALL_TOP }, /* ʛ */ + + { 0x2A0, AF_IGNORE_SMALL_TOP }, /* ʠ */ + + /* Spacing Modifier Letters */ + { 0x2B2, AF_ADJUST_UP }, /* ʲ */ + { 0x2B5, AF_IGNORE_SMALL_BOTTOM }, /* ʵ */ + + /* Greek and Coptic */ + { 0x390, AF_ADJUST_UP2 }, /* ΐ */ + + { 0x3AA, AF_ADJUST_UP }, /* Ϊ */ + { 0x3AB, AF_ADJUST_UP }, /* Ϋ */ + { 0x3AC, AF_ADJUST_UP }, /* ά */ + { 0x3AD, AF_ADJUST_UP }, /* έ */ + { 0x3AE, AF_ADJUST_UP }, /* ή */ + { 0x3AF, AF_ADJUST_UP }, /* ί */ + + { 0x3B0, AF_ADJUST_UP2 }, /* ΰ */ + + { 0x3CA, AF_ADJUST_UP }, /* ϊ */ + { 0x3CB, AF_ADJUST_UP }, /* ϋ */ + { 0x3CC, AF_ADJUST_UP }, /* ό */ + { 0x3CD, AF_ADJUST_UP }, /* ύ */ + { 0x3CE, AF_ADJUST_UP }, /* ώ */ + { 0x3CF, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϗ */ + + { 0x3D4, AF_ADJUST_UP }, /* ϔ */ + { 0x3D7, AF_IGNORE_SMALL_BOTTOM }, /* ϗ */ + { 0x3D9, AF_IGNORE_SMALL_BOTTOM }, /* ϙ */ + + { 0x3E2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ϣ */ + { 0x3E3, AF_IGNORE_SMALL_BOTTOM }, /* ϣ */ + + { 0x3F3, AF_ADJUST_UP }, /* ϳ */ + + /* Cyrillic */ + { 0x400, AF_ADJUST_UP }, /* Ѐ */ + { 0x401, AF_ADJUST_UP }, /* Ё */ + { 0x403, AF_ADJUST_UP }, /* Ѓ */ + { 0x407, AF_ADJUST_UP }, /* Ї */ + { 0x40C, AF_ADJUST_UP }, /* Ќ */ + { 0x40D, AF_ADJUST_UP }, /* Ѝ */ + { 0x40E, AF_ADJUST_UP }, /* Ў */ + { 0x40F, AF_IGNORE_CAPITAL_BOTTOM }, /* Џ */ + + { 0x419, AF_ADJUST_UP }, /* Й */ + + { 0x426, AF_IGNORE_CAPITAL_BOTTOM }, /* Ц */ + { 0x429, AF_IGNORE_CAPITAL_BOTTOM }, /* Щ */ + + { 0x439, AF_ADJUST_UP }, /* й */ + + { 0x446, AF_IGNORE_SMALL_BOTTOM }, /* ц */ + { 0x449, AF_IGNORE_SMALL_BOTTOM }, /* щ */ + + { 0x450, AF_ADJUST_UP }, /* ѐ */ + { 0x451, AF_ADJUST_UP }, /* ё */ + { 0x453, AF_ADJUST_UP }, /* ѓ */ + { 0x456, AF_ADJUST_UP }, /* і */ + { 0x457, AF_ADJUST_UP }, /* ї */ + { 0x458, AF_ADJUST_UP }, /* ј */ + { 0x45C, AF_ADJUST_UP }, /* ќ */ + { 0x45D, AF_ADJUST_UP }, /* ѝ */ + { 0x45E, AF_ADJUST_UP }, /* ў */ + { 0x45F, AF_IGNORE_SMALL_BOTTOM }, /* џ */ + + { 0x476, AF_ADJUST_UP }, /* Ѷ */ + { 0x477, AF_ADJUST_UP }, /* ѷ */ + { 0x47C, AF_ADJUST_UP2 }, /* Ѽ */ + { 0x47D, AF_ADJUST_UP2 }, /* ѽ */ + { 0x47E, AF_ADJUST_UP }, /* Ѿ */ + { 0x47F, AF_ADJUST_UP }, /* ѿ */ + + { 0x480, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҁ */ + { 0x481, AF_IGNORE_SMALL_BOTTOM }, /* ҁ */ + { 0x48A, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ҋ */ + { 0x48B, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ҋ */ + + { 0x490, AF_IGNORE_CAPITAL_TOP }, /* Ґ */ + { 0x491, AF_IGNORE_SMALL_TOP }, /* ґ */ + { 0x496, AF_IGNORE_CAPITAL_BOTTOM }, /* Җ */ + { 0x497, AF_IGNORE_SMALL_BOTTOM }, /* җ */ + { 0x498, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҙ */ + { 0x499, AF_IGNORE_SMALL_BOTTOM }, /* ҙ */ + { 0x49A, AF_IGNORE_CAPITAL_BOTTOM }, /* Қ */ + { 0x49B, AF_IGNORE_SMALL_BOTTOM }, /* қ */ + + { 0x4A2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ң */ + { 0x4A3, AF_IGNORE_SMALL_BOTTOM }, /* ң */ + { 0x4AA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҫ */ + { 0x4AB, AF_IGNORE_SMALL_BOTTOM }, /* ҫ */ + { 0x4AC, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҭ */ + { 0x4AD, AF_IGNORE_SMALL_BOTTOM }, /* ҭ */ + + { 0x4B2, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҳ */ + { 0x4B3, AF_IGNORE_SMALL_BOTTOM }, /* ҳ */ + { 0x4B4, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҵ */ + { 0x4B5, AF_IGNORE_SMALL_BOTTOM }, /* ҵ */ + { 0x4B6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҷ */ + { 0x4B7, AF_IGNORE_SMALL_BOTTOM }, /* ҷ */ + { 0x4BE, AF_IGNORE_CAPITAL_BOTTOM }, /* Ҿ */ + { 0x4BF, AF_IGNORE_SMALL_BOTTOM }, /* ҿ */ + + { 0x4C1, AF_ADJUST_UP }, /* Ӂ */ + { 0x4C2, AF_ADJUST_UP }, /* ӂ */ + { 0x4C5, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӆ */ + { 0x4C6, AF_IGNORE_SMALL_BOTTOM }, /* ӆ */ + { 0x4C9, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӊ */ + { 0x4CA, AF_IGNORE_SMALL_BOTTOM }, /* ӊ */ + { 0x4CB, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӌ */ + { 0x4CC, AF_IGNORE_SMALL_BOTTOM }, /* ӌ */ + { 0x4CD, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӎ */ + { 0x4CE, AF_IGNORE_SMALL_BOTTOM }, /* ӎ */ + + { 0x4D0, AF_ADJUST_UP }, /* Ӑ */ + { 0x4D1, AF_ADJUST_UP }, /* ӑ */ + { 0x4D2, AF_ADJUST_UP }, /* Ӓ */ + { 0x4D3, AF_ADJUST_UP }, /* ӓ */ + { 0x4D6, AF_ADJUST_UP }, /* Ӗ */ + { 0x4D7, AF_ADJUST_UP }, /* ӗ */ + { 0x4DA, AF_ADJUST_UP }, /* Ӛ */ + { 0x4DB, AF_ADJUST_UP }, /* ӛ */ + { 0x4DC, AF_ADJUST_UP }, /* Ӝ */ + { 0x4DD, AF_ADJUST_UP }, /* ӝ */ + { 0x4DE, AF_ADJUST_UP }, /* Ӟ */ + { 0x4DF, AF_ADJUST_UP }, /* ӟ */ + + { 0x4E2, AF_ADJUST_UP }, /* Ӣ */ + { 0x4E3, AF_ADJUST_UP }, /* ӣ */ + { 0x4E4, AF_ADJUST_UP }, /* Ӥ */ + { 0x4E5, AF_ADJUST_UP }, /* ӥ */ + { 0x4E6, AF_ADJUST_UP }, /* Ӧ */ + { 0x4E7, AF_ADJUST_UP }, /* ӧ */ + { 0x4EA, AF_ADJUST_UP }, /* Ӫ */ + { 0x4EB, AF_ADJUST_UP }, /* ӫ */ + { 0x4EC, AF_ADJUST_UP }, /* Ӭ */ + { 0x4ED, AF_ADJUST_UP }, /* ӭ */ + { 0x4EE, AF_ADJUST_UP }, /* Ӯ */ + { 0x4EF, AF_ADJUST_UP }, /* ӯ */ + + { 0x4F0, AF_ADJUST_UP }, /* Ӱ */ + { 0x4F1, AF_ADJUST_UP }, /* ӱ */ + { 0x4F2, AF_ADJUST_UP }, /* Ӳ */ + { 0x4F3, AF_ADJUST_UP }, /* ӳ */ + { 0x4F4, AF_ADJUST_UP }, /* Ӵ */ + { 0x4F5, AF_ADJUST_UP }, /* ӵ */ + { 0x4F6, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӷ */ + { 0x4F7, AF_IGNORE_SMALL_BOTTOM }, /* ӷ */ + { 0x4F8, AF_ADJUST_UP }, /* Ӹ */ + { 0x4F9, AF_ADJUST_UP }, /* ӹ */ + { 0x4FA, AF_IGNORE_CAPITAL_BOTTOM }, /* Ӻ */ + { 0x4FB, AF_IGNORE_SMALL_BOTTOM }, /* ӻ */ + + /* Cyrillic Supplement */ + { 0x506, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԇ */ + { 0x507, AF_IGNORE_SMALL_BOTTOM }, /* ԇ */ + + { 0x524, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԥ */ + { 0x525, AF_IGNORE_SMALL_BOTTOM }, /* ԥ */ + { 0x526, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԧ */ + { 0x527, AF_IGNORE_SMALL_BOTTOM }, /* ԧ */ + { 0x52E, AF_IGNORE_CAPITAL_BOTTOM }, /* Ԯ */ + { 0x52F, AF_IGNORE_SMALL_BOTTOM }, /* ԯ */ + + /* Cherokee */ + { 0x13A5, AF_ADJUST_UP }, /* Ꭵ */ + + /* Phonetic Extensions */ + { 0x1D09, AF_ADJUST_DOWN }, /* ᴉ */ + + { 0x1D4E, AF_ADJUST_DOWN }, /* ᵎ */ + + { 0x1D51, AF_IGNORE_SMALL_BOTTOM }, /* ᵑ */ + + { 0x1D62, AF_ADJUST_UP }, /* ᵢ */ + + /* Phonetic Extensions Supplement */ + { 0x1D80, AF_IGNORE_SMALL_BOTTOM }, /* ᶀ */ + { 0x1D81, AF_IGNORE_SMALL_BOTTOM }, /* ᶁ */ + { 0x1D82, AF_IGNORE_SMALL_BOTTOM }, /* ᶂ */ + { 0x1D84, AF_IGNORE_SMALL_BOTTOM }, /* ᶄ */ + { 0x1D85, AF_IGNORE_SMALL_BOTTOM }, /* ᶅ */ + { 0x1D86, AF_IGNORE_SMALL_BOTTOM }, /* ᶆ */ + { 0x1D87, AF_IGNORE_SMALL_BOTTOM }, /* ᶇ */ + { 0x1D89, AF_IGNORE_SMALL_BOTTOM }, /* ᶉ */ + { 0x1D8A, AF_IGNORE_SMALL_BOTTOM }, /* ᶊ */ + { 0x1D8C, AF_IGNORE_SMALL_BOTTOM }, /* ᶌ */ + { 0x1D8D, AF_IGNORE_SMALL_BOTTOM }, /* ᶍ */ + { 0x1D8E, AF_IGNORE_SMALL_BOTTOM }, /* ᶎ */ + { 0x1D8F, AF_IGNORE_SMALL_BOTTOM }, /* ᶏ */ + + { 0x1D90, AF_IGNORE_SMALL_BOTTOM }, /* ᶐ */ + { 0x1D91, AF_IGNORE_SMALL_BOTTOM }, /* ᶑ */ + { 0x1D92, AF_IGNORE_SMALL_BOTTOM }, /* ᶒ */ + { 0x1D93, AF_IGNORE_SMALL_BOTTOM }, /* ᶓ */ + { 0x1D94, AF_IGNORE_SMALL_BOTTOM }, /* ᶔ */ + { 0x1D95, AF_IGNORE_SMALL_BOTTOM }, /* ᶕ */ + { 0x1D96, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ᶖ */ + { 0x1D97, AF_IGNORE_SMALL_BOTTOM }, /* ᶗ */ + { 0x1D98, AF_IGNORE_SMALL_BOTTOM }, /* ᶘ */ + { 0x1D99, AF_IGNORE_SMALL_BOTTOM }, /* ᶙ */ + { 0x1D9A, AF_IGNORE_SMALL_BOTTOM }, /* ᶚ */ + + { 0x1DA4, AF_ADJUST_UP }, /* ᶤ */ + { 0x1DA8, AF_ADJUST_UP }, /* ᶨ */ + { 0x1DA9, AF_IGNORE_SMALL_BOTTOM }, /* ᶩ */ + { 0x1DAA, AF_IGNORE_SMALL_BOTTOM }, /* ᶪ */ + { 0x1DAC, AF_IGNORE_SMALL_BOTTOM }, /* ᶬ */ + { 0x1DAE, AF_IGNORE_SMALL_BOTTOM }, /* ᶮ */ + { 0x1DAF, AF_IGNORE_SMALL_BOTTOM }, /* ᶯ */ + + { 0x1DB3, AF_IGNORE_SMALL_BOTTOM }, /* ᶳ */ + { 0x1DB5, AF_IGNORE_SMALL_BOTTOM }, /* ᶵ */ + { 0x1DBC, AF_IGNORE_SMALL_BOTTOM }, /* ᶼ */ + + /* Latin Extended Additional */ + { 0x1E00, AF_ADJUST_DOWN }, /* Ḁ */ + { 0x1E01, AF_ADJUST_DOWN }, /* ḁ */ + { 0x1E02, AF_ADJUST_UP }, /* Ḃ */ + { 0x1E03, AF_ADJUST_UP }, /* ḃ */ + { 0x1E04, AF_ADJUST_DOWN }, /* Ḅ */ + { 0x1E05, AF_ADJUST_DOWN }, /* ḅ */ + { 0x1E06, AF_ADJUST_DOWN }, /* Ḇ */ + { 0x1E07, AF_ADJUST_DOWN }, /* ḇ */ + { 0x1E08, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḉ */ + { 0x1E09, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḉ */ + { 0x1E0A, AF_ADJUST_UP }, /* Ḋ */ + { 0x1E0B, AF_ADJUST_UP }, /* ḋ */ + { 0x1E0C, AF_ADJUST_DOWN }, /* Ḍ */ + { 0x1E0D, AF_ADJUST_DOWN }, /* ḍ */ + { 0x1E0E, AF_ADJUST_DOWN }, /* Ḏ */ + { 0x1E0F, AF_ADJUST_DOWN }, /* ḏ */ + + { 0x1E10, AF_ADJUST_DOWN }, /* Ḑ */ + { 0x1E11, AF_ADJUST_DOWN }, /* ḑ */ + { 0x1E12, AF_ADJUST_DOWN }, /* Ḓ */ + { 0x1E13, AF_ADJUST_DOWN }, /* ḓ */ + { 0x1E14, AF_ADJUST_UP2 }, /* Ḕ */ + { 0x1E15, AF_ADJUST_UP2 }, /* ḕ */ + { 0x1E16, AF_ADJUST_UP2 }, /* Ḗ */ + { 0x1E17, AF_ADJUST_UP2 }, /* ḗ */ + { 0x1E18, AF_ADJUST_DOWN }, /* Ḙ */ + { 0x1E19, AF_ADJUST_DOWN }, /* ḙ */ + { 0x1E1A, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḛ */ + { 0x1E1B, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḛ */ + { 0x1E1C, AF_ADJUST_UP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ḝ */ + { 0x1E1D, AF_ADJUST_UP | AF_IGNORE_SMALL_BOTTOM }, /* ḝ */ + { 0x1E1E, AF_ADJUST_UP }, /* Ḟ */ + { 0x1E1F, AF_ADJUST_UP }, /* ḟ */ + + { 0x1E20, AF_ADJUST_UP }, /* Ḡ */ + { 0x1E21, AF_ADJUST_UP }, /* ḡ */ + { 0x1E22, AF_ADJUST_UP }, /* Ḣ */ + { 0x1E23, AF_ADJUST_UP }, /* ḣ */ + { 0x1E24, AF_ADJUST_DOWN }, /* Ḥ */ + { 0x1E25, AF_ADJUST_DOWN }, /* ḥ */ + { 0x1E26, AF_ADJUST_UP }, /* Ḧ */ + { 0x1E27, AF_ADJUST_UP }, /* ḧ */ + { 0x1E28, AF_IGNORE_CAPITAL_BOTTOM }, /* Ḩ */ + { 0x1E29, AF_IGNORE_SMALL_BOTTOM }, /* ḩ */ + { 0x1E2A, AF_ADJUST_DOWN }, /* Ḫ */ + { 0x1E2B, AF_ADJUST_DOWN }, /* ḫ */ + { 0x1E2C, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ḭ */ + { 0x1E2D, AF_ADJUST_UP | AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ḭ */ + { 0x1E2E, AF_ADJUST_UP2 }, /* Ḯ */ + { 0x1E2F, AF_ADJUST_UP2 }, /* ḯ */ + + { 0x1E30, AF_ADJUST_UP }, /* Ḱ */ + { 0x1E31, AF_ADJUST_UP }, /* ḱ */ + { 0x1E32, AF_ADJUST_DOWN }, /* Ḳ */ + { 0x1E33, AF_ADJUST_DOWN }, /* ḳ */ + { 0x1E34, AF_ADJUST_DOWN }, /* Ḵ */ + { 0x1E35, AF_ADJUST_DOWN }, /* ḵ */ + { 0x1E36, AF_ADJUST_DOWN }, /* Ḷ */ + { 0x1E37, AF_ADJUST_DOWN }, /* ḷ */ + { 0x1E38, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ḹ */ + { 0x1E39, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ḹ */ + { 0x1E3A, AF_ADJUST_DOWN }, /* Ḻ */ + { 0x1E3B, AF_ADJUST_DOWN }, /* ḻ */ + { 0x1E3C, AF_ADJUST_DOWN }, /* Ḽ */ + { 0x1E3D, AF_ADJUST_DOWN }, /* ḽ */ + { 0x1E3E, AF_ADJUST_UP }, /* Ḿ */ + { 0x1E3F, AF_ADJUST_UP }, /* ḿ */ + + { 0x1E40, AF_ADJUST_UP }, /* Ṁ */ + { 0x1E41, AF_ADJUST_UP }, /* ṁ */ + { 0x1E42, AF_ADJUST_DOWN }, /* Ṃ */ + { 0x1E43, AF_ADJUST_DOWN }, /* ṃ */ + { 0x1E44, AF_ADJUST_UP }, /* Ṅ */ + { 0x1E45, AF_ADJUST_UP }, /* ṅ */ + { 0x1E46, AF_ADJUST_DOWN }, /* Ṇ */ + { 0x1E47, AF_ADJUST_DOWN }, /* ṇ */ + { 0x1E48, AF_ADJUST_DOWN }, /* Ṉ */ + { 0x1E49, AF_ADJUST_DOWN }, /* ṉ */ + { 0x1E4A, AF_ADJUST_DOWN }, /* Ṋ */ + { 0x1E4B, AF_ADJUST_DOWN }, /* ṋ */ + { 0x1E4C, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṍ */ + { 0x1E4D, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṍ */ + { 0x1E4E, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṏ */ + { 0x1E4F, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṏ */ + + { 0x1E50, AF_ADJUST_UP2 }, /* Ṑ */ + { 0x1E51, AF_ADJUST_UP2 }, /* ṑ */ + { 0x1E52, AF_ADJUST_UP2 }, /* Ṓ */ + { 0x1E53, AF_ADJUST_UP2 }, /* ṓ */ + { 0x1E54, AF_ADJUST_UP }, /* Ṕ */ + { 0x1E55, AF_ADJUST_UP }, /* ṕ */ + { 0x1E56, AF_ADJUST_UP }, /* Ṗ */ + { 0x1E57, AF_ADJUST_UP }, /* ṗ */ + { 0x1E58, AF_ADJUST_UP }, /* Ṙ */ + { 0x1E59, AF_ADJUST_UP }, /* ṙ */ + { 0x1E5A, AF_ADJUST_DOWN }, /* Ṛ */ + { 0x1E5B, AF_ADJUST_DOWN }, /* ṛ */ + { 0x1E5C, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṝ */ + { 0x1E5D, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṝ */ + { 0x1E5E, AF_ADJUST_DOWN }, /* Ṟ */ + { 0x1E5F, AF_ADJUST_DOWN }, /* ṟ */ + + { 0x1E60, AF_ADJUST_UP }, /* Ṡ */ + { 0x1E61, AF_ADJUST_UP }, /* ṡ */ + { 0x1E62, AF_ADJUST_DOWN }, /* Ṣ */ + { 0x1E63, AF_ADJUST_DOWN }, /* ṣ */ + { 0x1E64, AF_ADJUST_UP }, /* Ṥ */ + { 0x1E65, AF_ADJUST_UP }, /* ṥ */ + { 0x1E66, AF_ADJUST_UP }, /* Ṧ */ + { 0x1E67, AF_ADJUST_UP }, /* ṧ */ + { 0x1E68, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ṩ */ + { 0x1E69, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ṩ */ + { 0x1E6A, AF_ADJUST_UP }, /* Ṫ */ + { 0x1E6B, AF_ADJUST_UP }, /* ṫ */ + { 0x1E6C, AF_ADJUST_DOWN }, /* Ṭ */ + { 0x1E6D, AF_ADJUST_DOWN }, /* ṭ */ + { 0x1E6E, AF_ADJUST_DOWN }, /* Ṯ */ + { 0x1E6F, AF_ADJUST_DOWN }, /* ṯ */ + + { 0x1E70, AF_ADJUST_DOWN }, /* Ṱ */ + { 0x1E71, AF_ADJUST_DOWN }, /* ṱ */ + { 0x1E72, AF_ADJUST_DOWN }, /* Ṳ */ + { 0x1E73, AF_ADJUST_DOWN }, /* ṳ */ + { 0x1E74, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* Ṵ */ + { 0x1E75, AF_ADJUST_DOWN | AF_ADJUST_TILDE_BOTTOM }, /* ṵ */ + { 0x1E76, AF_ADJUST_DOWN }, /* Ṷ */ + { 0x1E77, AF_ADJUST_DOWN }, /* ṷ */ + { 0x1E78, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* Ṹ */ + { 0x1E79, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP2 }, /* ṹ */ + { 0x1E7A, AF_ADJUST_UP2 }, /* Ṻ */ + { 0x1E7B, AF_ADJUST_UP2 }, /* ṻ */ + { 0x1E7C, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ṽ */ + { 0x1E7D, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ṽ */ + { 0x1E7E, AF_ADJUST_DOWN }, /* Ṿ */ + { 0x1E7F, AF_ADJUST_DOWN }, /* ṿ */ + + { 0x1E80, AF_ADJUST_UP }, /* Ẁ */ + { 0x1E81, AF_ADJUST_UP }, /* ẁ */ + { 0x1E82, AF_ADJUST_UP }, /* Ẃ */ + { 0x1E83, AF_ADJUST_UP }, /* ẃ */ + { 0x1E84, AF_ADJUST_UP }, /* Ẅ */ + { 0x1E85, AF_ADJUST_UP }, /* ẅ */ + { 0x1E86, AF_ADJUST_UP }, /* Ẇ */ + { 0x1E87, AF_ADJUST_UP }, /* ẇ */ + { 0x1E88, AF_ADJUST_DOWN }, /* Ẉ */ + { 0x1E89, AF_ADJUST_DOWN }, /* ẉ */ + { 0x1E8A, AF_ADJUST_UP }, /* Ẋ */ + { 0x1E8B, AF_ADJUST_UP }, /* ẋ */ + { 0x1E8C, AF_ADJUST_UP }, /* Ẍ */ + { 0x1E8D, AF_ADJUST_UP }, /* ẍ */ + { 0x1E8E, AF_ADJUST_UP }, /* Ẏ */ + { 0x1E8F, AF_ADJUST_UP }, /* ẏ */ + + { 0x1E90, AF_ADJUST_UP }, /* Ẑ */ + { 0x1E91, AF_ADJUST_UP }, /* ẑ */ + { 0x1E92, AF_ADJUST_DOWN }, /* Ẓ */ + { 0x1E93, AF_ADJUST_DOWN }, /* ẓ */ + { 0x1E94, AF_ADJUST_DOWN }, /* Ẕ */ + { 0x1E95, AF_ADJUST_DOWN }, /* ẕ */ + { 0x1E96, AF_ADJUST_DOWN }, /* ẖ */ + { 0x1E97, AF_ADJUST_UP }, /* ẗ */ + { 0x1E98, AF_ADJUST_UP }, /* ẘ */ + { 0x1E99, AF_ADJUST_UP }, /* ẙ */ + { 0x1E9A, AF_ADJUST_UP }, /* ẚ */ + { 0x1E9B, AF_ADJUST_UP }, /* ẛ */ + + { 0x1EA0, AF_ADJUST_DOWN }, /* Ạ */ + { 0x1EA1, AF_ADJUST_DOWN }, /* ạ */ + { 0x1EA2, AF_ADJUST_UP }, /* Ả */ + { 0x1EA3, AF_ADJUST_UP }, /* ả */ + { 0x1EA4, AF_ADJUST_UP2 }, /* Ấ */ + { 0x1EA5, AF_ADJUST_UP2 }, /* ấ */ + { 0x1EA6, AF_ADJUST_UP2 }, /* Ầ */ + { 0x1EA7, AF_ADJUST_UP2 }, /* ầ */ + { 0x1EA8, AF_ADJUST_UP2 }, /* Ẩ */ + { 0x1EA9, AF_ADJUST_UP2 }, /* ẩ */ + { 0x1EAA, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẫ */ + { 0x1EAB, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẫ */ + { 0x1EAC, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ậ */ + { 0x1EAD, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ậ */ + { 0x1EAE, AF_ADJUST_UP2 }, /* Ắ */ + { 0x1EAF, AF_ADJUST_UP2 }, /* ắ */ + + { 0x1EB0, AF_ADJUST_UP2 }, /* Ằ */ + { 0x1EB1, AF_ADJUST_UP2 }, /* ằ */ + { 0x1EB2, AF_ADJUST_UP2 }, /* Ẳ */ + { 0x1EB3, AF_ADJUST_UP2 }, /* ẳ */ + { 0x1EB4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ẵ */ + { 0x1EB5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ẵ */ + { 0x1EB6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ặ */ + { 0x1EB7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ặ */ + { 0x1EB8, AF_ADJUST_DOWN }, /* Ẹ */ + { 0x1EB9, AF_ADJUST_DOWN }, /* ẹ */ + { 0x1EBA, AF_ADJUST_UP }, /* Ẻ */ + { 0x1EBB, AF_ADJUST_UP }, /* ẻ */ + { 0x1EBC, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ẽ */ + { 0x1EBD, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ẽ */ + { 0x1EBE, AF_ADJUST_UP2 }, /* Ế */ + { 0x1EBF, AF_ADJUST_UP2 }, /* ế */ + + { 0x1EC0, AF_ADJUST_UP2 }, /* Ề */ + { 0x1EC1, AF_ADJUST_UP2 }, /* ề */ + { 0x1EC2, AF_ADJUST_UP2 }, /* Ể */ + { 0x1EC3, AF_ADJUST_UP2 }, /* ể */ + { 0x1EC4, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ễ */ + { 0x1EC5, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ễ */ + { 0x1EC6, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ệ */ + { 0x1EC7, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ệ */ + { 0x1EC8, AF_ADJUST_UP }, /* Ỉ */ + { 0x1EC9, AF_ADJUST_UP }, /* ỉ */ + { 0x1ECA, AF_ADJUST_DOWN }, /* Ị */ + { 0x1ECB, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ị */ + { 0x1ECC, AF_ADJUST_DOWN }, /* Ọ */ + { 0x1ECD, AF_ADJUST_DOWN }, /* ọ */ + { 0x1ECE, AF_ADJUST_UP }, /* Ỏ */ + { 0x1ECF, AF_ADJUST_UP }, /* ỏ */ + + { 0x1ED0, AF_ADJUST_UP2 }, /* Ố */ + { 0x1ED1, AF_ADJUST_UP2 }, /* ố */ + { 0x1ED2, AF_ADJUST_UP2 }, /* Ồ */ + { 0x1ED3, AF_ADJUST_UP2 }, /* ồ */ + { 0x1ED4, AF_ADJUST_UP2 }, /* Ổ */ + { 0x1ED5, AF_ADJUST_UP2 }, /* ổ */ + { 0x1ED6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* Ỗ */ + { 0x1ED7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ỗ */ + { 0x1ED8, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* Ộ */ + { 0x1ED9, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ộ */ + { 0x1EDA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ớ */ + { 0x1EDB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ớ */ + { 0x1EDC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ờ */ + { 0x1EDD, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ờ */ + { 0x1EDE, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ở */ + { 0x1EDF, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ở */ + + { 0x1EE0, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ỡ */ + { 0x1EE1, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ỡ */ + { 0x1EE2, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ợ */ + { 0x1EE3, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ợ */ + { 0x1EE4, AF_ADJUST_DOWN }, /* Ụ */ + { 0x1EE5, AF_ADJUST_DOWN }, /* ụ */ + { 0x1EE6, AF_ADJUST_UP }, /* Ủ */ + { 0x1EE7, AF_ADJUST_UP }, /* ủ */ + { 0x1EE8, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ứ */ + { 0x1EE9, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ứ */ + { 0x1EEA, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ừ */ + { 0x1EEB, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ừ */ + { 0x1EEC, AF_ADJUST_UP | AF_IGNORE_CAPITAL_TOP }, /* Ử */ + { 0x1EED, AF_ADJUST_UP | AF_IGNORE_SMALL_TOP }, /* ử */ + { 0x1EEE, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_CAPITAL_TOP }, /* Ữ */ + { 0x1EEF, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_IGNORE_SMALL_TOP }, /* ữ */ + + { 0x1EF0, AF_ADJUST_DOWN | AF_IGNORE_CAPITAL_TOP }, /* Ự */ + { 0x1EF1, AF_ADJUST_DOWN | AF_IGNORE_SMALL_TOP }, /* ự */ + { 0x1EF2, AF_ADJUST_UP }, /* Ỳ */ + { 0x1EF3, AF_ADJUST_UP }, /* ỳ */ + { 0x1EF4, AF_ADJUST_DOWN }, /* Ỵ */ + { 0x1EF5, AF_ADJUST_DOWN }, /* ỵ */ + { 0x1EF6, AF_ADJUST_UP }, /* Ỷ */ + { 0x1EF7, AF_ADJUST_UP }, /* ỷ */ + { 0x1EF8, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* Ỹ */ + { 0x1EF9, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ỹ */ + + /* Greek Extended */ + { 0x1F00, AF_ADJUST_UP }, /* ἀ */ + { 0x1F01, AF_ADJUST_UP }, /* ἁ */ + { 0x1F02, AF_ADJUST_UP }, /* ἂ */ + { 0x1F03, AF_ADJUST_UP }, /* ἃ */ + { 0x1F04, AF_ADJUST_UP }, /* ἄ */ + { 0x1F05, AF_ADJUST_UP }, /* ἅ */ + { 0x1F06, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἆ */ + { 0x1F07, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἇ */ + + { 0x1F10, AF_ADJUST_UP }, /* ἐ */ + { 0x1F11, AF_ADJUST_UP }, /* ἑ */ + { 0x1F12, AF_ADJUST_UP }, /* ἒ */ + { 0x1F13, AF_ADJUST_UP }, /* ἓ */ + { 0x1F14, AF_ADJUST_UP }, /* ἔ */ + { 0x1F15, AF_ADJUST_UP }, /* ἕ */ + + { 0x1F20, AF_ADJUST_UP }, /* ἠ */ + { 0x1F21, AF_ADJUST_UP }, /* ἡ */ + { 0x1F22, AF_ADJUST_UP }, /* ἢ */ + { 0x1F23, AF_ADJUST_UP }, /* ἣ */ + { 0x1F24, AF_ADJUST_UP }, /* ἤ */ + { 0x1F25, AF_ADJUST_UP }, /* ἥ */ + { 0x1F26, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἦ */ + { 0x1F27, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἧ */ + + { 0x1F30, AF_ADJUST_UP }, /* ἰ */ + { 0x1F31, AF_ADJUST_UP }, /* ἱ */ + { 0x1F32, AF_ADJUST_UP }, /* ἲ */ + { 0x1F33, AF_ADJUST_UP }, /* ἳ */ + { 0x1F34, AF_ADJUST_UP }, /* ἴ */ + { 0x1F35, AF_ADJUST_UP }, /* ἵ */ + { 0x1F36, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἶ */ + { 0x1F37, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ἷ */ + + { 0x1F40, AF_ADJUST_UP }, /* ὀ */ + { 0x1F41, AF_ADJUST_UP }, /* ὁ */ + { 0x1F42, AF_ADJUST_UP }, /* ὂ */ + { 0x1F43, AF_ADJUST_UP }, /* ὃ */ + { 0x1F44, AF_ADJUST_UP }, /* ὄ */ + { 0x1F45, AF_ADJUST_UP }, /* ὅ */ + + { 0x1F50, AF_ADJUST_UP }, /* ὐ */ + { 0x1F51, AF_ADJUST_UP }, /* ὑ */ + { 0x1F52, AF_ADJUST_UP }, /* ὒ */ + { 0x1F53, AF_ADJUST_UP }, /* ὓ */ + { 0x1F54, AF_ADJUST_UP }, /* ὔ */ + { 0x1F55, AF_ADJUST_UP }, /* ὕ */ + { 0x1F56, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὖ */ + { 0x1F57, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὗ */ + + { 0x1F60, AF_ADJUST_UP }, /* ὠ */ + { 0x1F61, AF_ADJUST_UP }, /* ὡ */ + { 0x1F62, AF_ADJUST_UP }, /* ὢ */ + { 0x1F63, AF_ADJUST_UP }, /* ὣ */ + { 0x1F64, AF_ADJUST_UP }, /* ὤ */ + { 0x1F65, AF_ADJUST_UP }, /* ὥ */ + { 0x1F66, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὦ */ + { 0x1F67, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ὧ */ + + { 0x1F70, AF_ADJUST_UP }, /* ὰ */ + { 0x1F71, AF_ADJUST_UP }, /* ά */ + { 0x1F72, AF_ADJUST_UP }, /* ὲ */ + { 0x1F73, AF_ADJUST_UP }, /* έ */ + { 0x1F74, AF_ADJUST_UP }, /* ὴ */ + { 0x1F75, AF_ADJUST_UP }, /* ή */ + { 0x1F76, AF_ADJUST_UP }, /* ὶ */ + { 0x1F77, AF_ADJUST_UP }, /* ί */ + { 0x1F78, AF_ADJUST_UP }, /* ὸ */ + { 0x1F79, AF_ADJUST_UP }, /* ό */ + { 0x1F7A, AF_ADJUST_UP }, /* ὺ */ + { 0x1F7B, AF_ADJUST_UP }, /* ύ */ + { 0x1F7C, AF_ADJUST_UP }, /* ὼ */ + { 0x1F7D, AF_ADJUST_UP }, /* ώ */ + + { 0x1F80, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾀ */ + { 0x1F81, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾁ */ + { 0x1F82, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾂ */ + { 0x1F83, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾃ */ + { 0x1F84, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾄ */ + { 0x1F85, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾅ */ + { 0x1F86, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾆ */ + { 0x1F87, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾇ */ + { 0x1F88, AF_ADJUST_DOWN }, /* ᾈ */ + { 0x1F89, AF_ADJUST_DOWN }, /* ᾉ */ + { 0x1F8A, AF_ADJUST_DOWN }, /* ᾊ */ + { 0x1F8B, AF_ADJUST_DOWN }, /* ᾋ */ + { 0x1F8C, AF_ADJUST_DOWN }, /* ᾌ */ + { 0x1F8D, AF_ADJUST_DOWN }, /* ᾍ */ + { 0x1F8E, AF_ADJUST_DOWN }, /* ᾎ */ + { 0x1F8F, AF_ADJUST_DOWN }, /* ᾏ */ + + { 0x1F90, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾐ */ + { 0x1F91, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾑ */ + { 0x1F92, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾒ */ + { 0x1F93, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾓ */ + { 0x1F94, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾔ */ + { 0x1F95, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾕ */ + { 0x1F96, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾖ */ + { 0x1F97, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾗ */ + { 0x1F98, AF_ADJUST_DOWN }, /* ᾘ */ + { 0x1F99, AF_ADJUST_DOWN }, /* ᾙ */ + { 0x1F9A, AF_ADJUST_DOWN }, /* ᾚ */ + { 0x1F9B, AF_ADJUST_DOWN }, /* ᾛ */ + { 0x1F9C, AF_ADJUST_DOWN }, /* ᾜ */ + { 0x1F9D, AF_ADJUST_DOWN }, /* ᾝ */ + { 0x1F9E, AF_ADJUST_DOWN }, /* ᾞ */ + { 0x1F9F, AF_ADJUST_DOWN }, /* ᾟ */ + + { 0x1FA0, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾠ */ + { 0x1FA1, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾡ */ + { 0x1FA2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾢ */ + { 0x1FA3, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾣ */ + { 0x1FA4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾤ */ + { 0x1FA5, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾥ */ + { 0x1FA6, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾦ */ + { 0x1FA7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾧ */ + { 0x1FA8, AF_ADJUST_DOWN }, /* ᾨ */ + { 0x1FA9, AF_ADJUST_DOWN }, /* ᾩ */ + { 0x1FAA, AF_ADJUST_DOWN }, /* ᾪ */ + { 0x1FAB, AF_ADJUST_DOWN }, /* ᾫ */ + { 0x1FAC, AF_ADJUST_DOWN }, /* ᾬ */ + { 0x1FAD, AF_ADJUST_DOWN }, /* ᾭ */ + { 0x1FAE, AF_ADJUST_DOWN }, /* ᾮ */ + { 0x1FAF, AF_ADJUST_DOWN }, /* ᾯ */ + + { 0x1FB0, AF_ADJUST_UP }, /* ᾰ */ + { 0x1FB1, AF_ADJUST_UP }, /* ᾱ */ + { 0x1FB2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾲ */ + { 0x1FB3, AF_ADJUST_DOWN }, /* ᾳ */ + { 0x1FB4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ᾴ */ + { 0x1FB6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ᾶ */ + { 0x1FB7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ᾷ */ + { 0x1FB8, AF_ADJUST_UP }, /* Ᾰ */ + { 0x1FB9, AF_ADJUST_UP }, /* Ᾱ */ + { 0x1FBC, AF_ADJUST_DOWN }, /* ᾼ */ + + { 0x1FC2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῂ */ + { 0x1FC3, AF_ADJUST_DOWN }, /* ῃ */ + { 0x1FC4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῄ */ + { 0x1FC6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῆ */ + { 0x1FC7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῇ */ + { 0x1FCC, AF_ADJUST_DOWN }, /* ῌ */ + + { 0x1FD0, AF_ADJUST_UP }, /* ῐ */ + { 0x1FD1, AF_ADJUST_UP }, /* ῑ */ + { 0x1FD2, AF_ADJUST_UP2 }, /* ῒ */ + { 0x1FD3, AF_ADJUST_UP2 }, /* ΐ */ + { 0x1FD6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῖ */ + { 0x1FD7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῗ */ + { 0x1FD8, AF_ADJUST_UP }, /* Ῐ */ + { 0x1FD9, AF_ADJUST_UP }, /* Ῑ */ + + { 0x1FE0, AF_ADJUST_UP }, /* ῠ */ + { 0x1FE1, AF_ADJUST_UP }, /* ῡ */ + { 0x1FE2, AF_ADJUST_UP2 }, /* ῢ */ + { 0x1FE3, AF_ADJUST_UP2 }, /* ΰ */ + { 0x1FE4, AF_ADJUST_UP }, /* ῤ */ + { 0x1FE5, AF_ADJUST_UP }, /* ῥ */ + { 0x1FE6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῦ */ + { 0x1FE7, AF_ADJUST_UP2 | AF_ADJUST_TILDE_TOP }, /* ῧ */ + { 0x1FE8, AF_ADJUST_UP }, /* Ῠ */ + { 0x1FE9, AF_ADJUST_UP }, /* Ῡ */ + { 0x1FF2, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῲ */ + { 0x1FF3, AF_ADJUST_DOWN }, /* ῳ */ + { 0x1FF4, AF_ADJUST_UP | AF_ADJUST_DOWN }, /* ῴ */ + { 0x1FF6, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP }, /* ῶ */ + { 0x1FF7, AF_ADJUST_UP | AF_ADJUST_TILDE_TOP | AF_ADJUST_DOWN }, /* ῷ */ + { 0x1FFC, AF_ADJUST_DOWN }, /* ῼ */ + + /* General Punctuation */ + { 0x203C, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‼ */ + { 0x203D, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ‽ */ + + { 0x2047, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁇ */ + { 0x2048, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁈ */ + { 0x2049, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⁉ */ + + /* Superscripts and Subscripts */ + { 0x2071, AF_ADJUST_UP }, /* ⁱ */ + + /* Currency Symbols */ + { 0x20AB, AF_ADJUST_DOWN }, /* ₫ */ + + { 0x20C0, AF_ADJUST_DOWN }, /* ⃀ */ + + /* Number Forms */ + { 0x2170, AF_ADJUST_UP }, /* ⅰ */ + { 0x2171, AF_ADJUST_UP }, /* ⅱ */ + { 0x2172, AF_ADJUST_UP }, /* ⅲ */ + { 0x2173, AF_ADJUST_UP }, /* ⅳ */ + { 0x2175, AF_ADJUST_UP }, /* ⅵ */ + { 0x2176, AF_ADJUST_UP }, /* ⅶ */ + { 0x2177, AF_ADJUST_UP }, /* ⅷ */ + { 0x2178, AF_ADJUST_UP }, /* ⅸ */ + { 0x217A, AF_ADJUST_UP }, /* ⅺ */ + { 0x217B, AF_ADJUST_UP }, /* ⅻ */ + + /* Latin Extended-C */ + { 0x2C64, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɽ */ + { 0x2C67, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱨ */ + { 0x2C68, AF_IGNORE_SMALL_BOTTOM } , /* ⱨ */ + { 0x2C69, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱪ */ + { 0x2C6A, AF_IGNORE_SMALL_BOTTOM } , /* ⱪ */ + { 0x2C6B, AF_IGNORE_CAPITAL_BOTTOM } , /* Ⱬ */ + { 0x2C6C, AF_IGNORE_SMALL_BOTTOM } , /* ⱬ */ + { 0x2C6E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɱ */ + + { 0x2C7C, AF_ADJUST_UP }, /* ⱼ */ + { 0x2C7E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ȿ */ + { 0x2C7F, AF_IGNORE_CAPITAL_BOTTOM } , /* Ɀ */ + + /* Coptic */ + { 0x2CC2, AF_ADJUST_UP }, /* Ⳃ */ + { 0x2CC3, AF_ADJUST_UP }, /* ⳃ */ + + /* Supplemental Punctuation */ + { 0x2E18, AF_ADJUST_UP }, /* ⸘ */ + + { 0x2E2E, AF_ADJUST_UP | AF_ADJUST_NO_HEIGHT_CHECK }, /* ⸮ */ + + /* Cyrillic Extended-B */ + { 0xA640, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙁ */ + { 0xA641, AF_IGNORE_SMALL_BOTTOM } , /* ꙁ */ + { 0xA642, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꙃ */ + { 0xA643, AF_IGNORE_SMALL_BOTTOM } , /* ꙃ */ + + { 0xA680, AF_IGNORE_CAPITAL_TOP } , /* Ꚁ */ + { 0xA681, AF_IGNORE_SMALL_TOP } , /* ꚁ */ + { 0xA688, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚉ */ + { 0xA689, AF_IGNORE_SMALL_BOTTOM } , /* ꚉ */ + { 0xA68A, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚋ */ + { 0xA68B, AF_IGNORE_SMALL_BOTTOM } , /* ꚋ */ + { 0xA68E, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚏ */ + { 0xA68F, AF_IGNORE_SMALL_BOTTOM } , /* ꚏ */ + + { 0xA690, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚑ */ + { 0xA691, AF_IGNORE_SMALL_BOTTOM } , /* ꚑ */ + { 0xA696, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꚗ */ + { 0xA697, AF_IGNORE_SMALL_BOTTOM } , /* ꚗ */ + + /* Latin Extended-D */ + { 0xA726, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꜧ */ + { 0xA727, AF_IGNORE_SMALL_BOTTOM } , /* ꜧ */ + + { 0xA756, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝗ */ + { 0xA758, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꝙ */ + + { 0xA771, AF_IGNORE_SMALL_BOTTOM } , /* ꝱ */ + { 0xA772, AF_IGNORE_SMALL_BOTTOM } , /* ꝲ */ + { 0xA773, AF_IGNORE_SMALL_BOTTOM } , /* ꝳ */ + { 0xA774, AF_IGNORE_SMALL_BOTTOM } , /* ꝴ */ + { 0xA776, AF_IGNORE_SMALL_BOTTOM } , /* ꝶ */ + + { 0xA790, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞑ */ + { 0xA791, AF_IGNORE_SMALL_BOTTOM } , /* ꞑ */ + { 0xA794, AF_IGNORE_SMALL_BOTTOM } , /* ꞔ */ + { 0xA795, AF_IGNORE_SMALL_BOTTOM } , /* ꞕ */ + + { 0xA7C0, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟁ */ + { 0xA7C1, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟁ */ + { 0xA7C4, AF_IGNORE_CAPITAL_BOTTOM } , /* Ꞔ */ + { 0xA7C5, AF_IGNORE_CAPITAL_BOTTOM } , /* Ʂ */ + { 0xA7C6, AF_IGNORE_CAPITAL_BOTTOM } , /* Ᶎ */ + { 0xA7CC, AF_IGNORE_CAPITAL_TOP | AF_IGNORE_CAPITAL_BOTTOM }, /* Ꟍ */ + { 0xA7CD, AF_IGNORE_SMALL_TOP | AF_IGNORE_SMALL_BOTTOM }, /* ꟍ */ + + /* Latin Extended-E */ + { 0xAB3C, AF_IGNORE_SMALL_BOTTOM } , /* ꬼ */ + + { 0xAB46, AF_IGNORE_SMALL_BOTTOM } , /* ꭆ */ + + { 0xAB5C, AF_IGNORE_SMALL_BOTTOM } , /* ꭜ */ + + { 0xAB66, AF_IGNORE_SMALL_BOTTOM } , /* ꭦ */ + { 0xAB67, AF_IGNORE_SMALL_BOTTOM } , /* ꭧ */ + }; + + + FT_LOCAL_DEF( FT_UInt32 ) + af_adjustment_database_lookup( FT_UInt32 codepoint ) + { + /* Binary search for database entry */ + FT_Offset low = 0; + FT_Offset high = AF_ADJUSTMENT_DATABASE_LENGTH - 1; + + + while ( high >= low ) + { + FT_Offset mid = ( low + high ) / 2; + FT_UInt32 mid_codepoint = adjustment_database[mid].codepoint; + + + if ( mid_codepoint < codepoint ) + low = mid + 1; + else if ( mid_codepoint > codepoint ) + high = mid - 1; + else + return adjustment_database[mid].flags; + } + + return 0; + } + + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + static FT_Error + add_substitute( FT_Int glyph_idx, + size_t value, + FT_UInt32 codepoint, + FT_Hash reverse_map, + FT_Hash subst_map, + FT_Memory memory ) + { + FT_Error error; + + FT_Int first_substitute = (FT_Int)( value & 0xFFFF ); + + FT_UInt used = reverse_map->used; + + + /* + OpenType features like 'unic' map lowercase letter glyphs to uppercase + forms (and vice versa), which could lead to the use of wrong entries + in the adjustment database. For this reason we don't overwrite, + prioritizing cmap entries. + + XXX Note, however, that this cannot cover all cases since there might + be contradictory entries for glyphs not in the cmap. A possible + solution might be to specially mark pairs of related lowercase and + uppercase characters in the adjustment database that have diacritics + on different vertical sides (for example, U+0122 'Ģ' and U+0123 'ģ'). + The auto-hinter could then perform a topological analysis to do the + right thing. + */ + error = ft_hash_num_insert_no_overwrite( first_substitute, codepoint, + reverse_map, memory ); + if ( error ) + return error; + + if ( reverse_map->used > used ) + { + size_t* subst = ft_hash_num_lookup( first_substitute, subst_map ); + + + if ( subst ) + { + error = add_substitute( first_substitute, *subst, codepoint, + reverse_map, subst_map, memory ); + if ( error ) + return error; + } + } + + /* The remaining substitutes. */ + if ( value & 0xFFFF0000U ) + { + FT_UInt num_substitutes = value >> 16; + + FT_UInt i; + + + for ( i = 1; i <= num_substitutes; i++ ) + { + FT_Int idx = glyph_idx + (FT_Int)( i << 16 ); + size_t* substitute = ft_hash_num_lookup( idx, subst_map ); + + + used = reverse_map->used; + + error = ft_hash_num_insert_no_overwrite( *substitute, + codepoint, + reverse_map, + memory ); + if ( error ) + return error; + + if ( reverse_map->used > used ) + { + size_t* subst = ft_hash_num_lookup( *substitute, subst_map ); + + + if ( subst ) + { + error = add_substitute( *substitute, *subst, codepoint, + reverse_map, subst_map, memory ); + if ( error ) + return error; + } + } + } + } + + return FT_Err_Ok; + } + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + /* Construct a 'reverse cmap' (i.e., a mapping from glyph indices to */ + /* character codes) for all glyphs that an input code point could turn */ + /* into. */ + /* */ + /* If HarfBuzz support is not available, this is the direct inversion */ + /* of the cmap table, otherwise the mapping gets extended with data */ + /* from the 'GSUB' table. */ + FT_LOCAL_DEF( FT_Error ) + af_reverse_character_map_new( FT_Hash *map, + AF_StyleMetrics metrics ) + { + FT_Error error; + + AF_FaceGlobals globals = metrics->globals; + FT_Face face = globals->face; + FT_Memory memory = face->memory; + + FT_CharMap old_charmap; + + FT_UInt32 codepoint; + FT_Offset i; + + + FT_TRACE4(( "af_reverse_character_map_new:" + " building reverse character map (style `%s')\n", + af_style_names[metrics->style_class->style] )); + + /* Search for a unicode charmap. */ + /* If there isn't one, create a blank map. */ + + /* Back up `face->charmap` because `find_unicode_charmap` sets it. */ + old_charmap = face->charmap; + + if ( ( error = find_unicode_charmap( face ) ) ) + goto Exit; + + *map = NULL; + if ( FT_QNEW( *map ) ) + goto Exit; + + error = ft_hash_num_init( *map, memory ); + if ( error ) + goto Exit; + + /* Initialize reverse cmap with data directly from the cmap table. */ + for ( i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ ) + { + FT_Int cmap_glyph; + + + /* + We cannot restrict `codepoint` to character ranges; we have no + control what data the script-specific portion of the GSUB table + actually holds. + + An example is `arial.ttf` version 7.00; in this font, there are + lookups for Cyrillic (lookup 43), Greek (lookup 44), and Latin + (lookup 45) that map capital letter glyphs to small capital glyphs. + It is tempting to expect that script-specific versions of the 'c2sc' + feature only use script-specific lookups. However, this is not the + case in this font: the feature uses all three lookups regardless of + the script. + + The auto-hinter, while assigning glyphs to styles, uses the first + coverage result it encounters for a particular glyph. For example, + if the coverage for Cyrillic is tested before Latin (as is currently + the case), glyphs without a cmap entry that are covered in 'c2sc' + are treated as Cyrillic. + + If we now look at glyph 3498, which is a small-caps version of the + Latin character 'A grave' (U+00C0, glyph 172), we can see that it is + registered as belonging to a Cyrillic style due to the algorithm + just described. As a result, checking only for characters from the + Latin range would miss this glyph; we thus have to test all + character codes in the database. + */ + codepoint = adjustment_database[i].codepoint; + + cmap_glyph = (FT_Int)FT_Get_Char_Index( face, codepoint ); + if ( cmap_glyph == 0 ) + continue; + + error = ft_hash_num_insert( cmap_glyph, codepoint, *map, memory ); + if ( error ) + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + if ( ft_hb_enabled( globals ) ) + { + hb_font_t *hb_font; + hb_face_t *hb_face; + + hb_set_t *gsub_lookups; + hb_script_t script; + + unsigned int script_count = 1; + hb_tag_t script_tags[2] = { HB_TAG_NONE, HB_TAG_NONE }; + + FT_Hash subst_map = NULL; + + hb_codepoint_t idx; + FT_UInt hash_idx; + FT_Int glyph_idx; + size_t value; + + + /* No need to check whether HarfBuzz has allocation issues; */ + /* it continues to work in such cases and simply returns */ + /* 'empty' objects that do nothing. */ + + hb_font = globals->hb_font; + hb_face = hb( font_get_face )( hb_font ); + + gsub_lookups = hb( set_create )(); + + script = af_hb_scripts[metrics->style_class->script]; + + hb( ot_tags_from_script_and_language )( script, NULL, + &script_count, script_tags, + NULL, NULL ); + + /* Compute set of all script-specific GSUB lookups. */ + hb( ot_layout_collect_lookups )( hb_face, + HB_OT_TAG_GSUB, + script_tags, NULL, NULL, + gsub_lookups ); + +#ifdef FT_DEBUG_LEVEL_TRACE + { + FT_Bool have_idx = FALSE; + + + FT_TRACE4(( " GSUB lookups to check:\n" )); + + FT_TRACE4(( " " )); + idx = HB_SET_VALUE_INVALID; + while ( hb( set_next )( gsub_lookups, &idx ) ) + if ( globals->gsub_lookups_single_alternate[idx] ) + { + have_idx = TRUE; + FT_TRACE4(( " %u", idx )); + } + if ( !have_idx ) + FT_TRACE4(( " (none)" )); + FT_TRACE4(( "\n" )); + + FT_TRACE4(( "\n" )); + } +#endif + + if ( FT_QNEW( subst_map ) ) + goto Exit_HarfBuzz; + + error = ft_hash_num_init( subst_map, memory ); + if ( error ) + goto Exit_HarfBuzz; + + idx = HB_SET_VALUE_INVALID; + while ( hb( set_next )( gsub_lookups, &idx ) ) + { + FT_UInt32 offset = globals->gsub_lookups_single_alternate[idx]; + + + /* Put all substitutions into a single hash table. Note that */ + /* the hash values usually contain more than a single character */ + /* code; this can happen if different 'SingleSubst' subtables */ + /* map a given glyph index to different substitutions, or if */ + /* 'AlternateSubst' subtable entries are present. */ + if ( offset ) + af_map_lookup( globals, subst_map, offset ); + } + + /* + Now iterate over the collected substitution data in `subst_map` + (using recursion to resolve one-to-many mappings) and insert the + data into the reverse cmap. + + As an example, suppose we have the following cmap and substitution + data: + + cmap: X -> a + Y -> b + Z -> c + + substitutions: a -> b + b -> c, d + d -> e + + The reverse map now becomes as follows. + + a -> X + b -> Y + c -> Z (via cmap, ignoring mapping from 'b') + d -> Y (via 'b') + e -> Y (via 'b' and 'd') + */ + + hash_idx = 0; + while ( ft_hash_num_iterator( &hash_idx, + &glyph_idx, + &value, + subst_map ) ) + { + size_t* val; + + + /* Ignore keys that do not point to the first substitute. */ + if ( (FT_UInt)glyph_idx & 0xFFFF0000U ) + continue; + + /* Ignore glyph indices that are not related to accents. */ + val = ft_hash_num_lookup( glyph_idx, *map ); + if ( !val ) + continue; + + codepoint = *val; + + error = add_substitute( glyph_idx, value, codepoint, + *map, subst_map, memory ); + if ( error ) + break; + } + + Exit_HarfBuzz: + hb( set_destroy )( gsub_lookups ); + + ft_hash_num_free( subst_map, memory ); + FT_FREE( subst_map ); + + if ( error ) + goto Exit; + } + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + FT_TRACE4(( " reverse character map built successfully" + " with %u entries\n", ( *map )->used )); + +#ifdef FT_DEBUG_LEVEL_TRACE + + { + FT_UInt cnt; + + + FT_TRACE7(( " gidx code flags\n" )); + /* " XXXXX 0xXXXX XXXXXXXXXXX..." */ + FT_TRACE7(( " ------------------------------\n" )); + + for ( cnt = 0; cnt < globals->glyph_count; cnt++ ) + { + size_t* val; + FT_UInt32 adj_type; + + const char* flag_names[] = + { + "up", /* AF_ADJUST_UP */ + "down", /* AF_ADJUST_DOWN */ + "double up", /* AF_ADJUST_UP2 */ + "double down", /* AF_ADJUST_DOWN2 */ + + "top tilde", /* AF_ADJUST_TILDE_TOP */ + "bottom tilde", /* AF_ADJUST_TILDE_BOTTOM */ + "below-top tilde", /* AF_ADJUST_TILDE_TOP2 */ + "above-bottom tilde", /* AF_ADJUST_TILDE_BOTTOM2 */ + + "ignore capital top", /* AF_IGNORE_CAPITAL_TOP */ + "ignore capital bottom", /* AF_IGNORE_CAPITAL_BOTTOM */ + "ignore small top", /* AF_IGNORE_SMALL_TOP */ + "ignore small bottom", /* AF_IGNORE_SMALL_BOTTOM */ + }; + size_t flag_names_size = sizeof ( flag_names ) / sizeof ( char* ); + + char flag_str[256]; + int need_comma; + + size_t j; + + + val = ft_hash_num_lookup( (FT_Int)cnt, *map ); + if ( !val ) + continue; + codepoint = *val; + + adj_type = af_adjustment_database_lookup( codepoint ); + if ( !adj_type ) + continue; + + flag_str[0] = '\0'; + need_comma = 0; + + for ( j = 0; j < flag_names_size; j++ ) + { + if ( adj_type & (1 << j ) ) + { + if ( !need_comma ) + need_comma = 1; + else + strcat( flag_str, ", " ); + strcat( flag_str, flag_names[j] ); + } + } + + FT_TRACE7(( " %5u 0x%04X %s\n", cnt, codepoint, flag_str )); + } + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + Exit: + face->charmap = old_charmap; + + if ( error ) + { + FT_TRACE4(( " error while building reverse character map." + " Using blank map.\n" )); + + if ( *map ) + ft_hash_num_free( *map, memory ); + + FT_FREE( *map ); + *map = NULL; + return error; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + af_reverse_character_map_done( FT_Hash map, + FT_Memory memory ) + { + if ( map ) + ft_hash_num_free( map, memory ); + FT_FREE( map ); + + return FT_Err_Ok; + } + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afadjust.h b/src/thirdparty/freetype2/src/autofit/afadjust.h new file mode 100644 index 000000000..4837451ae --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afadjust.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * afadjust.h + * + * Auto-fitter routines to adjust components based on charcode (header). + * + * Copyright (C) 2023-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Craig White . + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 AFADJUST_H_ +#define AFADJUST_H_ + +#include + +#include "afglobal.h" +#include "aftypes.h" + + +FT_BEGIN_HEADER + + /* + * Adjustment type flags. + * + * They also specify topological constraints that the auto-hinter relies + * on. For example, using `AF_ADJUST_UP` implies that we have two + * enclosing contours, one for the base glyph and one for the diacritic + * above, and no other contour inbetween or above. With 'enclosing' it is + * meant that such a contour can contain more inner contours. + * + */ + + /* Find the topmost contour and push it up until its lowest point is */ + /* one pixel above the highest point not enclosed by that contour. */ +#define AF_ADJUST_UP 0x01 + + /* Find the bottommost contour and push it down until its highest point */ + /* is one pixel below the lowest point not enclosed by that contour. */ +#define AF_ADJUST_DOWN 0x02 + + /* Find the contour below the topmost contour and push it up, together */ + /* with the topmost contour, until its lowest point is one pixel above */ + /* the highest point not enclosed by that contour. This flag is */ + /* mutually exclusive with `AF_ADJUST_UP`. */ +#define AF_ADJUST_UP2 0x04 + + /* Find the contour above the bottommost contour and push it down, */ + /* together with the bottommost contour, until its highest point is */ + /* one pixel below the lowest point not enclosed by that contour. */ + /* This flag is mutually exclusive with `AF_ADJUST_DOWN`. */ +#define AF_ADJUST_DOWN2 0x08 + + /* The topmost contour is a tilde. Enlarge it vertically so that it */ + /* stays legible at small sizes, not degenerating to a horizontal line. */ +#define AF_ADJUST_TILDE_TOP 0x10 + + /* The bottommost contour is a tilde. Enlarge it vertically so that it */ + /* stays legible at small sizes, not degenerating to a horizontal line. */ +#define AF_ADJUST_TILDE_BOTTOM 0x20 + + /* The contour below the topmost contour is a tilde. Enlarge it */ + /* vertically so that it stays legible at small sizes, not degenerating */ + /* to a horizontal line. To be used with `AF_ADJUST_UP2` only. */ +#define AF_ADJUST_TILDE_TOP2 0x40 + + /* The contour above the bottommost contour is a tilde. Enlarge it */ + /* vertically so that it stays legible at small sizes, not degenerating */ + /* to a horizontal line. To be used with `AF_ADJUST_DOWN2` only. */ +#define AF_ADJUST_TILDE_BOTTOM2 0x80 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the top */ + /* of an uppercase base character. */ +#define AF_IGNORE_CAPITAL_TOP 0x100 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the */ + /* bottom of an uppercase base character. */ +#define AF_IGNORE_CAPITAL_BOTTOM 0x200 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the top */ + /* of a lowercase base character. */ +#define AF_IGNORE_SMALL_TOP 0x400 + + /* Make the auto-hinter ignore any diacritic (either a separate contour */ + /* or part of the base character outline) that is attached to the */ + /* bottom of a lowercase base character. */ +#define AF_IGNORE_SMALL_BOTTOM 0x800 + + /* By default, the AF_ADJUST_XXX flags are applied only if diacritics */ + /* have a 'small' height (based on some heuristic checks). If this */ + /* flag is set, no such check is performed. */ +#define AF_ADJUST_NO_HEIGHT_CHECK 0x1000 + + /* No adjustment, i.e., no flag is set. */ +#define AF_ADJUST_NONE 0x00 + + + FT_LOCAL( FT_UInt32 ) + af_adjustment_database_lookup( FT_UInt32 codepoint ); + + /* Allocate and populate the reverse character map, */ + /* using the character map within the face. */ + FT_LOCAL( FT_Error ) + af_reverse_character_map_new( FT_Hash *map, + AF_StyleMetrics metrics ); + + /* Free the reverse character map. */ + FT_LOCAL( FT_Error ) + af_reverse_character_map_done( FT_Hash map, + FT_Memory memory ); + + +FT_END_HEADER + +#endif /* AFADJUST_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afangles.c b/src/thirdparty/freetype2/src/autofit/afangles.c deleted file mode 100644 index 9e1f7a21f..000000000 --- a/src/thirdparty/freetype2/src/autofit/afangles.c +++ /dev/null @@ -1,285 +0,0 @@ -/**************************************************************************** - * - * afangles.c - * - * Routines used to compute vector angles with limited accuracy - * and very high speed. It also contains sorting routines (body). - * - * Copyright (C) 2003-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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" - - - /* - * 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_and_quantize_widths( FT_UInt* count, - AF_Width table, - FT_Pos threshold ) - { - FT_UInt i, j; - FT_UInt cur_idx; - FT_Pos cur_val; - FT_Pos sum; - AF_WidthRec swap; - - - if ( *count == 1 ) - return; - - /* sort */ - 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; - } - } - - cur_idx = 0; - cur_val = table[cur_idx].org; - - /* compute and use mean values for clusters not larger than */ - /* `threshold'; this is very primitive and might not yield */ - /* the best result, but normally, using reference character */ - /* `o', `*count' is 2, so the code below is fully sufficient */ - for ( i = 1; i < *count; i++ ) - { - if ( table[i].org - cur_val > threshold || - i == *count - 1 ) - { - sum = 0; - - /* fix loop for end of array */ - if ( table[i].org - cur_val <= threshold && - i == *count - 1 ) - i++; - - for ( j = cur_idx; j < i; j++ ) - { - sum += table[j].org; - table[j].org = 0; - } - table[cur_idx].org = sum / (FT_Pos)j; - - if ( i < *count - 1 ) - { - cur_idx = i + 1; - cur_val = table[cur_idx].org; - } - } - } - - cur_idx = 1; - - /* compress array to remove zero values */ - for ( i = 1; i < *count; i++ ) - { - if ( table[i].org ) - table[cur_idx++] = table[i]; - } - - *count = cur_idx; - } - - -/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afangles.h b/src/thirdparty/freetype2/src/autofit/afangles.h deleted file mode 100644 index 18d7dae3a..000000000 --- a/src/thirdparty/freetype2/src/autofit/afangles.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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/thirdparty/freetype2/src/autofit/afblue.c b/src/thirdparty/freetype2/src/autofit/afblue.c index b99dbeb19..a6219bdfe 100644 --- a/src/thirdparty/freetype2/src/autofit/afblue.c +++ b/src/thirdparty/freetype2/src/autofit/afblue.c @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -134,7 +134,7 @@ '\0', '\xF0', '\x90', '\x90', '\xA8', ' ', '\xF0', '\x90', '\x90', '\xAA', ' ', '\xF0', '\x90', '\x90', '\xAC', ' ', '\xF0', '\x90', '\x90', '\xBF', ' ', '\xF0', '\x90', '\x91', '\x83', /* 𐐨 𐐪 𐐬 𐐿 𐑃 */ '\0', - '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x85', ' ', '\xE0', '\xA4', '\x86', ' ', '\xE0', '\xA4', '\xA5', ' ', '\xE0', '\xA4', '\xA7', ' ', '\xE0', '\xA4', '\xAD', ' ', '\xE0', '\xA4', '\xB6', /* क म अ आ थ ध भ श */ + '\xE0', '\xA4', '\x95', ' ', '\xE0', '\xA4', '\xA8', ' ', '\xE0', '\xA4', '\xAE', ' ', '\xE0', '\xA4', '\x89', ' ', '\xE0', '\xA4', '\x9B', ' ', '\xE0', '\xA4', '\x9F', ' ', '\xE0', '\xA4', '\xA0', ' ', '\xE0', '\xA4', '\xA1', /* क न म उ छ ट ठ ड */ '\0', '\xE0', '\xA4', '\x88', ' ', '\xE0', '\xA4', '\x90', ' ', '\xE0', '\xA4', '\x93', ' ', '\xE0', '\xA4', '\x94', ' ', '\xE0', '\xA4', '\xBF', ' ', '\xE0', '\xA5', '\x80', ' ', '\xE0', '\xA5', '\x8B', ' ', '\xE0', '\xA5', '\x8C', /* ई ऐ ओ औ ि ी ो ौ */ '\0', @@ -296,6 +296,20 @@ '\0', '\xE0', '\xB4', '\x9F', ' ', '\xE0', '\xB4', '\xA0', ' ', '\xE0', '\xB4', '\xA7', ' ', '\xE0', '\xB4', '\xB6', ' ', '\xE0', '\xB4', '\x98', ' ', '\xE0', '\xB4', '\x9A', ' ', '\xE0', '\xB4', '\xA5', ' ', '\xE0', '\xB4', '\xB2', /* ട ഠ ധ ശ ഘ ച ഥ ല */ '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x9F', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹟 */ + '\0', + '\xF0', '\x96', '\xB9', '\x80', ' ', '\xF0', '\x96', '\xB9', '\x81', ' ', '\xF0', '\x96', '\xB9', '\x82', ' ', '\xF0', '\x96', '\xB9', '\x83', ' ', '\xF0', '\x96', '\xB9', '\x8F', ' ', '\xF0', '\x96', '\xB9', '\x9A', ' ', '\xF0', '\x96', '\xB9', '\x92', ' ', '\xF0', '\x96', '\xB9', '\x93', /* 𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹒 𖹓 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA4', ' ', '\xF0', '\x96', '\xB9', '\xAC', ' ', '\xF0', '\x96', '\xB9', '\xA7', ' ', '\xF0', '\x96', '\xB9', '\xB4', ' ', '\xF0', '\x96', '\xB9', '\xB6', ' ', '\xF0', '\x96', '\xB9', '\xBE', /* 𖹤 𖹬 𖹧 𖹴 𖹶 𖹾 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB9', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAE', /* 𖹠 𖹡 𖹢 𖹹 𖹳 𖹮 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA0', ' ', '\xF0', '\x96', '\xB9', '\xA1', ' ', '\xF0', '\x96', '\xB9', '\xA2', ' ', '\xF0', '\x96', '\xB9', '\xB3', ' ', '\xF0', '\x96', '\xB9', '\xAD', ' ', '\xF0', '\x96', '\xB9', '\xBD', /* 𖹠 𖹡 𖹢 𖹳 𖹭 𖹽 */ + '\0', + '\xF0', '\x96', '\xB9', '\xA5', ' ', '\xF0', '\x96', '\xB9', '\xA8', ' ', '\xF0', '\x96', '\xB9', '\xA9', /* 𖹥 𖹨 𖹩 */ + '\0', + '\xF0', '\x96', '\xBA', '\x80', ' ', '\xF0', '\x96', '\xBA', '\x85', ' ', '\xF0', '\x96', '\xBA', '\x88', ' ', '\xF0', '\x96', '\xBA', '\x84', ' ', '\xF0', '\x96', '\xBA', '\x8D', /* 𖺀 𖺅 𖺈 𖺄 𖺍 */ + '\0', '\xE1', '\xA0', '\xB3', ' ', '\xE1', '\xA0', '\xB4', ' ', '\xE1', '\xA0', '\xB6', ' ', '\xE1', '\xA0', '\xBD', ' ', '\xE1', '\xA1', '\x82', ' ', '\xE1', '\xA1', '\x8A', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xA1', '\xE2', '\x80', '\x8D', ' ', '\xE2', '\x80', '\x8D', '\xE1', '\xA1', '\xB3', '\xE2', '\x80', '\x8D', /* ᠳ ᠴ ᠶ ᠽ ᡂ ᡊ ‍ᡡ‍ ‍ᡳ‍ */ '\0', '\xE1', '\xA1', '\x83', /* ᡃ */ @@ -340,6 +354,12 @@ '\0', '\xF0', '\x90', '\x92', '\x80', ' ', '\xF0', '\x90', '\x92', '\x82', ' ', '\xF0', '\x90', '\x92', '\x86', ' ', '\xF0', '\x90', '\x92', '\x88', ' ', '\xF0', '\x90', '\x92', '\x8A', ' ', '\xF0', '\x90', '\x92', '\x92', ' ', '\xF0', '\x90', '\x92', '\xA0', ' ', '\xF0', '\x90', '\x92', '\xA9', /* 𐒀 𐒂 𐒆 𐒈 𐒊 𐒒 𐒠 𐒩 */ '\0', + '\xF0', '\x90', '\xB4', '\x83', ' ', '\xF0', '\x90', '\xB4', '\x80', ' ', '\xF0', '\x90', '\xB4', '\x86', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', /* 𐴃 𐴀 𐴆 𐴖 𐴕 */ + '\0', + '\xF0', '\x90', '\xB4', '\x94', ' ', '\xF0', '\x90', '\xB4', '\x96', ' ', '\xF0', '\x90', '\xB4', '\x95', ' ', '\xF0', '\x90', '\xB4', '\x91', ' ', '\xF0', '\x90', '\xB4', '\x90', /* 𐴔 𐴖 𐴕 𐴑 𐴐 */ + '\0', + '\xD9', '\x80', /* ـ */ + '\0', '\xEA', '\xA2', '\x9C', ' ', '\xEA', '\xA2', '\x9E', ' ', '\xEA', '\xA2', '\xB3', ' ', '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\x96', ' ', '\xEA', '\xA2', '\x92', ' ', '\xEA', '\xA2', '\x9D', ' ', '\xEA', '\xA2', '\x9B', /* ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ꢝ ꢛ */ '\0', '\xEA', '\xA2', '\x82', ' ', '\xEA', '\xA2', '\xA8', ' ', '\xEA', '\xA2', '\xBA', ' ', '\xEA', '\xA2', '\xA4', ' ', '\xEA', '\xA2', '\x8E', /* ꢂ ꢨ ꢺ ꢤ ꢎ */ @@ -447,24 +467,24 @@ af_blue_stringsets[] = { /* */ - { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ARABIC_BOTTOM, 0 }, { AF_BLUE_STRING_ARABIC_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_AVESTAN_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -488,14 +508,14 @@ { AF_BLUE_STRING_CHAKMA_BOTTOM, 0 }, { AF_BLUE_STRING_CHAKMA_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CARIAN_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -507,24 +527,24 @@ { AF_BLUE_STRING_CHEROKEE_SMALL, 0 }, { AF_BLUE_STRING_CHEROKEE_SMALL_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CYPRIOT_BOTTOM, 0 }, { AF_BLUE_STRING_CYPRIOT_SMALL, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_CYPRIOT_SMALL, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, - { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 }, + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_DEVANAGARI_HEAD, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_DEVANAGARI_BASE, AF_BLUE_PROPERTY_LATIN_TOP | @@ -533,12 +553,12 @@ { AF_BLUE_STRING_DEVANAGARI_BASE, 0 }, { AF_BLUE_STRING_DEVANAGARI_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_ETHIOPIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -558,23 +578,23 @@ { AF_BLUE_STRING_GEORGIAN_NUSKHURI_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GEORGIAN_NUSKHURI_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GOTHIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_GREEK_SMALL, 0 }, - { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_GREEK_SMALL, 0 }, + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_GUJARATI_BOTTOM, 0 }, @@ -595,6 +615,9 @@ { AF_BLUE_STRING_HEBREW_BOTTOM, 0 }, { AF_BLUE_STRING_HEBREW_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_KAYAH_LI_BOTTOM, 0 }, @@ -613,9 +636,6 @@ AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_KANNADA_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_LAO_BOTTOM, 0 }, @@ -623,36 +643,45 @@ { AF_BLUE_STRING_LAO_LARGE_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LAO_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, - { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, - { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 }, + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_LISU_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MALAYALAM_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 }, { AF_BLUE_STRING_MAX, 0 }, @@ -662,12 +691,12 @@ { AF_BLUE_STRING_MYANMAR_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_MYANMAR_DESCENDER, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_NKO_BOTTOM, 0 }, + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_NKO_BOTTOM, 0 }, { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_OL_CHIKI, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OL_CHIKI, 0 }, @@ -675,28 +704,32 @@ { AF_BLUE_STRING_OLD_TURKIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OLD_TURKIC_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 }, - { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, - { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM }, + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 }, + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 }, + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, - { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 }, + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 }, { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, - { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 }, - { AF_BLUE_STRING_MAX, 0 }, + AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_SINHALA_BOTTOM, 0 }, { AF_BLUE_STRING_SINHALA_DESCENDER, 0 }, @@ -714,9 +747,6 @@ { AF_BLUE_STRING_TELUGU_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_TELUGU_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, - { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP }, - { AF_BLUE_STRING_TIFINAGH, 0 }, - { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT }, { AF_BLUE_STRING_THAI_BOTTOM, 0 }, @@ -726,6 +756,9 @@ { AF_BLUE_STRING_THAI_LARGE_DESCENDER, 0 }, { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 }, { AF_BLUE_STRING_MAX, 0 }, + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP }, + { AF_BLUE_STRING_TIFINAGH, 0 }, + { AF_BLUE_STRING_MAX, 0 }, { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP }, { AF_BLUE_STRING_VAI_BOTTOM, 0 }, { AF_BLUE_STRING_MAX, 0 }, diff --git a/src/thirdparty/freetype2/src/autofit/afblue.cin b/src/thirdparty/freetype2/src/autofit/afblue.cin index 6545d1fd4..786c6b3b9 100644 --- a/src/thirdparty/freetype2/src/autofit/afblue.cin +++ b/src/thirdparty/freetype2/src/autofit/afblue.cin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/afblue.dat b/src/thirdparty/freetype2/src/autofit/afblue.dat index 46db43fe2..f6e96ff81 100644 --- a/src/thirdparty/freetype2/src/autofit/afblue.dat +++ b/src/thirdparty/freetype2/src/autofit/afblue.dat @@ -2,7 +2,7 @@ // // Auto-fitter data for blue strings. // -// Copyright (C) 2013-2019 by +// Copyright (C) 2013-2025 by // David Turner, Robert Wilhelm, and Werner Lemberg. // // This file is part of the FreeType project, and may only be used, @@ -89,7 +89,7 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: "ت ث ط ظ ك" // We don't necessarily have access to medial forms via Unicode in case // Arabic presentational forms are missing. The only character that is - // guaranteed to have the same vertical position with joining (this is, + // guaranteed to have the same vertical position with joining (that is, // non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both // round and flat curves. AF_BLUE_STRING_ARABIC_JOIN @@ -203,7 +203,7 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: "𐐨 𐐪 𐐬 𐐿 𐑃" AF_BLUE_STRING_DEVANAGARI_BASE - "क म अ आ थ ध भ श" + "क न म उ छ ट ठ ड" AF_BLUE_STRING_DEVANAGARI_TOP "ई ऐ ओ औ ि ी ो ौ" // note that some fonts have extreme variation in the height of the @@ -392,6 +392,21 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: AF_BLUE_STRING_MALAYALAM_BOTTOM "ട ഠ ധ ശ ഘ ച ഥ ല" + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP + "𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹟" + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM + "𖹀 𖹁 𖹂 𖹃 𖹏 𖹚 𖹒 𖹓" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP + "𖹤 𖹬 𖹧 𖹴 𖹶 𖹾" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP + "𖹠 𖹡 𖹢 𖹹 𖹳 𖹮" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM + "𖹠 𖹡 𖹢 𖹳 𖹭 𖹽" + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER + "𖹥 𖹨 𖹩" + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP + "𖺀 𖺅 𖺈 𖺄 𖺍" + AF_BLUE_STRING_MONGOLIAN_TOP_BASE "ᠳ ᠴ ᠶ ᠽ ᡂ ᡊ ‍ᡡ‍ ‍ᡳ‍" AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE @@ -443,6 +458,13 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: AF_BLUE_STRING_OSMANYA_BOTTOM "𐒀 𐒂 𐒆 𐒈 𐒊 𐒒 𐒠 𐒩" + AF_BLUE_STRING_ROHINGYA_TOP + "𐴃 𐴀 𐴆 𐴖 𐴕" + AF_BLUE_STRING_ROHINGYA_BOTTOM + "𐴔 𐴖 𐴕 𐴑 𐴐" + AF_BLUE_STRING_ROHINGYA_JOIN + "ـ" + AF_BLUE_STRING_SAURASHTRA_TOP "ꢜ ꢞ ꢳ ꢂ ꢖ ꢒ ꢝ ꢛ" AF_BLUE_STRING_SAURASHTRA_BOTTOM @@ -677,12 +699,12 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN: AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: AF_BLUE_STRINGSET_ADLM - { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_ADLAM_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ADLAM_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_ADLAM_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ADLAM_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ARAB { AF_BLUE_STRING_ARABIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -691,14 +713,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ARMN - { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ARMENIAN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_ARMENIAN_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_ARMENIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_ARMENIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_ARMENIAN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_AVST { AF_BLUE_STRING_AVESTAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -734,14 +756,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CANS - { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_BOTTOM, 0 } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CANADIAN_SYLLABICS_SUPS_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CARI { AF_BLUE_STRING_CARIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -759,12 +781,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_COPT - { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_COPTIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_COPTIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_COPTIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_COPTIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CPRT { AF_BLUE_STRING_CYPRIOT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -774,13 +796,13 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_CYRL - { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_CYRILLIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_CYRILLIC_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } - { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_CYRILLIC_SMALL, 0 } + { AF_BLUE_STRING_CYRILLIC_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_DEVA { AF_BLUE_STRING_DEVANAGARI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -793,12 +815,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_DSRT - { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_DESERET_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_DESERET_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_DESERET_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_DESERET_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_ETHI { AF_BLUE_STRING_ETHIOPIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -826,12 +848,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GLAG - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, 0 } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GLAGOLITIC_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } { AF_BLUE_STRING_GLAGOLITIC_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GLAGOLITIC_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GOTH { AF_BLUE_STRING_GOTHIC_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -839,14 +861,14 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GREK - { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_GREEK_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_GREEK_SMALL_BETA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_GREEK_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_GREEK_SMALL, 0 } - { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_GREEK_SMALL, 0 } + { AF_BLUE_STRING_GREEK_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_GUJR { AF_BLUE_STRING_GUJARATI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | @@ -874,6 +896,11 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_HEBREW_DESCENDER, 0 } { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_KNDA + { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_KANNADA_BOTTOM, 0 } + { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_KALI { AF_BLUE_STRING_KAYAH_LI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT } @@ -898,11 +925,6 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_KHMER_SYMBOLS_WANING_BOTTOM, 0 } { AF_BLUE_STRING_MAX, 0 } - AF_BLUE_STRINGSET_KNDA - { AF_BLUE_STRING_KANNADA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_KANNADA_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } - AF_BLUE_STRINGSET_LAO { AF_BLUE_STRING_LAO_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT } @@ -913,34 +935,34 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATN - { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_LATIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATB - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUBS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SUBS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } - { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUBS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUBS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LATP - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_LATIN_SUPS_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_LATIN_SUPS_SMALL, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } - { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_LATIN_SUPS_SMALL, 0 } + { AF_BLUE_STRING_LATIN_SUPS_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_LISU { AF_BLUE_STRING_LISU_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -952,6 +974,17 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MALAYALAM_BOTTOM, 0 } { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_MEDF + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_MONG { AF_BLUE_STRING_MONGOLIAN_TOP_BASE, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE, 0 } @@ -966,12 +999,12 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_NKOO - { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_NKO_BOTTOM, 0 } + { AF_BLUE_STRING_NKO_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_NKO_BOTTOM, 0 } { AF_BLUE_STRING_NKO_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_NKO_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_NKO_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_NONE { AF_BLUE_STRING_MAX, 0 } @@ -987,34 +1020,40 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_OSGE - { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, 0 } - { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } - { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } - { AF_BLUE_STRING_MAX, 0 } + { AF_BLUE_STRING_OSAGE_CAPITAL_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM, AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM } + { AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER, 0 } + { AF_BLUE_STRING_OSAGE_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_OSAGE_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_OSAGE_SMALL_ASCENDER, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_OSAGE_SMALL_DESCENDER, 0 } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_OSMA { AF_BLUE_STRING_OSMANYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_OSMANYA_BOTTOM, 0 } { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_ROHG + { AF_BLUE_STRING_ROHINGYA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_ROHINGYA_BOTTOM, 0 } + { AF_BLUE_STRING_ROHINGYA_JOIN, AF_BLUE_PROPERTY_LATIN_NEUTRAL } + { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_SAUR { AF_BLUE_STRING_SAURASHTRA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_SAURASHTRA_BOTTOM, 0 } { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_SHAW - { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } - { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } + { AF_BLUE_STRING_SHAVIAN_TOP, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_SHAVIAN_BOTTOM, 0 } + { AF_BLUE_STRING_SHAVIAN_DESCENDER, 0 } { AF_BLUE_STRING_SHAVIAN_SMALL_TOP, AF_BLUE_PROPERTY_LATIN_TOP | - AF_BLUE_PROPERTY_LATIN_X_HEIGHT } - { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, 0 } - { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_PROPERTY_LATIN_X_HEIGHT } + { AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM, AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM } + { AF_BLUE_STRING_MAX, 0 } AF_BLUE_STRINGSET_SINH { AF_BLUE_STRING_SINHALA_TOP, AF_BLUE_PROPERTY_LATIN_TOP } @@ -1043,11 +1082,6 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_TELUGU_BOTTOM, 0 } { AF_BLUE_STRING_MAX, 0 } - AF_BLUE_STRINGSET_TFNG - { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP } - { AF_BLUE_STRING_TIFINAGH, 0 } - { AF_BLUE_STRING_MAX, 0 } - AF_BLUE_STRINGSET_THAI { AF_BLUE_STRING_THAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP | AF_BLUE_PROPERTY_LATIN_X_HEIGHT } @@ -1059,6 +1093,11 @@ AF_BLUE_STRINGSET_ENUM AF_BLUE_STRINGSETS_ARRAY AF_BLUE_STRINGSET_MAX_LEN: { AF_BLUE_STRING_THAI_DIGIT_TOP, 0 } { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_TFNG + { AF_BLUE_STRING_TIFINAGH, AF_BLUE_PROPERTY_LATIN_TOP } + { AF_BLUE_STRING_TIFINAGH, 0 } + { AF_BLUE_STRING_MAX, 0 } + AF_BLUE_STRINGSET_VAII { AF_BLUE_STRING_VAI_TOP, AF_BLUE_PROPERTY_LATIN_TOP } { AF_BLUE_STRING_VAI_BOTTOM, 0 } diff --git a/src/thirdparty/freetype2/src/autofit/afblue.h b/src/thirdparty/freetype2/src/autofit/afblue.h index b69b1df52..5bb8406dc 100644 --- a/src/thirdparty/freetype2/src/autofit/afblue.h +++ b/src/thirdparty/freetype2/src/autofit/afblue.h @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -212,58 +212,68 @@ FT_BEGIN_HEADER AF_BLUE_STRING_LISU_BOTTOM = 3506, AF_BLUE_STRING_MALAYALAM_TOP = 3538, AF_BLUE_STRING_MALAYALAM_BOTTOM = 3582, - AF_BLUE_STRING_MONGOLIAN_TOP_BASE = 3614, - AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE = 3658, - AF_BLUE_STRING_MYANMAR_TOP = 3662, - AF_BLUE_STRING_MYANMAR_BOTTOM = 3694, - AF_BLUE_STRING_MYANMAR_ASCENDER = 3726, - AF_BLUE_STRING_MYANMAR_DESCENDER = 3754, - AF_BLUE_STRING_NKO_TOP = 3786, - AF_BLUE_STRING_NKO_BOTTOM = 3810, - AF_BLUE_STRING_NKO_SMALL_TOP = 3825, - AF_BLUE_STRING_NKO_SMALL_BOTTOM = 3834, - AF_BLUE_STRING_OL_CHIKI = 3846, - AF_BLUE_STRING_OLD_TURKIC_TOP = 3870, - AF_BLUE_STRING_OLD_TURKIC_BOTTOM = 3885, - AF_BLUE_STRING_OSAGE_CAPITAL_TOP = 3905, - AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM = 3945, - AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER = 3975, - AF_BLUE_STRING_OSAGE_SMALL_TOP = 3990, - AF_BLUE_STRING_OSAGE_SMALL_BOTTOM = 4030, - AF_BLUE_STRING_OSAGE_SMALL_ASCENDER = 4070, - AF_BLUE_STRING_OSAGE_SMALL_DESCENDER = 4095, - AF_BLUE_STRING_OSMANYA_TOP = 4110, - AF_BLUE_STRING_OSMANYA_BOTTOM = 4150, - AF_BLUE_STRING_SAURASHTRA_TOP = 4190, - AF_BLUE_STRING_SAURASHTRA_BOTTOM = 4222, - AF_BLUE_STRING_SHAVIAN_TOP = 4242, - AF_BLUE_STRING_SHAVIAN_BOTTOM = 4252, - AF_BLUE_STRING_SHAVIAN_DESCENDER = 4277, - AF_BLUE_STRING_SHAVIAN_SMALL_TOP = 4287, - AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM = 4322, - AF_BLUE_STRING_SINHALA_TOP = 4337, - AF_BLUE_STRING_SINHALA_BOTTOM = 4369, - AF_BLUE_STRING_SINHALA_DESCENDER = 4401, - AF_BLUE_STRING_SUNDANESE_TOP = 4445, - AF_BLUE_STRING_SUNDANESE_BOTTOM = 4469, - AF_BLUE_STRING_SUNDANESE_DESCENDER = 4501, - AF_BLUE_STRING_TAI_VIET_TOP = 4509, - AF_BLUE_STRING_TAI_VIET_BOTTOM = 4529, - AF_BLUE_STRING_TAMIL_TOP = 4541, - AF_BLUE_STRING_TAMIL_BOTTOM = 4573, - AF_BLUE_STRING_TELUGU_TOP = 4605, - AF_BLUE_STRING_TELUGU_BOTTOM = 4633, - AF_BLUE_STRING_THAI_TOP = 4661, - AF_BLUE_STRING_THAI_BOTTOM = 4685, - AF_BLUE_STRING_THAI_ASCENDER = 4713, - AF_BLUE_STRING_THAI_LARGE_ASCENDER = 4725, - AF_BLUE_STRING_THAI_DESCENDER = 4737, - AF_BLUE_STRING_THAI_LARGE_DESCENDER = 4753, - AF_BLUE_STRING_THAI_DIGIT_TOP = 4761, - AF_BLUE_STRING_TIFINAGH = 4773, - AF_BLUE_STRING_VAI_TOP = 4805, - AF_BLUE_STRING_VAI_BOTTOM = 4837, - af_blue_1_1 = 4868, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_TOP = 3614, + AF_BLUE_STRING_MEDEFAIDRIN_CAPITAL_BOTTOM = 3649, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_F_TOP = 3689, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_TOP = 3719, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_BOTTOM = 3749, + AF_BLUE_STRING_MEDEFAIDRIN_SMALL_DESCENDER = 3779, + AF_BLUE_STRING_MEDEFAIDRIN_DIGIT_TOP = 3794, + AF_BLUE_STRING_MONGOLIAN_TOP_BASE = 3819, + AF_BLUE_STRING_MONGOLIAN_BOTTOM_BASE = 3863, + AF_BLUE_STRING_MYANMAR_TOP = 3867, + AF_BLUE_STRING_MYANMAR_BOTTOM = 3899, + AF_BLUE_STRING_MYANMAR_ASCENDER = 3931, + AF_BLUE_STRING_MYANMAR_DESCENDER = 3959, + AF_BLUE_STRING_NKO_TOP = 3991, + AF_BLUE_STRING_NKO_BOTTOM = 4015, + AF_BLUE_STRING_NKO_SMALL_TOP = 4030, + AF_BLUE_STRING_NKO_SMALL_BOTTOM = 4039, + AF_BLUE_STRING_OL_CHIKI = 4051, + AF_BLUE_STRING_OLD_TURKIC_TOP = 4075, + AF_BLUE_STRING_OLD_TURKIC_BOTTOM = 4090, + AF_BLUE_STRING_OSAGE_CAPITAL_TOP = 4110, + AF_BLUE_STRING_OSAGE_CAPITAL_BOTTOM = 4150, + AF_BLUE_STRING_OSAGE_CAPITAL_DESCENDER = 4180, + AF_BLUE_STRING_OSAGE_SMALL_TOP = 4195, + AF_BLUE_STRING_OSAGE_SMALL_BOTTOM = 4235, + AF_BLUE_STRING_OSAGE_SMALL_ASCENDER = 4275, + AF_BLUE_STRING_OSAGE_SMALL_DESCENDER = 4300, + AF_BLUE_STRING_OSMANYA_TOP = 4315, + AF_BLUE_STRING_OSMANYA_BOTTOM = 4355, + AF_BLUE_STRING_ROHINGYA_TOP = 4395, + AF_BLUE_STRING_ROHINGYA_BOTTOM = 4420, + AF_BLUE_STRING_ROHINGYA_JOIN = 4445, + AF_BLUE_STRING_SAURASHTRA_TOP = 4448, + AF_BLUE_STRING_SAURASHTRA_BOTTOM = 4480, + AF_BLUE_STRING_SHAVIAN_TOP = 4500, + AF_BLUE_STRING_SHAVIAN_BOTTOM = 4510, + AF_BLUE_STRING_SHAVIAN_DESCENDER = 4535, + AF_BLUE_STRING_SHAVIAN_SMALL_TOP = 4545, + AF_BLUE_STRING_SHAVIAN_SMALL_BOTTOM = 4580, + AF_BLUE_STRING_SINHALA_TOP = 4595, + AF_BLUE_STRING_SINHALA_BOTTOM = 4627, + AF_BLUE_STRING_SINHALA_DESCENDER = 4659, + AF_BLUE_STRING_SUNDANESE_TOP = 4703, + AF_BLUE_STRING_SUNDANESE_BOTTOM = 4727, + AF_BLUE_STRING_SUNDANESE_DESCENDER = 4759, + AF_BLUE_STRING_TAI_VIET_TOP = 4767, + AF_BLUE_STRING_TAI_VIET_BOTTOM = 4787, + AF_BLUE_STRING_TAMIL_TOP = 4799, + AF_BLUE_STRING_TAMIL_BOTTOM = 4831, + AF_BLUE_STRING_TELUGU_TOP = 4863, + AF_BLUE_STRING_TELUGU_BOTTOM = 4891, + AF_BLUE_STRING_THAI_TOP = 4919, + AF_BLUE_STRING_THAI_BOTTOM = 4943, + AF_BLUE_STRING_THAI_ASCENDER = 4971, + AF_BLUE_STRING_THAI_LARGE_ASCENDER = 4983, + AF_BLUE_STRING_THAI_DESCENDER = 4995, + AF_BLUE_STRING_THAI_LARGE_DESCENDER = 5011, + AF_BLUE_STRING_THAI_DIGIT_TOP = 5019, + AF_BLUE_STRING_TIFINAGH = 5031, + AF_BLUE_STRING_VAI_TOP = 5063, + AF_BLUE_STRING_VAI_BOTTOM = 5095, + af_blue_1_1 = 5126, #ifdef AF_CONFIG_OPTION_CJK AF_BLUE_STRING_CJK_TOP = af_blue_1_1 + 1, AF_BLUE_STRING_CJK_BOTTOM = af_blue_1_1 + 203, @@ -304,14 +314,17 @@ FT_BEGIN_HEADER /* Properties are specific to a writing system. We assume that a given */ /* blue string can't be used in more than a single writing system, which */ /* is a safe bet. */ -#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must be value 1 */ #define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) #define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) #define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) -#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ -#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ( 1U << 5 ) +#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ( 1U << 6 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must be value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must be value 2 */ #define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP @@ -347,35 +360,37 @@ FT_BEGIN_HEADER AF_BLUE_STRINGSET_GUJR = 112, AF_BLUE_STRINGSET_GURU = 118, AF_BLUE_STRINGSET_HEBR = 124, - AF_BLUE_STRINGSET_KALI = 128, - AF_BLUE_STRINGSET_KHMR = 134, - AF_BLUE_STRINGSET_KHMS = 140, - AF_BLUE_STRINGSET_KNDA = 143, + AF_BLUE_STRINGSET_KNDA = 128, + AF_BLUE_STRINGSET_KALI = 131, + AF_BLUE_STRINGSET_KHMR = 137, + AF_BLUE_STRINGSET_KHMS = 143, AF_BLUE_STRINGSET_LAO = 146, AF_BLUE_STRINGSET_LATN = 152, AF_BLUE_STRINGSET_LATB = 159, AF_BLUE_STRINGSET_LATP = 166, AF_BLUE_STRINGSET_LISU = 173, AF_BLUE_STRINGSET_MLYM = 176, - AF_BLUE_STRINGSET_MONG = 179, - AF_BLUE_STRINGSET_MYMR = 182, - AF_BLUE_STRINGSET_NKOO = 187, - AF_BLUE_STRINGSET_NONE = 192, - AF_BLUE_STRINGSET_OLCK = 193, - AF_BLUE_STRINGSET_ORKH = 196, - AF_BLUE_STRINGSET_OSGE = 199, - AF_BLUE_STRINGSET_OSMA = 207, - AF_BLUE_STRINGSET_SAUR = 210, - AF_BLUE_STRINGSET_SHAW = 213, - AF_BLUE_STRINGSET_SINH = 219, - AF_BLUE_STRINGSET_SUND = 223, - AF_BLUE_STRINGSET_TAML = 227, - AF_BLUE_STRINGSET_TAVT = 230, - AF_BLUE_STRINGSET_TELU = 233, - AF_BLUE_STRINGSET_TFNG = 236, - AF_BLUE_STRINGSET_THAI = 239, - AF_BLUE_STRINGSET_VAII = 247, - af_blue_2_1 = 250, + AF_BLUE_STRINGSET_MEDF = 179, + AF_BLUE_STRINGSET_MONG = 187, + AF_BLUE_STRINGSET_MYMR = 190, + AF_BLUE_STRINGSET_NKOO = 195, + AF_BLUE_STRINGSET_NONE = 200, + AF_BLUE_STRINGSET_OLCK = 201, + AF_BLUE_STRINGSET_ORKH = 204, + AF_BLUE_STRINGSET_OSGE = 207, + AF_BLUE_STRINGSET_OSMA = 215, + AF_BLUE_STRINGSET_ROHG = 218, + AF_BLUE_STRINGSET_SAUR = 222, + AF_BLUE_STRINGSET_SHAW = 225, + AF_BLUE_STRINGSET_SINH = 231, + AF_BLUE_STRINGSET_SUND = 235, + AF_BLUE_STRINGSET_TAML = 239, + AF_BLUE_STRINGSET_TAVT = 242, + AF_BLUE_STRINGSET_TELU = 245, + AF_BLUE_STRINGSET_THAI = 248, + AF_BLUE_STRINGSET_TFNG = 256, + AF_BLUE_STRINGSET_VAII = 259, + af_blue_2_1 = 262, #ifdef AF_CONFIG_OPTION_CJK AF_BLUE_STRINGSET_HANI = af_blue_2_1 + 0, af_blue_2_1_1 = af_blue_2_1 + 2, diff --git a/src/thirdparty/freetype2/src/autofit/afblue.hin b/src/thirdparty/freetype2/src/autofit/afblue.hin index 30a28dafa..dbac14548 100644 --- a/src/thirdparty/freetype2/src/autofit/afblue.hin +++ b/src/thirdparty/freetype2/src/autofit/afblue.hin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -99,14 +99,17 @@ FT_BEGIN_HEADER /* Properties are specific to a writing system. We assume that a given */ /* blue string can't be used in more than a single writing system, which */ /* is a safe bet. */ -#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must have value 1 */ +#define AF_BLUE_PROPERTY_LATIN_TOP ( 1U << 0 ) /* must be value 1 */ #define AF_BLUE_PROPERTY_LATIN_SUB_TOP ( 1U << 1 ) #define AF_BLUE_PROPERTY_LATIN_NEUTRAL ( 1U << 2 ) #define AF_BLUE_PROPERTY_LATIN_X_HEIGHT ( 1U << 3 ) #define AF_BLUE_PROPERTY_LATIN_LONG ( 1U << 4 ) -#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must have value 1 */ -#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must have value 2 */ +#define AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ( 1U << 5 ) +#define AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ( 1U << 6 ) + +#define AF_BLUE_PROPERTY_CJK_TOP ( 1U << 0 ) /* must be value 1 */ +#define AF_BLUE_PROPERTY_CJK_HORIZ ( 1U << 1 ) /* must be value 2 */ #define AF_BLUE_PROPERTY_CJK_RIGHT AF_BLUE_PROPERTY_CJK_TOP diff --git a/src/thirdparty/freetype2/src/autofit/afcjk.c b/src/thirdparty/freetype2/src/autofit/afcjk.c index a61689bee..708660183 100644 --- a/src/thirdparty/freetype2/src/autofit/afcjk.c +++ b/src/thirdparty/freetype2/src/autofit/afcjk.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (body). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,9 +22,8 @@ * */ -#include -#include FT_ADVANCES_H -#include FT_INTERNAL_DEBUG_H +#include +#include #include "afglobal.h" #include "aflatin.h" @@ -38,11 +37,6 @@ #include "aferrors.h" -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif - - /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -73,11 +67,11 @@ AF_GlyphHintsRec hints[1]; - FT_TRACE5(( "\n" - "cjk standard widths computation (style `%s')\n" - "===================================================\n" - "\n", + FT_TRACE5(( "\n" )); + FT_TRACE5(( "cjk standard widths computation (style `%s')\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "===================================================\n" )); + FT_TRACE5(( "\n" )); af_glyph_hints_init( hints, face->memory ); @@ -96,12 +90,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif const char* p; @@ -111,9 +101,8 @@ p = script_class->standard_charstring; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); /* We check a list of standard characters. The first match wins. */ @@ -150,7 +139,7 @@ break; } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( !glyph_index ) goto Exit; @@ -158,7 +147,7 @@ if ( !glyph_index ) goto Exit; - FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", + FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n", ch, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); @@ -261,9 +250,9 @@ dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); - FT_TRACE5(( " %d (standard)", axis->standard_width )); + FT_TRACE5(( " %ld (standard)", axis->standard_width )); for ( i = 1; i < axis->width_count; i++ ) - FT_TRACE5(( " %d", axis->widths[i].org )); + FT_TRACE5(( " %ld", axis->widths[i].org )); FT_TRACE5(( "\n" )); } @@ -303,25 +292,20 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array, computing its */ /* extremum points (depending on the string properties) */ - FT_TRACE5(( "cjk blue zones computation\n" - "==========================\n" - "\n" )); + FT_TRACE5(( "cjk blue zones computation\n" )); + FT_TRACE5(( "==========================\n" )); + FT_TRACE5(( "\n" )); -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { @@ -346,7 +330,7 @@ }; - FT_TRACE5(( "blue zone %d (%s):\n", + FT_TRACE5(( "blue zone %u (%s):\n", axis->blue_count, cjk_blue_name[AF_CJK_IS_HORIZ_BLUE( bs ) | AF_CJK_IS_TOP_BLUE( bs ) ] )); @@ -423,16 +407,14 @@ { FT_Int nn; - FT_Int first = 0; - FT_Int last = -1; + FT_Int pp, first, last; - for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) { - FT_Int pp; - - - last = outline.contours[nn]; + first = last + 1; + last = outline.contours[nn]; /* Avoid single-point contours since they are never rasterized. */ /* In some fonts, they correspond to mark attachment points */ @@ -556,13 +538,12 @@ if ( AF_CJK_IS_TOP_BLUE( bs ) ) blue->flags |= AF_CJK_BLUE_TOP; - FT_TRACE5(( " -> reference = %ld\n" - " overshoot = %ld\n", - *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); } /* end for loop */ - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); FT_TRACE5(( "\n" )); @@ -576,28 +557,25 @@ af_cjk_metrics_check_digits( AF_CJKMetrics metrics, FT_Face face ) { - FT_Bool started = 0, same_width = 1; - FT_Fixed advance = 0, old_advance = 0; + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* in all supported charmaps, digits have character codes 0x30-0x39 */ const char digits[] = "0 1 2 3 4 5 6 7 8 9"; const char* p; + FT_UNUSED( face ); + p = digits; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); while ( *p ) { @@ -633,7 +611,7 @@ } } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); metrics->root.digits_have_same_width = same_width; } @@ -642,10 +620,11 @@ /* Initialize global metrics. */ FT_LOCAL_DEF( FT_Error ) - af_cjk_metrics_init( AF_CJKMetrics metrics, - FT_Face face ) + af_cjk_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) { - FT_CharMap oldmap = face->charmap; + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_CharMap oldmap = face->charmap; metrics->units_per_em = face->units_per_EM; @@ -657,7 +636,7 @@ af_cjk_metrics_check_digits( metrics, face ); } - FT_Set_Charmap( face, oldmap ); + face->charmap = oldmap; return FT_Err_Ok; } @@ -718,7 +697,7 @@ FT_Pos delta1, delta2; - blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); /* shoot is under shoot for cjk */ delta1 = FT_DivFix( blue->ref.fit, scale ) - blue->shoot.org; @@ -728,7 +707,7 @@ delta2 = FT_MulFix( delta2, scale ); - FT_TRACE5(( "delta: %d", delta1 )); + FT_TRACE5(( "delta: %ld", delta1 )); if ( delta2 < 32 ) delta2 = 0; #if 0 @@ -737,20 +716,22 @@ #endif else delta2 = FT_PIX_ROUND( delta2 ); - FT_TRACE5(( "/%d\n", delta2 )); + FT_TRACE5(( "/%ld\n", delta2 )); if ( delta1 < 0 ) delta2 = -delta2; blue->shoot.fit = blue->ref.fit - delta2; - FT_TRACE5(( ">> active cjk blue zone %c%d[%ld/%ld]:\n" - " ref: cur=%.2f fit=%.2f\n" - " shoot: cur=%.2f fit=%.2f\n", + FT_TRACE5(( ">> active cjk blue zone %c%u[%ld/%ld]:\n", ( dim == AF_DIMENSION_HORZ ) ? 'H' : 'V', - nn, blue->ref.org, blue->shoot.org, - blue->ref.cur / 64.0, blue->ref.fit / 64.0, - blue->shoot.cur / 64.0, blue->shoot.fit / 64.0 )); + nn, blue->ref.org, blue->shoot.org )); + FT_TRACE5(( " ref: cur=%.2f fit=%.2f\n", + (double)blue->ref.cur / 64, + (double)blue->ref.fit / 64 )); + FT_TRACE5(( " shoot: cur=%.2f fit=%.2f\n", + (double)blue->shoot.cur / 64, + (double)blue->shoot.fit / 64 )); blue->flags |= AF_CJK_BLUE_ACTIVE; } @@ -761,9 +742,12 @@ /* Scale global values in both directions. */ FT_LOCAL_DEF( void ) - af_cjk_metrics_scale( AF_CJKMetrics metrics, - AF_Scaler scaler ) + af_cjk_metrics_scale( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + AF_Scaler scaler ) { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + /* we copy the whole structure since the x and y scaling values */ /* are not modified, contrary to e.g. the `latin' auto-hinter */ metrics->root.scaler = *scaler; @@ -776,11 +760,14 @@ /* Extract standard_width from writing system/script specific */ /* metrics class. */ - FT_LOCAL_DEF( void ) - af_cjk_get_standard_widths( AF_CJKMetrics metrics, - FT_Pos* stdHW, - FT_Pos* stdVW ) + FT_CALLBACK_DEF( void ) + af_cjk_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + if ( stdHW ) *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; @@ -806,7 +793,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); FT_Error error; AF_Segment seg; @@ -850,7 +837,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Direction major_dir = axis->major_dir; AF_Segment seg1, seg2; FT_Pos len_threshold; @@ -1012,7 +999,7 @@ AF_CJKAxis laxis = &((AF_CJKMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; FT_Fixed scale; @@ -1051,7 +1038,7 @@ { AF_Edge found = NULL; FT_Pos best = 0xFFFFU; - FT_Int ee; + FT_UInt ee; /* look for an edge corresponding to the segment */ @@ -1160,7 +1147,7 @@ */ { AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; @@ -1298,7 +1285,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edge = axis->edges; - AF_Edge edge_limit = edge + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); AF_CJKAxis cjk = &metrics->axis[dim]; FT_Fixed scale = cjk->scale; FT_Pos best_dist0; /* initial threshold */ @@ -1378,12 +1365,13 @@ } - /* Initalize hinting engine. */ + /* Initialize hinting engine. */ FT_LOCAL_DEF( FT_Error ) - af_cjk_hints_init( AF_GlyphHints hints, - AF_CJKMetrics metrics ) + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; @@ -1402,11 +1390,6 @@ /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; -#if 0 /* AF_CONFIG_OPTION_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; @@ -1435,12 +1418,6 @@ scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE; -#ifdef AF_CONFIG_OPTION_USE_WARPER - /* get (global) warper flag */ - if ( !metrics->root.globals->module->warping ) - scaler_flags |= AF_SCALER_FLAG_NO_WARPER; -#endif - hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; @@ -1644,11 +1621,13 @@ stem_edge->pos = base_edge->pos + fitted_width; - FT_TRACE5(( " CJKLINK: edge %d @%d (opos=%.2f) linked to %.2f," + FT_TRACE5(( " CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f," " dist was %.2f, now %.2f\n", stem_edge - hints->axis[dim].edges, stem_edge->fpos, - stem_edge->opos / 64.0, stem_edge->pos / 64.0, - dist / 64.0, fitted_width / 64.0 )); + (double)stem_edge->opos / 64, + (double)stem_edge->pos / 64, + (double)dist / 64, + (double)fitted_width / 64 )); } @@ -1816,7 +1795,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); FT_PtrDist n_edges; AF_Edge edge; AF_Edge anchor = NULL; @@ -1866,10 +1845,10 @@ continue; #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( " CJKBLUE: edge %d @%d (opos=%.2f) snapped to %.2f," + FT_TRACE5(( " CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f," " was %.2f\n", - edge1 - edges, edge1->fpos, edge1->opos / 64.0, - blue->fit / 64.0, edge1->pos / 64.0 )); + edge1 - edges, edge1->fpos, (double)edge1->opos / 64, + (double)blue->fit / 64, (double)edge1->pos / 64 )); num_actions++; #endif @@ -1930,7 +1909,7 @@ /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { - FT_TRACE5(( "ASSERTION FAILED for edge %d\n", edge2-edges )); + FT_TRACE5(( "ASSERTION FAILED for edge %td\n", edge2 - edges )); af_cjk_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; @@ -2042,8 +2021,8 @@ #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 ); + (double)( edge->pos - edge->opos ) / 64, + (double)( edge2->pos - edge2->opos ) / 64 ); #endif anchor = edge; @@ -2193,9 +2172,9 @@ af_cjk_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = & hints->axis[dim]; + AF_AxisHints axis = &hints->axis[dim]; AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; FT_Bool snapping; @@ -2282,11 +2261,13 @@ /* Apply the complete hinting algorithm to a CJK glyph. */ FT_LOCAL_DEF( FT_Error ) - af_cjk_hints_apply( FT_UInt glyph_index, - AF_GlyphHints hints, - FT_Outline* outline, - AF_CJKMetrics metrics ) + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */ { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + FT_Error error; int dim; @@ -2323,25 +2304,6 @@ if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { - -#ifdef AF_CONFIG_OPTION_USE_WARPER - if ( dim == AF_DIMENSION_HORZ && - metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL && - AF_HINTS_DO_WARP( hints ) ) - { - AF_WarperRec warper; - FT_Fixed scale; - FT_Pos delta; - - - af_warper_compute( &warper, hints, (AF_Dimension)dim, - &scale, &delta ); - af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, - scale, delta ); - continue; - } -#endif /* AF_CONFIG_OPTION_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 ); diff --git a/src/thirdparty/freetype2/src/autofit/afcjk.h b/src/thirdparty/freetype2/src/autofit/afcjk.h index 59acae534..bd1b39358 100644 --- a/src/thirdparty/freetype2/src/autofit/afcjk.h +++ b/src/thirdparty/freetype2/src/autofit/afcjk.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -84,7 +84,7 @@ FT_BEGIN_HEADER /* used for horizontal metrics too for CJK */ FT_Bool control_overshoot; FT_UInt blue_count; - AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX]; + AF_CJKBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; FT_Fixed org_scale; FT_Pos org_delta; @@ -103,22 +103,22 @@ FT_BEGIN_HEADER #ifdef AF_CONFIG_OPTION_CJK FT_LOCAL( FT_Error ) - af_cjk_metrics_init( AF_CJKMetrics metrics, - FT_Face face ); + af_cjk_metrics_init( AF_StyleMetrics metrics, + FT_Face face ); FT_LOCAL( void ) - af_cjk_metrics_scale( AF_CJKMetrics metrics, - AF_Scaler scaler ); + af_cjk_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ); FT_LOCAL( FT_Error ) - af_cjk_hints_init( AF_GlyphHints hints, - AF_CJKMetrics metrics ); + af_cjk_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ); FT_LOCAL( FT_Error ) - af_cjk_hints_apply( FT_UInt glyph_index, - AF_GlyphHints hints, - FT_Outline* outline, - AF_CJKMetrics metrics ); + af_cjk_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ); /* shared; called from afindic.c */ FT_LOCAL( void ) diff --git a/src/thirdparty/freetype2/src/autofit/afcover.h b/src/thirdparty/freetype2/src/autofit/afcover.h index ff207a97e..b93bcd1a2 100644 --- a/src/thirdparty/freetype2/src/autofit/afcover.h +++ b/src/thirdparty/freetype2/src/autofit/afcover.h @@ -4,7 +4,7 @@ * * Auto-fitter coverages (specification only). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/afdummy.c b/src/thirdparty/freetype2/src/autofit/afdummy.c index 7e07a41e7..8613544f9 100644 --- a/src/thirdparty/freetype2/src/autofit/afdummy.c +++ b/src/thirdparty/freetype2/src/autofit/afdummy.c @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/afdummy.h b/src/thirdparty/freetype2/src/autofit/afdummy.h index ab9227d35..78a79439d 100644 --- a/src/thirdparty/freetype2/src/autofit/afdummy.h +++ b/src/thirdparty/freetype2/src/autofit/afdummy.h @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/aferrors.h b/src/thirdparty/freetype2/src/autofit/aferrors.h index 2ec336f72..f3093fc90 100644 --- a/src/thirdparty/freetype2/src/autofit/aferrors.h +++ b/src/thirdparty/freetype2/src/autofit/aferrors.h @@ -4,7 +4,7 @@ * * Autofitter error codes (specification only). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef AFERRORS_H_ #define AFERRORS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX AF_Err_ #define FT_ERR_BASE FT_Mod_Err_Autofit -#include FT_ERRORS_H +#include #endif /* AFERRORS_H_ */ diff --git a/src/thirdparty/freetype2/src/autofit/afglobal.c b/src/thirdparty/freetype2/src/autofit/afglobal.c index 6a9a1e5aa..e74d81411 100644 --- a/src/thirdparty/freetype2/src/autofit/afglobal.c +++ b/src/thirdparty/freetype2/src/autofit/afglobal.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to compute global hinting values (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,13 @@ #include "afglobal.h" #include "afranges.h" #include "afshaper.h" -#include FT_INTERNAL_DEBUG_H +#include "afws-decl.h" +#include + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +# include "afgsub.h" +# include "ft-hb-ft.h" +#endif /************************************************************************** @@ -32,11 +38,6 @@ #define FT_COMPONENT afglobal - /* get writing system specific header files */ -#undef WRITING_SYSTEM -#define WRITING_SYSTEM( ws, WS ) /* empty */ -#include "afwrtsys.h" - #include "aferrors.h" @@ -74,7 +75,7 @@ af_writing_system_classes[] = { -#include "afwrtsys.h" +#include "afws-iter.h" NULL /* do not remove */ }; @@ -133,13 +134,13 @@ FT_Face face = globals->face; FT_CharMap old_charmap = face->charmap; FT_UShort* gstyles = globals->glyph_styles; - FT_UInt ss; + FT_UShort ss; + FT_UShort dflt = 0xFFFFU; /* a non-valid value */ FT_UInt i; - FT_UInt dflt = ~0U; /* a non-valid value */ /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */ - for ( i = 0; i < (FT_UInt)globals->glyph_count; i++ ) + for ( i = 0; i < globals->glyph_count; i++ ) gstyles[i] = AF_STYLE_UNASSIGNED; error = FT_Select_Charmap( face, FT_ENCODING_UNICODE ); @@ -172,8 +173,7 @@ */ if ( style_class->coverage == AF_COVERAGE_DEFAULT ) { - if ( (FT_UInt)style_class->script == - globals->module->default_script ) + if ( style_class->script == globals->module->default_script ) dflt = ss; for ( range = script_class->script_uni_ranges; @@ -187,9 +187,9 @@ gindex = FT_Get_Char_Index( face, charcode ); if ( gindex != 0 && - gindex < (FT_ULong)globals->glyph_count && + gindex < globals->glyph_count && ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) - gstyles[gindex] = (FT_UShort)ss; + gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY; for (;;) { @@ -198,9 +198,9 @@ if ( gindex == 0 || charcode > range->last ) break; - if ( gindex < (FT_ULong)globals->glyph_count && + if ( gindex < globals->glyph_count && ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED ) - gstyles[gindex] = (FT_UShort)ss; + gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY; } } @@ -215,9 +215,9 @@ gindex = FT_Get_Char_Index( face, charcode ); - if ( gindex != 0 && - gindex < (FT_ULong)globals->glyph_count && - ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss ) + if ( gindex != 0 && + gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) gstyles[gindex] |= AF_NONBASE; for (;;) @@ -227,8 +227,8 @@ if ( gindex == 0 || charcode > range->last ) break; - if ( gindex < (FT_ULong)globals->glyph_count && - ( gstyles[gindex] & AF_STYLE_MASK ) == (FT_UShort)ss ) + if ( gindex < globals->glyph_count && + ( gstyles[gindex] & AF_STYLE_MASK ) == ss ) gstyles[gindex] |= AF_NONBASE; } } @@ -259,7 +259,7 @@ FT_UInt gindex = FT_Get_Char_Index( face, i ); - if ( gindex != 0 && gindex < (FT_ULong)globals->glyph_count ) + if ( gindex != 0 && gindex < globals->glyph_count ) gstyles[gindex] |= AF_DIGIT; } @@ -270,7 +270,7 @@ */ if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED ) { - FT_Long nn; + FT_UInt nn; for ( nn = 0; nn < globals->glyph_count; nn++ ) @@ -285,16 +285,16 @@ #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( "\n" - "style coverage\n" - "==============\n" - "\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "style coverage\n" )); + FT_TRACE4(( "==============\n" )); + FT_TRACE4(( "\n" )); for ( ss = 0; af_style_classes[ss]; ss++ ) { AF_StyleClass style_class = af_style_classes[ss]; FT_UInt count = 0; - FT_Long idx; + FT_UInt idx; FT_TRACE4(( "%s:\n", af_style_names[style_class->style] )); @@ -306,7 +306,7 @@ if ( !( count % 10 ) ) FT_TRACE4(( " " )); - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; if ( !( count % 10 ) ) @@ -322,7 +322,7 @@ #endif /* FT_DEBUG_LEVEL_TRACE */ - FT_Set_Charmap( face, old_charmap ); + face->charmap = old_charmap; return error; } @@ -341,13 +341,15 @@ /* we allocate an AF_FaceGlobals structure together */ /* with the glyph_styles array */ - if ( FT_ALLOC( globals, - sizeof ( *globals ) + - (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) + if ( FT_QALLOC( globals, + sizeof ( *globals ) + + (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) ) goto Exit; + FT_ZERO( &globals->metrics ); + globals->face = face; - globals->glyph_count = face->num_glyphs; + globals->glyph_count = (FT_UInt)face->num_glyphs; /* right after the globals structure come the glyph styles */ globals->glyph_styles = (FT_UShort*)( globals + 1 ); globals->module = module; @@ -359,8 +361,21 @@ globals->scale_down_factor = 0; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - globals->hb_font = hb_ft_font_create( face, NULL ); - globals->hb_buf = hb_buffer_create(); + if ( ft_hb_enabled ( globals ) ) + { + globals->hb_font = ft_hb_ft_font_create( globals ); + globals->hb_buf = hb( buffer_create )(); + + af_parse_gsub( globals ); + } + else + { + globals->hb_font = NULL; + globals->hb_buf = NULL; + + globals->gsub = NULL; + globals->gsub_lookups_single_alternate = NULL; + } #endif error = af_face_globals_compute_style_coverage( globals ); @@ -379,8 +394,11 @@ FT_LOCAL_DEF( void ) - af_face_globals_free( AF_FaceGlobals globals ) + af_face_globals_free( void* globals_ ) { + AF_FaceGlobals globals = (AF_FaceGlobals)globals_; + + if ( globals ) { FT_Memory memory = globals->face->memory; @@ -405,8 +423,14 @@ } #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - hb_font_destroy( globals->hb_font ); - hb_buffer_destroy( globals->hb_buf ); + if ( ft_hb_enabled ( globals ) ) + { + hb( font_destroy )( globals->hb_font ); + hb( buffer_destroy )( globals->hb_buf ); + + FT_FREE( globals->gsub ); + FT_FREE( globals->gsub_lookups_single_alternate ); + } #endif /* no need to free `globals->glyph_styles'; */ @@ -431,7 +455,7 @@ FT_Error error = FT_Err_Ok; - if ( gindex >= (FT_ULong)globals->glyph_count ) + if ( gindex >= globals->glyph_count ) { error = FT_THROW( Invalid_Argument ); goto Exit; @@ -478,6 +502,10 @@ { style = (AF_Style)( globals->glyph_styles[gindex] & AF_STYLE_UNASSIGNED ); + /* IMPORTANT: Clear the error code, see + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063 + */ + error = FT_Err_Ok; goto Again; } @@ -499,7 +527,7 @@ af_face_globals_is_digit( AF_FaceGlobals globals, FT_UInt gindex ) { - if ( gindex < (FT_ULong)globals->glyph_count ) + if ( gindex < globals->glyph_count ) return FT_BOOL( globals->glyph_styles[gindex] & AF_DIGIT ); return FT_BOOL( 0 ); diff --git a/src/thirdparty/freetype2/src/autofit/afglobal.h b/src/thirdparty/freetype2/src/autofit/afglobal.h index 52f38350d..362f56e29 100644 --- a/src/thirdparty/freetype2/src/autofit/afglobal.h +++ b/src/thirdparty/freetype2/src/autofit/afglobal.h @@ -5,7 +5,7 @@ * Auto-fitter routines to compute global hinting values * (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -73,15 +73,17 @@ FT_BEGIN_HEADER /* default script for OpenType; ignored if HarfBuzz isn't used */ #define AF_SCRIPT_DEFAULT AF_SCRIPT_LATN - /* a bit mask for AF_DIGIT and AF_NONBASE */ -#define AF_STYLE_MASK 0x3FFF + /* a bit mask for AF_DIGIT, AF_NONBASE, and AF_HAS_CMAP_ENTRY */ +#define AF_STYLE_MASK 0x1FFF /* an uncovered glyph */ #define AF_STYLE_UNASSIGNED AF_STYLE_MASK - /* if this flag is set, we have an ASCII digit */ + /* if this flag is set, we have an ASCII digit */ #define AF_DIGIT 0x8000U /* if this flag is set, we have a non-base character */ #define AF_NONBASE 0x4000U + /* if this flag is set, the glyph has a (direct) cmap entry */ +#define AF_HAS_CMAP_ENTRY 0x2000U /* `increase-x-height' property */ #define AF_PROP_INCREASE_X_HEIGHT_MIN 6 @@ -105,12 +107,17 @@ FT_BEGIN_HEADER typedef struct AF_FaceGlobalsRec_ { FT_Face face; - FT_Long glyph_count; /* same as face->num_glyphs */ + FT_UInt glyph_count; /* unsigned face->num_glyphs */ FT_UShort* glyph_styles; #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ hb_font_t* hb_font; hb_buffer_t* hb_buf; /* for feature comparison */ + + /* The GSUB table. */ + FT_Byte* gsub; + /* Lookup offsets, with only SingleSubst and AlternateSubst non-NULL. */ + FT_UInt32* gsub_lookups_single_alternate; #endif /* per-face auto-hinter properties */ @@ -156,9 +163,9 @@ FT_BEGIN_HEADER AF_StyleMetrics *ametrics ); FT_LOCAL( void ) - af_face_globals_free( AF_FaceGlobals globals ); + af_face_globals_free( void* globals ); - FT_LOCAL_DEF( FT_Bool ) + FT_LOCAL( FT_Bool ) af_face_globals_is_digit( AF_FaceGlobals globals, FT_UInt gindex ); diff --git a/src/thirdparty/freetype2/src/autofit/afgsub.c b/src/thirdparty/freetype2/src/autofit/afgsub.c new file mode 100644 index 000000000..386999d5c --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afgsub.c @@ -0,0 +1,693 @@ +/**************************************************************************** + * + * afgsub.c + * + * Auto-fitter routines to parse the GSUB table (body). + * + * Copyright (C) 2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + + +#include +#include +#include + +#include + +#include "afglobal.h" +#include "afgsub.h" +#include "aftypes.h" + + + /*********************************/ + /******** ********/ + /******** GSUB validation ********/ + /******** ********/ + /*********************************/ + + + static FT_Bool + af_validate_coverage( FT_Byte* table, + FT_Byte* table_limit, + FT_UInt *num_glyphs ) + { + FT_UInt format; + + FT_Byte* p = table; + FT_UInt count = 0; + + + if ( table_limit < p + 4 ) + return FALSE; + + format = FT_NEXT_USHORT( p ); + if ( format == 1 ) + { + FT_UInt glyphCount = FT_NEXT_USHORT( p ); + + + /* We don't validate glyph IDs. */ + if ( table_limit < p + glyphCount * 2 ) + return FALSE; + + count += glyphCount; + } + else if ( format == 2 ) + { + FT_UInt rangeCount = FT_NEXT_USHORT( p ); + FT_Byte* limit = p + rangeCount * 6; + + + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt startGlyphID = FT_NEXT_USHORT( p ); + FT_UInt endGlyphID = FT_NEXT_USHORT( p ); + + + if ( startGlyphID > endGlyphID ) + return FALSE; + + count += endGlyphID - startGlyphID + 1; + + /* We don't validate coverage indices. */ + p += 2; + } + } + else + return FALSE; + + if ( num_glyphs ) + *num_glyphs = count; + + return TRUE; + } + + + static FT_Bool + af_validate_single_subst1( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_Byte* coverage; + + + /* Subtable format is already checked. */ + + /* The four bytes for the coverage table offset */ + /* and the glyph ID delta are already checked. */ + coverage = table + FT_PEEK_USHORT( table + 2 ); + if ( !af_validate_coverage( coverage, table_limit, NULL ) ) + return FALSE; + + /* We don't validate glyph IDs. */ + + return TRUE; + } + + + static FT_Bool + af_validate_single_subst2( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_Byte* coverage; + FT_UInt glyphCount; + FT_UInt num_glyphs; + + /* Subtable format is already checked. */ + FT_Byte* p = table + 2; + + + /* The four bytes for the coverage table offset */ + /* and `glyphCount` are already checked. */ + coverage = table + FT_NEXT_USHORT( p ); + if ( !af_validate_coverage( coverage, table_limit, &num_glyphs ) ) + return FALSE; + + glyphCount = FT_NEXT_USHORT( p ); + /* We don't validate glyph IDs. */ + if ( table_limit < p + glyphCount * 2 ) + return FALSE; + + if ( glyphCount != num_glyphs ) + return FALSE; + + return TRUE; + } + + + static FT_Bool + af_validate_alternate( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_Byte* coverage; + FT_UInt alternateSetCount; + FT_UInt num_glyphs; + + /* Subtable format is already checked. */ + FT_Byte* p = table + 2; + FT_Byte* limit; + + + /* The four bytes for the coverage table offset */ + /* and `alternateSetCount` are already checked. */ + coverage = table + FT_NEXT_USHORT( p ); + if ( !af_validate_coverage( coverage, table_limit, &num_glyphs ) ) + return FALSE; + + alternateSetCount = FT_NEXT_USHORT( p ); + limit = p + alternateSetCount * 2; + if ( table_limit < limit ) + return FALSE; + + if ( alternateSetCount != num_glyphs ) + return FALSE; + + while ( p < limit ) + { + FT_Byte* alternate_set; + FT_UInt glyphCount; + + + alternate_set = table + FT_NEXT_USHORT( p ); + if ( table_limit < alternate_set + 2 ) + return FALSE; + + glyphCount = FT_PEEK_USHORT( alternate_set ); + /* We don't validate glyph IDs. */ + if ( table_limit < alternate_set + 2 + glyphCount * 2 ) + return FALSE; + } + + return TRUE; + } + + + /* Validate 'SingleSubst' and 'AlternateSubst' lookup tables. */ + static FT_Bool + af_validate_lookup_table( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_UInt lookupType; + FT_UInt real_lookupType = 0; + FT_UInt subtableCount; + + FT_Byte* p = table; + FT_Byte* limit; + + + if ( table_limit < p + 6 ) + return FALSE; + + lookupType = FT_NEXT_USHORT( p ); + + p += 2; /* Skip `lookupFlag`. */ + + subtableCount = FT_NEXT_USHORT( p ); + limit = p + subtableCount * 2; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_Byte* subtable = table + FT_NEXT_USHORT( p ); + FT_UInt format; + + + if ( lookupType == 7 ) + { + /* Substitution extension. */ + FT_Byte* q = subtable; + + + if ( table_limit < q + 8 ) + return FALSE; + + if ( FT_NEXT_USHORT( q ) != 1 ) /* format */ + return FALSE; + + if ( real_lookupType == 0 ) + real_lookupType = FT_NEXT_USHORT( q ); + else if ( real_lookupType != FT_NEXT_USHORT( q ) ) + return FALSE; + + subtable += FT_PEEK_ULONG( q ); + } + else + real_lookupType = lookupType; + + /* Ensure the first six bytes of all subtable formats. */ + if ( table_limit < subtable + 6 ) + return FALSE; + + format = FT_PEEK_USHORT( subtable ); + + if ( real_lookupType == 1 ) + { + if ( format == 1 ) + { + if ( !af_validate_single_subst1( subtable, table_limit ) ) + return FALSE; + } + else if ( format == 2 ) + { + if ( !af_validate_single_subst2( subtable, table_limit ) ) + return FALSE; + } + else + return FALSE; + } + else if ( real_lookupType == 3 ) + { + if ( format == 1 ) + { + if ( !af_validate_alternate( subtable, table_limit ) ) + return FALSE; + } + else + return FALSE; + } + else + return FALSE; + } + + return TRUE; + } + + + FT_LOCAL_DEF( void ) + af_parse_gsub( AF_FaceGlobals globals ) + { + FT_Error error = FT_Err_Ok; + + FT_Face face = globals->face; + FT_Memory memory = face->memory; + + FT_ULong gsub_length; + FT_Byte* gsub; + FT_Byte* gsub_limit; + + FT_UInt32* gsub_lookups_single_alternate; + + FT_UInt lookupListOffset; + FT_Byte* lookup_list; + FT_UInt lookupCount; + + FT_UInt idx; + + FT_Byte* p; + FT_Byte* limit; + + + globals->gsub = NULL; + globals->gsub_lookups_single_alternate = NULL; + + /* No error if we can't load or parse GSUB data. */ + + gsub = NULL; + gsub_lookups_single_alternate = NULL; + + gsub_length = 0; + if ( FT_Load_Sfnt_Table( face, TTAG_GSUB, 0, NULL, &gsub_length ) ) + goto Fail; + + if ( FT_QALLOC( gsub, gsub_length ) ) + goto Fail; + + if ( FT_Load_Sfnt_Table( face, TTAG_GSUB, 0, gsub, &gsub_length ) ) + goto Fail; + + if ( gsub_length < 10 ) + goto Fail; + + lookupListOffset = FT_PEEK_USHORT( gsub + 8 ); + if ( gsub_length < lookupListOffset + 2 ) + goto Fail; + + lookupCount = FT_PEEK_USHORT( gsub + lookupListOffset ); + if ( gsub_length < lookupListOffset + 2 + lookupCount * 2 ) + goto Fail; + + if ( FT_NEW_ARRAY( gsub_lookups_single_alternate, lookupCount ) ) + goto Fail; + + gsub_limit = gsub + gsub_length; + lookup_list = gsub + lookupListOffset; + p = lookup_list + 2; + limit = p + lookupCount * 2; + idx = 0; + while ( p < limit ) + { + FT_UInt lookupOffset = FT_NEXT_USHORT( p ); + + + if ( af_validate_lookup_table( lookup_list + lookupOffset, + gsub_limit ) ) + { + /* We store offsets relative to the start of the GSUB table. */ + gsub_lookups_single_alternate[idx] = lookupListOffset + lookupOffset; + } + + idx++; + } + + globals->gsub = gsub; + globals->gsub_lookups_single_alternate = gsub_lookups_single_alternate; + + return; + + Fail: + FT_FREE( gsub ); + FT_FREE( gsub_lookups_single_alternate ); + } + + + /*********************************/ + /******** ********/ + /******** GSUB access ********/ + /******** ********/ + /*********************************/ + + + static FT_UInt + af_coverage_format( FT_Byte* coverage ) + { + return FT_PEEK_USHORT( coverage ); + } + + + static FT_Byte* + af_coverage_start( FT_Byte* coverage ) + { + return coverage + 4; + } + + + static FT_Byte* + af_coverage_limit( FT_Byte* coverage ) + { + if ( af_coverage_format( coverage ) == 1 ) + { + FT_UInt glyphCount = FT_PEEK_USHORT( coverage + 2 ); + + + return af_coverage_start( coverage ) + glyphCount * 2; + } + else + { + FT_UInt rangeCount = FT_PEEK_USHORT( coverage + 2 ); + + + return af_coverage_start( coverage ) + rangeCount * 6; + } + } + + + typedef struct AF_CoverageIteratorRec_* AF_CoverageIterator; + + typedef struct AF_CoverageIteratorRec_ + { + FT_UInt format; + + FT_Byte* p; + FT_Byte* limit; + + FT_UInt16 glyph; + FT_UInt16 glyph_limit; + + } AF_CoverageIteratorRec; + + + static FT_Bool + af_coverage_iterator( AF_CoverageIterator iter, + FT_UInt16* glyph ) + { + if ( iter->p >= iter->limit ) + return FALSE; + + if ( iter->format == 1 ) + *glyph = FT_NEXT_USHORT( iter->p ); + else + { + if ( iter->glyph > iter->glyph_limit ) + { + iter->glyph = FT_NEXT_USHORT( iter->p ); + iter->glyph_limit = FT_NEXT_USHORT( iter->p ); + + iter->p += 2; + } + + *glyph = iter->glyph++; + } + + return TRUE; + } + + + static AF_CoverageIteratorRec + af_coverage_iterator_init( FT_Byte* coverage ) + { + AF_CoverageIteratorRec iterator; + + + iterator.format = af_coverage_format( coverage ); + iterator.p = af_coverage_start( coverage ); + iterator.limit = af_coverage_limit( coverage ); + iterator.glyph = 1; + iterator.glyph_limit = 0; + + return iterator; + } + + + /* + Because we merge all single and alternate substitution mappings into + one, large hash, we need the possibility to have multiple glyphs as + values. We utilize that we have 32bit integers but only 16bit glyph + indices, using the following scheme. + + If glyph G maps to a single substitute S, the entry in the map is + + G -> S + + If glyph G maps to multiple substitutes S1, S2, ..., Sn, we do + + G -> S1 + ((n - 1) << 16) + G + (1 << 16) -> S2 + G + (2 << 16) -> S3 + ... + G + ((n - 1) << 16) -> Sn + */ + static FT_Error + af_hash_insert( FT_UInt16 glyph, + FT_UInt16 substitute, + FT_Hash map, + FT_Memory memory ) + { + FT_Error error; + + size_t* value = ft_hash_num_lookup( glyph, map ); + + + if ( !value ) + { + error = ft_hash_num_insert( glyph, substitute, map, memory ); + if ( error ) + return error; + } + else + { + /* Get number of substitutes, increased by one... */ + FT_UInt mask = ( (FT_UInt)*value & 0xFFFF0000U ) + 0x10000U; + + + /* ... which becomes the new key mask. */ + error = ft_hash_num_insert( (FT_Int)( glyph | mask ), + substitute, + map, + memory ); + if ( error ) + return error; + + /* Update number of substitutes. */ + *value += 0x10000U; + } + + return FT_Err_Ok; + } + + + static FT_Error + af_map_single_subst1( FT_Hash map, + FT_Byte* table, + FT_Memory memory ) + { + FT_Error error; + + FT_Byte* coverage = table + FT_PEEK_USHORT( table + 2 ); + FT_UInt deltaGlyphID = FT_PEEK_USHORT( table + 4 ); + + AF_CoverageIteratorRec iterator = af_coverage_iterator_init( coverage ); + + FT_UInt16 glyph; + + + while ( af_coverage_iterator( &iterator, &glyph ) ) + { + /* `deltaGlyphID` requires modulo 65536 arithmetic. */ + FT_UInt16 subst = (FT_UInt16)( ( glyph + deltaGlyphID ) % 0x10000U ); + + + error = af_hash_insert( glyph, subst, map, memory ); + if ( error ) + return error; + } + + return FT_Err_Ok; + } + + + static FT_Error + af_map_single_subst2( FT_Hash map, + FT_Byte* table, + FT_Memory memory ) + { + FT_Error error; + + FT_Byte* coverage = table + FT_PEEK_USHORT( table + 2 ); + + AF_CoverageIteratorRec iterator = af_coverage_iterator_init( coverage ); + + FT_UInt16 glyph; + FT_Byte* p = table + 6; + + + while ( af_coverage_iterator( &iterator, &glyph ) ) + { + FT_UInt16 subst = FT_NEXT_USHORT( p ); + + + error = af_hash_insert( glyph, subst, map, memory ); + if ( error ) + return error; + } + + return FT_Err_Ok; + } + + + static FT_Error + af_map_alternate( FT_Hash map, + FT_Byte* table, + FT_Memory memory ) + { + FT_Error error; + + FT_Byte* coverage = table + FT_PEEK_USHORT( table + 2 ); + + AF_CoverageIteratorRec iterator = af_coverage_iterator_init( coverage ); + + FT_UInt16 glyph; + FT_Byte* p = table + 6; + + + while ( af_coverage_iterator( &iterator, &glyph ) ) + { + FT_Byte* alternate_set = table + FT_NEXT_USHORT( p ); + + FT_Byte* q = alternate_set; + FT_UInt glyphCount = FT_NEXT_USHORT( q ); + + FT_UInt i; + + + for ( i = 0; i < glyphCount; i++ ) + { + FT_UInt16 subst = FT_NEXT_USHORT( q ); + + + error = af_hash_insert( glyph, subst, map, memory ); + if ( error ) + return error; + } + } + + return FT_Err_Ok; + } + + + /* Map 'SingleSubst' and 'AlternateSubst' lookup tables. */ + FT_LOCAL_DEF( FT_Error ) + af_map_lookup( AF_FaceGlobals globals, + FT_Hash map, + FT_UInt32 lookup_offset ) + { + FT_Face face = globals->face; + FT_Memory memory = face->memory; + + FT_Byte* table = globals->gsub + lookup_offset; + + FT_UInt lookupType = FT_PEEK_USHORT( table ); + FT_UInt subtableCount = FT_PEEK_USHORT( table + 4 ); + + FT_Byte* p = table + 6; + FT_Byte* limit = p + subtableCount * 2; + + + while ( p < limit ) + { + FT_Error error; + + FT_UInt real_lookupType = lookupType; + + FT_Byte* subtable = table + FT_NEXT_USHORT( p ); + + + if ( lookupType == 7 ) + { + FT_Byte* q = subtable + 2; + + + real_lookupType = FT_NEXT_USHORT( q ); + subtable += FT_PEEK_ULONG( q ); + } + + if ( real_lookupType == 1 ) + { + FT_UInt format = FT_PEEK_USHORT( subtable ); + + + error = ( format == 1 ) + ? af_map_single_subst1( map, subtable, memory ) + : af_map_single_subst2( map, subtable, memory ); + } + else + error = af_map_alternate( map, subtable, memory ); + + if ( error ) + return error; + } + + return FT_Err_Ok; + } + + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* ANSI C doesn't like empty source files */ +typedef int afgsub_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afgsub.h b/src/thirdparty/freetype2/src/autofit/afgsub.h new file mode 100644 index 000000000..d57d61475 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afgsub.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * afgsub.h + * + * Auto-fitter routines to parse the GSUB table (header). + * + * Copyright (C) 2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 AFGSUB_H_ +#define AFGSUB_H_ + +#include "afglobal.h" + + +FT_BEGIN_HEADER + + FT_LOCAL( void ) + af_parse_gsub( AF_FaceGlobals globals ); + + FT_LOCAL( FT_Error ) + af_map_lookup( AF_FaceGlobals globals, + FT_Hash map, + FT_UInt32 lookup_offset ); + +FT_END_HEADER + +#endif /* AFGSUB_H_ */ + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afhints.c b/src/thirdparty/freetype2/src/autofit/afhints.c index ed111c411..11faa655f 100644 --- a/src/thirdparty/freetype2/src/autofit/afhints.c +++ b/src/thirdparty/freetype2/src/autofit/afhints.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,8 +18,8 @@ #include "afhints.h" #include "aferrors.h" -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H +#include +#include /************************************************************************** @@ -32,6 +32,104 @@ #define FT_COMPONENT afhints + 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_and_quantize_widths( FT_UInt* count, + AF_Width table, + FT_Pos threshold ) + { + FT_UInt i, j; + FT_UInt cur_idx; + FT_Pos cur_val; + FT_Pos sum; + AF_WidthRec swap; + + + if ( *count == 1 ) + return; + + /* sort */ + 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; + } + } + + cur_idx = 0; + cur_val = table[cur_idx].org; + + /* compute and use mean values for clusters not larger than */ + /* `threshold'; this is very primitive and might not yield */ + /* the best result, but normally, using reference character */ + /* `o', `*count' is 2, so the code below is fully sufficient */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org - cur_val > threshold || + i == *count - 1 ) + { + sum = 0; + + /* fix loop for end of array */ + if ( table[i].org - cur_val <= threshold && + i == *count - 1 ) + i++; + + for ( j = cur_idx; j < i; j++ ) + { + sum += table[j].org; + table[j].org = 0; + } + table[cur_idx].org = sum / (FT_Pos)j; + + if ( i < *count - 1 ) + { + cur_idx = i + 1; + cur_val = table[cur_idx].org; + } + } + } + + cur_idx = 1; + + /* compress array to remove zero values */ + for ( i = 1; i < *count; i++ ) + { + if ( table[i].org ) + table[cur_idx++] = table[i]; + } + + *count = cur_idx; + } + /* Get new segment for given axis. */ FT_LOCAL_DEF( FT_Error ) @@ -53,9 +151,9 @@ } else 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)( FT_INT_MAX / sizeof ( *segment ) ); + FT_UInt old_max = axis->max_segments; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *segment ); if ( old_max >= big_max ) @@ -95,7 +193,7 @@ /* Get new edge for given axis, direction, and position, */ /* without initializing the edge itself. */ - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) af_axis_hints_new_edge( AF_AxisHints axis, FT_Int fpos, AF_Direction dir, @@ -118,9 +216,9 @@ } else 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)( FT_INT_MAX / sizeof ( *edge ) ); + FT_UInt old_max = axis->max_edges; + FT_UInt new_max = old_max; + FT_UInt big_max = FT_INT_MAX / sizeof ( *edge ); if ( old_max >= big_max ) @@ -222,8 +320,9 @@ static char* - af_print_idx( char* p, - int idx ) + af_print_idx( char* p, + size_t n, + int idx ) { if ( idx == -1 ) { @@ -232,7 +331,7 @@ p[2] = '\0'; } else - ft_sprintf( p, "%d", idx ); + ft_snprintf( p, n, "%d", idx ); return p; } @@ -359,12 +458,12 @@ " %5d %5d %7.2f %7.2f %7.2f %7.2f" " %5s %5s %5s %5s\n", point_idx, - af_print_idx( buf1, + af_print_idx( buf1, 16, af_get_edge_index( hints, segment_idx_1, 1 ) ), - af_print_idx( buf2, segment_idx_1 ), - af_print_idx( buf3, + af_print_idx( buf2, 16, segment_idx_1 ), + af_print_idx( buf3, 16, af_get_edge_index( hints, segment_idx_0, 0 ) ), - af_print_idx( buf4, segment_idx_0 ), + af_print_idx( buf4, 16, segment_idx_0 ), ( point->flags & AF_FLAG_NEAR ) ? " near " : ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) @@ -373,23 +472,27 @@ point->fx, point->fy, - point->ox / 64.0, - point->oy / 64.0, - point->x / 64.0, - point->y / 64.0, + (double)point->ox / 64, + (double)point->oy / 64, + (double)point->x / 64, + (double)point->y / 64, - af_print_idx( buf5, af_get_strong_edge_index( hints, - point->before, - 1 ) ), - af_print_idx( buf6, af_get_strong_edge_index( hints, - point->after, - 1 ) ), - af_print_idx( buf7, af_get_strong_edge_index( hints, - point->before, - 0 ) ), - af_print_idx( buf8, af_get_strong_edge_index( hints, - point->after, - 0 ) ) )); + af_print_idx( buf5, 16, + af_get_strong_edge_index( hints, + point->before, + 1 ) ), + af_print_idx( buf6, 16, + af_get_strong_edge_index( hints, + point->after, + 1 ) ), + af_print_idx( buf7, 16, + af_get_strong_edge_index( hints, + point->before, + 0 ) ), + af_print_idx( buf8, 16, + af_get_strong_edge_index( hints, + point->after, + 0 ) ) )); } AF_DUMP(( "\n" )); } @@ -476,9 +579,12 @@ AF_INDEX_NUM( seg->first, points ), AF_INDEX_NUM( seg->last, points ), - af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ), - af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ), - af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ), + af_print_idx( buf1, 16, + AF_INDEX_NUM( seg->link, segments ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( seg->serif, segments ) ), + af_print_idx( buf3, 16, + AF_INDEX_NUM( seg->edge, edges ) ), seg->height, seg->height - ( seg->max_coord - seg->min_coord ), @@ -499,7 +605,7 @@ FT_Error af_glyph_hints_get_num_segments( AF_GlyphHints hints, FT_Int dimension, - FT_Int* num_segments ) + FT_UInt* num_segments ) { AF_Dimension dim; AF_AxisHints axis; @@ -525,7 +631,7 @@ FT_Error af_glyph_hints_get_segment_offset( AF_GlyphHints hints, FT_Int dimension, - FT_Int idx, + FT_UInt idx, FT_Pos *offset, FT_Bool *is_blue, FT_Pos *blue_offset ) @@ -542,7 +648,7 @@ axis = &hints->axis[dim]; - if ( idx < 0 || idx >= axis->num_segments ) + if ( idx >= axis->num_segments ) return FT_THROW( Invalid_Argument ); seg = &axis->segments[idx]; @@ -594,13 +700,13 @@ if ( dimension == AF_DIMENSION_HORZ ) AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", "vertical", - 65536.0 * 64.0 / hints->x_scale, - 10.0 * hints->x_scale / 65536.0 / 64.0 )); + 65536 * 64 / (double)hints->x_scale, + 10 * (double)hints->x_scale / 65536 / 64 )); else AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n", "horizontal", - 65536.0 * 64.0 / hints->y_scale, - 10.0 * hints->y_scale / 65536.0 / 64.0 )); + 65536 * 64 / (double)hints->y_scale, + 10 * (double)hints->y_scale / 65536 / 64 )); if ( axis->num_edges ) { @@ -616,14 +722,16 @@ AF_DUMP(( " %5d %7.2f %5s %4s %5s" " %c %7.2f %7.2f %11s\n", AF_INDEX_NUM( edge, edges ), - (int)edge->opos / 64.0, + (double)(int)edge->opos / 64, af_dir_str( (AF_Direction)edge->dir ), - af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ), - af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ), + af_print_idx( buf1, 16, + AF_INDEX_NUM( edge->link, edges ) ), + af_print_idx( buf2, 16, + AF_INDEX_NUM( edge->serif, edges ) ), edge->blue_edge ? 'y' : 'n', - edge->opos / 64.0, - edge->pos / 64.0, + (double)edge->opos / 64, + (double)edge->pos / 64, af_edge_flags_to_string( edge->flags ) )); AF_DUMP(( "\n" )); } @@ -732,6 +840,10 @@ if ( hints->contours != hints->embedded.contours ) FT_FREE( hints->contours ); + if ( hints->contour_y_minima != hints->embedded.contour_y_minima ) + FT_FREE( hints->contour_y_minima ); + if ( hints->contour_y_maxima != hints->embedded.contour_y_maxima ) + FT_FREE( hints->contour_y_maxima ); hints->max_contours = 0; hints->num_contours = 0; @@ -764,7 +876,7 @@ { FT_Error error = FT_Err_Ok; AF_Point points; - FT_UInt old_max, new_max; + FT_Int 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; @@ -781,28 +893,39 @@ hints->axis[1].num_edges = 0; /* first of all, reallocate the contours array if necessary */ - new_max = (FT_UInt)outline->n_contours; - old_max = (FT_UInt)hints->max_contours; + new_max = outline->n_contours; + old_max = hints->max_contours; if ( new_max <= AF_CONTOURS_EMBEDDED ) { if ( !hints->contours ) { - hints->contours = hints->embedded.contours; + hints->contours = hints->embedded.contours; + hints->contour_y_minima = hints->embedded.contour_y_minima; + hints->contour_y_maxima = hints->embedded.contour_y_maxima; + hints->max_contours = AF_CONTOURS_EMBEDDED; } } else if ( new_max > old_max ) { if ( hints->contours == hints->embedded.contours ) - hints->contours = NULL; + { + hints->contours = NULL; + hints->contour_y_minima = NULL; + hints->contour_y_maxima = NULL; + } - new_max = ( new_max + 3 ) & ~3U; /* round up to a multiple of 4 */ + new_max = ( new_max + 3 ) & ~3; /* round up to a multiple of 4 */ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) ) goto Exit; + if ( FT_RENEW_ARRAY( hints->contour_y_minima, old_max, new_max ) ) + goto Exit; + if ( FT_RENEW_ARRAY( hints->contour_y_maxima, old_max, new_max ) ) + goto Exit; - hints->max_contours = (FT_Int)new_max; + hints->max_contours = new_max; } /* @@ -810,8 +933,8 @@ * note that we reserve two additional point positions, used to * hint metrics appropriately */ - new_max = (FT_UInt)( outline->n_points + 2 ); - old_max = (FT_UInt)hints->max_points; + new_max = outline->n_points + 2; + old_max = hints->max_points; if ( new_max <= AF_POINTS_EMBEDDED ) { @@ -826,12 +949,12 @@ if ( hints->points == hints->embedded.points ) hints->points = NULL; - new_max = ( new_max + 2 + 7 ) & ~7U; /* round up to a multiple of 8 */ + new_max = ( new_max + 2 + 7 ) & ~7; /* round up to a multiple of 8 */ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) ) goto Exit; - hints->max_points = (FT_Int)new_max; + hints->max_points = new_max; } hints->num_points = outline->n_points; @@ -855,9 +978,6 @@ 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; @@ -874,8 +994,8 @@ /* compute coordinates & Bezier flags, next and prev */ { FT_Vector* vec = outline->points; - char* tag = outline->tags; - FT_Short endpoint = outline->contours[0]; + FT_Byte* tag = outline->tags; + FT_UShort endpoint = outline->contours[0]; AF_Point end = points + endpoint; AF_Point prev = end; FT_Int contour_index = 0; @@ -941,16 +1061,16 @@ /* 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; + AF_Point* contour = hints->contours; + AF_Point* contour_limit = contour + hints->num_contours; + FT_UShort* end = outline->contours; + FT_Int idx = 0; for ( ; contour < contour_limit; contour++, end++ ) { contour[0] = points + idx; - idx = (short)( end[0] + 1 ); + idx = *end + 1; } } @@ -1187,7 +1307,7 @@ AF_Point point = hints->points; AF_Point limit = point + hints->num_points; FT_Vector* vec = outline->points; - char* tag = outline->tags; + FT_Byte* tag = outline->tags; for ( ; point < limit; point++, vec++, tag++ ) @@ -1219,9 +1339,9 @@ af_glyph_hints_align_edge_points( AF_GlyphHints hints, AF_Dimension dim ) { - AF_AxisHints axis = & hints->axis[dim]; + AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; @@ -1298,7 +1418,7 @@ 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_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); FT_UInt touch_flag; @@ -1688,33 +1808,4 @@ } -#ifdef AF_CONFIG_OPTION_USE_WARPER - - /* Apply (small) warp scale and warp delta for given dimension. */ - - 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_CONFIG_OPTION_USE_WARPER */ - /* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afhints.h b/src/thirdparty/freetype2/src/autofit/afhints.h index e0cf612f0..46b3ed336 100644 --- a/src/thirdparty/freetype2/src/autofit/afhints.h +++ b/src/thirdparty/freetype2/src/autofit/afhints.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,6 @@ #include "aftypes.h" -#define xxAF_SORT_SEGMENTS - FT_BEGIN_HEADER /* @@ -224,6 +222,9 @@ FT_BEGIN_HEADER /* the distance to the next point is very small */ #define AF_FLAG_NEAR ( 1U << 5 ) + /* prevent the auto-hinter from adding such a point to a segment */ +#define AF_FLAG_IGNORE ( 1U << 6 ) + /* edge hint flags */ #define AF_EDGE_NORMAL 0 @@ -231,6 +232,7 @@ FT_BEGIN_HEADER #define AF_EDGE_SERIF ( 1U << 1 ) #define AF_EDGE_DONE ( 1U << 2 ) #define AF_EDGE_NEUTRAL ( 1U << 3 ) /* edge aligns to a neutral blue zone */ +#define AF_EDGE_NO_BLUE ( 1U << 4 ) /* do not align edge to blue zone */ typedef struct AF_PointRec_* AF_Point; @@ -305,20 +307,18 @@ FT_BEGIN_HEADER } AF_EdgeRec; + #define AF_SEGMENTS_EMBEDDED 18 /* number of embedded segments */ #define AF_EDGES_EMBEDDED 12 /* number of embedded edges */ typedef struct AF_AxisHintsRec_ { - FT_Int num_segments; /* number of used segments */ - FT_Int max_segments; /* number of allocated segments */ + FT_UInt num_segments; /* number of used segments */ + FT_UInt max_segments; /* number of allocated segments */ AF_Segment segments; /* segments array */ -#ifdef AF_SORT_SEGMENTS - FT_Int mid_segments; -#endif - FT_Int num_edges; /* number of used edges */ - FT_Int max_edges; /* number of allocated edges */ + FT_UInt num_edges; /* number of used edges */ + FT_UInt max_edges; /* number of allocated edges */ AF_Edge edges; /* edges array */ AF_Direction major_dir; /* either vertical or horizontal */ @@ -351,9 +351,11 @@ FT_BEGIN_HEADER FT_Int num_points; /* number of used points */ AF_Point points; /* points array */ - FT_Int max_contours; /* number of allocated contours */ - FT_Int num_contours; /* number of used contours */ - AF_Point* contours; /* contours array */ + FT_Int max_contours; /* number of allocated contours */ + FT_Int num_contours; /* number of used contours */ + AF_Point* contours; /* contours array */ + FT_Pos* contour_y_minima; /* array with y maxima of contours */ + FT_Pos* contour_y_maxima; /* array with y minima of contours */ AF_AxisHintsRec axis[AF_DIMENSION_MAX]; @@ -362,14 +364,13 @@ FT_BEGIN_HEADER /* implementations */ AF_StyleMetrics metrics; - FT_Pos xmin_delta; /* used for warping */ - FT_Pos xmax_delta; - - /* Two arrays to avoid allocation penalty. */ + /* Some arrays to avoid allocation penalty. */ /* The `embedded' structure must be the last element! */ struct { AF_Point contours[AF_CONTOURS_EMBEDDED]; + FT_Pos contour_y_minima[AF_CONTOURS_EMBEDDED]; + FT_Pos contour_y_maxima[AF_CONTOURS_EMBEDDED]; AF_PointRec points[AF_POINTS_EMBEDDED]; } embedded; @@ -383,14 +384,14 @@ FT_BEGIN_HEADER #ifdef FT_DEBUG_AUTOFIT #define AF_HINTS_DO_HORIZONTAL( h ) \ - ( !_af_debug_disable_horz_hints && \ + ( !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_debug_disable_vert_hints_ && \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) ) -#define AF_HINTS_DO_BLUES( h ) ( !_af_debug_disable_blue_hints ) +#define AF_HINTS_DO_BLUES( h ) ( !af_debug_disable_blue_hints_ ) #else /* !FT_DEBUG_AUTOFIT */ @@ -408,10 +409,6 @@ FT_BEGIN_HEADER #define AF_HINTS_DO_ADVANCE( h ) \ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE ) -#define AF_HINTS_DO_WARP( h ) \ - !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_WARPER ) - - FT_LOCAL( AF_Direction ) af_direction_compute( FT_Pos dx, @@ -459,14 +456,6 @@ FT_BEGIN_HEADER af_glyph_hints_align_weak_points( AF_GlyphHints hints, AF_Dimension dim ); -#ifdef AF_CONFIG_OPTION_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 ); diff --git a/src/thirdparty/freetype2/src/autofit/afindic.c b/src/thirdparty/freetype2/src/autofit/afindic.c index a17117c71..a2cd14f88 100644 --- a/src/thirdparty/freetype2/src/autofit/afindic.c +++ b/src/thirdparty/freetype2/src/autofit/afindic.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for Indic writing system (body). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, @@ -27,15 +27,13 @@ #include "aferrors.h" -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif - - static FT_Error - af_indic_metrics_init( AF_CJKMetrics metrics, - FT_Face face ) + af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Face face ) { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + /* skip blue zone init in CJK routines */ FT_CharMap oldmap = face->charmap; @@ -54,15 +52,14 @@ af_cjk_metrics_check_digits( metrics, face ); } - FT_Set_Charmap( face, oldmap ); - + face->charmap = oldmap; return FT_Err_Ok; } static void - af_indic_metrics_scale( AF_CJKMetrics metrics, - AF_Scaler scaler ) + af_indic_metrics_scale( AF_StyleMetrics metrics, + AF_Scaler scaler ) { /* use CJK routines */ af_cjk_metrics_scale( metrics, scaler ); @@ -70,8 +67,8 @@ static FT_Error - af_indic_hints_init( AF_GlyphHints hints, - AF_CJKMetrics metrics ) + af_indic_hints_init( AF_GlyphHints hints, + AF_StyleMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_init( hints, metrics ); @@ -79,10 +76,10 @@ static FT_Error - af_indic_hints_apply( FT_UInt glyph_index, - AF_GlyphHints hints, - FT_Outline* outline, - AF_CJKMetrics metrics ) + af_indic_hints_apply( FT_UInt glyph_index, + AF_GlyphHints hints, + FT_Outline* outline, + AF_StyleMetrics metrics ) { /* use CJK routines */ return af_cjk_hints_apply( glyph_index, hints, outline, metrics ); @@ -93,10 +90,13 @@ /* metrics class. */ static void - af_indic_get_standard_widths( AF_CJKMetrics metrics, - FT_Pos* stdHW, - FT_Pos* stdVW ) + af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */ + FT_Pos* stdHW, + FT_Pos* stdVW ) { + AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_; + + if ( stdHW ) *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; diff --git a/src/thirdparty/freetype2/src/autofit/afindic.h b/src/thirdparty/freetype2/src/autofit/afindic.h index bc5bc59fa..a2e825e9f 100644 --- a/src/thirdparty/freetype2/src/autofit/afindic.h +++ b/src/thirdparty/freetype2/src/autofit/afindic.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for Indic writing system * (specification). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/aflatin.c b/src/thirdparty/freetype2/src/autofit/aflatin.c index 27d402488..cb5667ff7 100644 --- a/src/thirdparty/freetype2/src/autofit/aflatin.c +++ b/src/thirdparty/freetype2/src/autofit/aflatin.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for latin writing system (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,18 +16,13 @@ */ -#include -#include FT_ADVANCES_H -#include FT_INTERNAL_DEBUG_H +#include +#include #include "afglobal.h" #include "aflatin.h" #include "aferrors.h" - - -#ifdef AF_CONFIG_OPTION_USE_WARPER -#include "afwarp.h" -#endif +#include "afadjust.h" /************************************************************************** @@ -64,11 +59,11 @@ AF_GlyphHintsRec hints[1]; - FT_TRACE5(( "\n" - "latin standard widths computation (style `%s')\n" - "=====================================================\n" - "\n", + FT_TRACE5(( "\n" )); + FT_TRACE5(( "latin standard widths computation (style `%s')\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "=====================================================\n" )); + FT_TRACE5(( "\n" )); af_glyph_hints_init( hints, face->memory ); @@ -87,12 +82,8 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif const char* p; @@ -103,9 +94,9 @@ p = script_class->standard_charstring; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); + /* * We check a list of standard characters to catch features like * `c2sc' (small caps from caps) that don't contain lowercase letters @@ -146,7 +137,7 @@ break; } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( !glyph_index ) { @@ -155,7 +146,7 @@ goto Exit; } - FT_TRACE5(( "standard character: U+%04lX (glyph index %d)\n", + FT_TRACE5(( "standard character: U+%04lX (glyph index %lu)\n", ch, glyph_index )); error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); @@ -206,7 +197,7 @@ (AF_Dimension)dim ); seg = axhints->segments; - limit = seg + axhints->num_segments; + limit = FT_OFFSET( seg, axhints->num_segments ); for ( ; seg < limit; seg++ ) { @@ -258,9 +249,9 @@ dim == AF_DIMENSION_VERT ? "horizontal" : "vertical" )); - FT_TRACE5(( " %d (standard)", axis->standard_width )); + FT_TRACE5(( " %ld (standard)", axis->standard_width )); for ( i = 1; i < axis->width_count; i++ ) - FT_TRACE5(( " %d", axis->widths[i].org )); + FT_TRACE5(( " %ld", axis->widths[i].org )); FT_TRACE5(( "\n" )); } @@ -340,24 +331,19 @@ /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* we walk over the blue character strings as specified in the */ /* style's entry in the `af_blue_stringset' array */ - FT_TRACE5(( "latin blue zones computation\n" - "============================\n" - "\n" )); + FT_TRACE5(( "latin blue zones computation\n" )); + FT_TRACE5(( "============================\n" )); + FT_TRACE5(( "\n" )); -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) { @@ -373,7 +359,7 @@ FT_Bool have_flag = 0; - FT_TRACE5(( "blue zone %d", axis->blue_count )); + FT_TRACE5(( "blue zone %u", axis->blue_count )); if ( bs->properties ) { @@ -413,6 +399,20 @@ FT_TRACE5(( "long" )); } + if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "capital bottom" )); + } + + if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) ) + { + if ( have_flag ) + FT_TRACE5(( ", " )); + FT_TRACE5(( "small bottom" )); + } + FT_TRACE5(( ")" )); } @@ -460,9 +460,9 @@ } if ( AF_LATIN_IS_TOP_BLUE( bs ) ) - best_y_extremum = FT_INT_MIN; + best_y_extremum = FT_LONG_MIN; else - best_y_extremum = FT_INT_MAX; + best_y_extremum = FT_LONG_MAX; /* iterate over all glyph elements of the character cluster */ /* and get the data of the `biggest' one */ @@ -493,7 +493,7 @@ if ( num_idx == 1 ) FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch )); else - FT_TRACE5(( " component %d of cluster starting with U+%04lX" + FT_TRACE5(( " component %u of cluster starting with U+%04lX" " contains no (usable) outlines\n", i, ch )); #endif continue; @@ -502,23 +502,20 @@ /* now compute min or max point indices and coordinates */ points = outline.points; best_point = -1; + best_contour_first = -1; + best_contour_last = -1; best_y = 0; /* make compiler happy */ - best_contour_first = 0; /* ditto */ - best_contour_last = 0; /* ditto */ { FT_Int nn; - FT_Int first = 0; - FT_Int last = -1; + FT_Int pp, first, last; - for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ ) + last = -1; + for ( nn = 0; nn < outline.n_contours; nn++ ) { - FT_Int old_best_point = best_point; - FT_Int pp; - - - last = outline.contours[nn]; + first = last + 1; + last = outline.contours[nn]; /* Avoid single-point contours since they are never */ /* rasterized. In some fonts, they correspond to mark */ @@ -557,7 +554,7 @@ } } - if ( best_point != old_best_point ) + if ( best_point > best_contour_last ) { best_contour_first = first; best_contour_last = last; @@ -834,7 +831,7 @@ if ( num_idx == 1 ) FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y )); else - FT_TRACE5(( " component %d of cluster starting with U+%04lX:" + FT_TRACE5(( " component %u of cluster starting with U+%04lX:" " best_y = %5ld", i, ch, best_y )); #endif @@ -888,8 +885,8 @@ } /* end for loop */ - if ( !( best_y_extremum == FT_INT_MIN || - best_y_extremum == FT_INT_MAX ) ) + if ( !( best_y_extremum == FT_LONG_MIN || + best_y_extremum == FT_LONG_MAX ) ) { if ( best_round ) rounds[num_rounds++] = best_y_extremum; @@ -968,6 +965,10 @@ blue->flags |= AF_LATIN_BLUE_SUB_TOP; if ( AF_LATIN_IS_NEUTRAL_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_NEUTRAL; + if ( AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_BOTTOM; + if ( AF_LATIN_IS_SMALL_BOTTOM_BLUE( bs ) ) + blue->flags |= AF_LATIN_BLUE_BOTTOM_SMALL; /* * The following flag is used later to adjust the y and x scales @@ -977,13 +978,12 @@ if ( AF_LATIN_IS_X_HEIGHT_BLUE( bs ) ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; - FT_TRACE5(( " -> reference = %ld\n" - " overshoot = %ld\n", - *blue_ref, *blue_shoot )); + FT_TRACE5(( " -> reference = %ld\n", *blue_ref )); + FT_TRACE5(( " overshoot = %ld\n", *blue_shoot )); } /* end for loop */ - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); if ( axis->blue_count ) { @@ -991,7 +991,7 @@ /* `ref' and `shoot' values of two blue zones must not overlap */ FT_UInt i; - AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN + 2]; + AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN]; for ( i = 0; i < axis->blue_count; i++ ) @@ -1032,7 +1032,7 @@ { *a = *b; FT_TRACE5(( "blue zone overlap:" - " adjusting %s %d to %ld\n", + " adjusting %s %td to %ld\n", a_is_top ? "overshoot" : "reference", blue_sorted[i] - axis->blues, *a )); @@ -1050,7 +1050,7 @@ AF_FaceGlobals globals = metrics->root.globals; FT_UShort* gstyles = globals->glyph_styles; - FT_Long i; + FT_UInt i; FT_TRACE5(( "no blue zones found:" @@ -1075,28 +1075,25 @@ af_latin_metrics_check_digits( AF_LatinMetrics metrics, FT_Face face ) { - FT_Bool started = 0, same_width = 1; - FT_Fixed advance = 0, old_advance = 0; + FT_Bool started = 0, same_width = 1; + FT_Long advance = 0, old_advance = 0; /* If HarfBuzz is not available, we need a pointer to a single */ /* unsigned long value. */ -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - void* shaper_buf; -#else FT_ULong shaper_buf_; void* shaper_buf = &shaper_buf_; -#endif /* in all supported charmaps, digits have character codes 0x30-0x39 */ const char digits[] = "0 1 2 3 4 5 6 7 8 9"; const char* p; + FT_UNUSED( face ); + p = digits; -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - shaper_buf = af_shaper_buf_create( face ); -#endif + if ( ft_hb_enabled ( metrics->root.globals ) ) + shaper_buf = af_shaper_buf_create( metrics->root.globals ); while ( *p ) { @@ -1132,7 +1129,7 @@ } } - af_shaper_buf_destroy( face, shaper_buf ); + af_shaper_buf_destroy( metrics->root.globals, shaper_buf ); metrics->root.digits_have_same_width = same_width; } @@ -1141,9 +1138,11 @@ /* Initialize global metrics. */ FT_LOCAL_DEF( FT_Error ) - af_latin_metrics_init( AF_LatinMetrics metrics, + af_latin_metrics_init( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ FT_Face face ) { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + FT_Error error = FT_Err_Ok; FT_CharMap oldmap = face->charmap; @@ -1163,8 +1162,11 @@ af_latin_metrics_check_digits( metrics, face ); } + af_reverse_character_map_new( &metrics->root.reverse_charmap, + &metrics->root ); + Exit: - FT_Set_Charmap( face, oldmap ); + face->charmap = oldmap; return error; } @@ -1271,34 +1273,32 @@ max_height = FT_MAX( max_height, -Axis->blues[nn].descender ); } - dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) ); - dist &= ~127; + dist = FT_MulFix( max_height, new_scale - scale ); - if ( dist == 0 ) + if ( -128 < dist && dist < 128 ) { - FT_TRACE5(( - "af_latin_metrics_scale_dim:" - " x height alignment (style `%s'):\n" - " " - " vertical scaling changed from %.5f to %.5f (by %d%%)\n" - "\n", - af_style_names[metrics->root.style_class->style], - scale / 65536.0, - new_scale / 65536.0, - ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " vertical scaling changed" + " from %.5f to %.5f (by %ld%%)\n", + (double)scale / 65536, + (double)new_scale / 65536, + ( fitted - scaled ) * 100 / scaled )); + FT_TRACE5(( "\n" )); scale = new_scale; } #ifdef FT_DEBUG_LEVEL_TRACE else { - FT_TRACE5(( - "af_latin_metrics_scale_dim:" - " x height alignment (style `%s'):\n" - " " - " excessive vertical scaling abandoned\n" - "\n", - af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "af_latin_metrics_scale_dim:" + " x height alignment (style `%s'):\n", + af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( " " + " excessive vertical scaling abandoned\n" )); + FT_TRACE5(( "\n" )); } #endif } @@ -1333,9 +1333,9 @@ width->cur = FT_MulFix( width->org, scale ); width->fit = width->cur; - FT_TRACE5(( " %d scaled to %.2f\n", + FT_TRACE5(( " %ld scaled to %.2f\n", width->org, - width->cur / 64.0 )); + (double)width->cur / 64 )); } FT_TRACE5(( "\n" )); @@ -1347,9 +1347,11 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( axis->extra_light ) - FT_TRACE5(( "`%s' style is extra light (at current resolution)\n" - "\n", + { + FT_TRACE5(( "`%s' style is extra light (at current resolution)\n", af_style_names[metrics->root.style_class->style] )); + FT_TRACE5(( "\n" )); + } #endif if ( dim == AF_DIMENSION_VERT ) @@ -1474,16 +1476,16 @@ AF_LatinBlue blue = &axis->blues[nn]; - FT_TRACE5(( " reference %d: %d scaled to %.2f%s\n" - " overshoot %d: %d scaled to %.2f%s\n", + FT_TRACE5(( " reference %u: %ld scaled to %.2f%s\n", nn, blue->ref.org, - blue->ref.fit / 64.0, + (double)blue->ref.fit / 64, ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" - : " (inactive)", + : " (inactive)" )); + FT_TRACE5(( " overshoot %u: %ld scaled to %.2f%s\n", nn, blue->shoot.org, - blue->shoot.fit / 64.0, + (double)blue->shoot.fit / 64, ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? "" : " (inactive)" )); } @@ -1492,12 +1494,26 @@ } + FT_CALLBACK_DEF( void ) + af_latin_metrics_done( AF_StyleMetrics metrics_ ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + af_reverse_character_map_done( metrics->root.reverse_charmap, + metrics->root.globals->face->memory ); + } + + /* Scale global values in both directions. */ FT_LOCAL_DEF( void ) - af_latin_metrics_scale( AF_LatinMetrics metrics, + af_latin_metrics_scale( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ AF_Scaler scaler ) { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + metrics->root.scaler.render_mode = scaler->render_mode; metrics->root.scaler.face = scaler->face; metrics->root.scaler.flags = scaler->flags; @@ -1510,11 +1526,14 @@ /* Extract standard_width from writing system/script specific */ /* metrics class. */ - FT_LOCAL_DEF( void ) - af_latin_get_standard_widths( AF_LatinMetrics metrics, + FT_CALLBACK_DEF( void ) + af_latin_get_standard_widths( AF_StyleMetrics metrics_, /* AF_LatinMetrics */ FT_Pos* stdHW, FT_Pos* stdVW ) { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + if ( stdHW ) *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width; @@ -1619,7 +1638,8 @@ FT_Pos prev_max_on_coord = max_on_coord; - if ( FT_ABS( last->out_dir ) == major_dir && + if ( !( point->flags & AF_FLAG_IGNORE ) && + 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 */ @@ -1678,13 +1698,17 @@ max_on_coord = v; } - if ( point->out_dir != segment_dir || point == last ) + if ( point->flags & AF_FLAG_IGNORE || + point->out_dir != segment_dir || + point == last ) { /* check whether the new segment's start point is identical to */ /* the previous segment's end point; for example, this might */ /* happen for spikes */ - if ( !prev_segment || segment->first != prev_segment->last ) + if ( point->flags & AF_FLAG_IGNORE || + !prev_segment || + segment->first != prev_segment->last ) { /* points are different: we are just leaving an edge, thus */ /* record a new segment */ @@ -1844,10 +1868,36 @@ /* if we are not on an edge, check whether the major direction */ /* coincides with the current point's `out' direction, or */ /* whether we have a single-point contour */ - if ( !on_edge && + if ( !( point->flags & AF_FLAG_IGNORE ) && + !on_edge && ( FT_ABS( point->out_dir ) == major_dir || point == point->prev ) ) { + /* + * For efficiency, we restrict the number of segments to 1000, + * which is a heuristic value: it is very unlikely that a glyph + * with so many segments can be hinted in a sensible way. + * Reasons: + * + * - The glyph has really 1000 segments; this implies that it has + * at least 2000 outline points. Assuming 'normal' fonts that + * have superfluous points optimized away, viewing such a glyph + * only makes sense at large magnifications where hinting + * isn't applied anyway. + * + * - We have a broken glyph. Hinting doesn't make sense in this + * case either. + */ + if ( axis->num_segments > 1000 ) + { + FT_TRACE0(( "af_latin_hints_compute_segments:" + " more than 1000 segments in this glyph;\n" )); + FT_TRACE0(( " " + " hinting is suppressed\n" )); + axis->num_segments = 0; + return FT_Err_Ok; + } + /* this is the start of a new segment! */ segment_dir = (AF_Direction)point->out_dir; @@ -1910,7 +1960,7 @@ /* sense -- this is used to better detect and ignore serifs */ { AF_Segment segments = axis->segments; - AF_Segment segments_end = segments + axis->num_segments; + AF_Segment segments_end = FT_OFFSET( segments, axis->num_segments ); for ( segment = segments; segment < segments_end; segment++ ) @@ -1970,7 +2020,7 @@ { AF_AxisHints axis = &hints->axis[dim]; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); FT_Pos len_threshold, len_score, dist_score, max_width; AF_Segment seg1, seg2; @@ -2022,7 +2072,7 @@ max = seg2->max_coord; /* compute maximum coordinate difference of the two segments */ - /* (this is, how much they overlap) */ + /* (that is, how much they overlap) */ len = max - min; if ( len >= len_threshold ) { @@ -2090,7 +2140,7 @@ { if ( seg2->link != seg1 ) { - seg1->link = 0; + seg1->link = NULL; seg1->serif = seg2->link; } } @@ -2115,7 +2165,7 @@ FT_Bool top_to_bottom_hinting = 0; AF_Segment segments = axis->segments; - AF_Segment segment_limit = segments + axis->num_segments; + AF_Segment segment_limit = FT_OFFSET( segments, axis->num_segments ); AF_Segment seg; #if 0 @@ -2184,7 +2234,7 @@ for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = NULL; - FT_Int ee; + FT_UInt ee; /* ignore too short segments, too wide ones, and, in this loop, */ @@ -2258,7 +2308,7 @@ for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = NULL; - FT_Int ee; + FT_UInt ee; if ( seg->dir != AF_DIR_NONE ) @@ -2314,7 +2364,7 @@ */ { AF_Edge edges = axis->edges; - AF_Edge edge_limit = edges + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); AF_Edge edge; @@ -2481,7 +2531,7 @@ { AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; AF_Edge edge = axis->edges; - AF_Edge edge_limit = edge + axis->num_edges; + AF_Edge edge_limit = FT_OFFSET( edge, axis->num_edges ); AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT]; FT_Fixed scale = latin->scale; @@ -2498,6 +2548,9 @@ FT_Pos best_dist; /* initial threshold */ + if ( edge->flags & AF_EDGE_NO_BLUE ) + continue; + /* compute the initial threshold as a fraction of the EM size */ /* (the value 40 is heuristic) */ best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); @@ -2587,12 +2640,14 @@ } - /* Initalize hinting engine. */ + /* Initialize hinting engine. */ static FT_Error af_latin_hints_init( AF_GlyphHints hints, - AF_LatinMetrics metrics ) + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + FT_Render_Mode mode; FT_UInt32 scaler_flags, other_flags; FT_Face face = metrics->root.scaler.face; @@ -2612,11 +2667,6 @@ /* compute flags depending on render mode, etc. */ mode = metrics->root.scaler.render_mode; -#if 0 /* #ifdef AF_CONFIG_OPTION_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; @@ -2654,12 +2704,6 @@ ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; -#ifdef AF_CONFIG_OPTION_USE_WARPER - /* get (global) warper flag */ - if ( !metrics->root.globals->module->warping ) - scaler_flags |= AF_SCALER_FLAG_NO_WARPER; -#endif - hints->scaler_flags = scaler_flags; hints->other_flags = other_flags; @@ -2723,6 +2767,1192 @@ } +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + + + static void + af_move_contour_vertically( AF_Point contour, + FT_Int movement ) + { + AF_Point point = contour; + AF_Point first_point = point; + + + if ( point ) + { + do + { + point->y += movement; + point = point->next; + + } while ( point != first_point ); + } + } + + + /* Move all contours higher than `limit` by `delta`. */ + static void + af_move_contours_up( AF_GlyphHints hints, + FT_Pos limit, + FT_Pos delta ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + min_y > limit ) + af_move_contour_vertically( hints->contours[contour], + delta ); + } + } + + + static void + af_move_contours_down( AF_GlyphHints hints, + FT_Pos limit, + FT_Pos delta ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + max_y < limit ) + af_move_contour_vertically( hints->contours[contour], + -delta ); + } + } + + + /* Compute vertical extrema of all contours and store them in the */ + /* `contour_y_minima` and `contour_y_maxima` arrays of `hints`. */ + static void + af_compute_vertical_extrema( AF_GlyphHints hints ) + { + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = FT_LONG_MAX; + FT_Pos max_y = FT_LONG_MIN; + + AF_Point first_point = hints->contours[contour]; + AF_Point point = first_point; + + + if ( !first_point || first_point->next->next == first_point ) + goto End_loop; + + do + { + if ( point->y < min_y ) + min_y = point->y; + if ( point->y > max_y ) + max_y = point->y; + + point = point->next; + + } while ( point != first_point ); + + End_loop: + hints->contour_y_minima[contour] = min_y; + hints->contour_y_maxima[contour] = max_y; + } + } + + + static FT_Int + af_find_highest_contour( AF_GlyphHints hints ) + { + FT_Int highest_contour = 0; + FT_Pos highest_min_y = FT_LONG_MAX; + FT_Pos highest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + /* At this point we have one 'lower' (usually the base glyph) */ + /* and one 'upper' object (usually the diacritic glyph). If */ + /* there are more contours, they must be enclosed within either */ + /* 'lower' or 'upper'. To find this enclosing 'upper' contour */ + /* it is thus sufficient to search for the contour with the */ + /* highest y maximum value. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y = hints->contour_y_minima[contour]; + FT_Pos current_max_y = hints->contour_y_maxima[contour]; + + + /* If we have two contours with the same maximum value, take */ + /* the one that has a smaller height. */ + if ( current_max_y > highest_max_y || + ( current_max_y == highest_max_y && + current_min_y > highest_min_y ) ) + { + highest_min_y = current_min_y; + highest_max_y = current_max_y; + highest_contour = contour; + } + } + + return highest_contour; + } + + + static FT_Int + af_find_second_highest_contour( AF_GlyphHints hints ) + { + FT_Int highest_contour; + FT_Pos highest_min_y; + + FT_Int second_highest_contour = 0; + FT_Pos second_highest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + if ( hints->num_contours < 3 ) + return 0; + + highest_contour = af_find_highest_contour( hints ); + highest_min_y = hints->contour_y_minima[highest_contour]; + + /* Search the contour with the largest vertical maximum that has a */ + /* vertical minimum lower than the vertical minimum of the topmost */ + /* contour. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y; + FT_Pos current_max_y; + + + if ( contour == highest_contour ) + continue; + + current_min_y = hints->contour_y_minima[contour]; + current_max_y = hints->contour_y_maxima[contour]; + + if ( current_max_y > second_highest_max_y && + current_min_y < highest_min_y ) + { + second_highest_max_y = current_max_y; + second_highest_contour = contour; + } + } + + return second_highest_contour; + } + + + static FT_Int + af_find_lowest_contour( AF_GlyphHints hints ) + { + FT_Int lowest_contour = 0; + FT_Pos lowest_min_y = FT_LONG_MAX; + FT_Pos lowest_max_y = FT_LONG_MIN; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y = hints->contour_y_minima[contour]; + FT_Pos current_max_y = hints->contour_y_maxima[contour]; + + + if ( current_min_y < lowest_min_y || + ( current_min_y == lowest_min_y && + current_max_y < lowest_max_y ) ) + { + lowest_min_y = current_min_y; + lowest_max_y = current_max_y; + lowest_contour = contour; + } + } + + return lowest_contour; + } + + + static FT_Int + af_find_second_lowest_contour( AF_GlyphHints hints ) + { + FT_Int lowest_contour; + FT_Pos lowest_max_y; + + FT_Int second_lowest_contour = 0; + FT_Pos second_lowest_min_y = FT_LONG_MAX; + + FT_Int contour; + + + if ( hints->num_contours < 3 ) + return 0; + + lowest_contour = af_find_lowest_contour( hints ); + lowest_max_y = hints->contour_y_maxima[lowest_contour]; + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos current_min_y; + FT_Pos current_max_y; + + + if ( contour == lowest_contour ) + continue; + + current_min_y = hints->contour_y_minima[contour]; + current_max_y = hints->contour_y_maxima[contour]; + + if ( current_min_y < second_lowest_min_y && + current_max_y > lowest_max_y ) + { + second_lowest_min_y = current_min_y; + second_lowest_contour = contour; + } + } + + return second_lowest_contour; + } + + + /* While aligning edges to blue zones, make the auto-hinter */ + /* ignore the ones that are higher than `pos`. */ + static void + af_prevent_top_blue_alignment( AF_GlyphHints hints, + FT_Pos pos ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + if ( edge->pos > pos ) + edge->flags |= AF_EDGE_NO_BLUE; + } + + + static void + af_prevent_bottom_blue_alignment( AF_GlyphHints hints, + FT_Pos pos ) + { + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + + + for ( edge = edges; edge < edge_limit; edge++ ) + if ( edge->pos < pos ) + edge->flags |= AF_EDGE_NO_BLUE; + } + + + static void + af_latin_get_base_glyph_blues( AF_GlyphHints hints, + FT_Bool is_capital, + AF_LatinBlue* top, + AF_LatinBlue* bottom ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)hints->metrics; + AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; + + FT_UInt top_flag; + FT_UInt bottom_flag; + + FT_UInt i; + + + top_flag = is_capital ? AF_LATIN_BLUE_TOP + : AF_LATIN_BLUE_ADJUSTMENT; + top_flag |= AF_LATIN_BLUE_ACTIVE; + + for ( i = 0; i < axis->blue_count; i++ ) + if ( ( axis->blues[i].flags & top_flag ) == top_flag ) + break; + if ( i < axis->blue_count ) + *top = &axis->blues[i]; + + bottom_flag = is_capital ? AF_LATIN_BLUE_BOTTOM + : AF_LATIN_BLUE_BOTTOM_SMALL; + bottom_flag |= AF_LATIN_BLUE_ACTIVE; + + for ( i = 0; i < axis->blue_count; i++ ) + if ( ( axis->blues[i].flags & bottom_flag ) == bottom_flag ) + break; + if ( i < axis->blue_count ) + *bottom = &axis->blues[i]; + } + + + /* Make the auto-hinter ignore top blue zones while aligning edges. */ + /* This affects everything that is higher than a vertical position */ + /* based on the lowercase or uppercase top and bottom blue zones */ + /* (depending on `is_capital`). */ + static void + af_latin_ignore_top( AF_GlyphHints hints, + AF_LatinBlue top_blue, + AF_LatinBlue bottom_blue ) + { + FT_Pos base_glyph_height; + FT_Pos limit; + + + /* Ignore blue zones that are higher than a heuristic threshold */ + /* (value 7 corresponds to approx. 14%, which should be sufficient */ + /* to exceed the height of uppercase serifs. We also add a quarter */ + /* of a pixel as a safety measure. */ + base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur; + limit = top_blue->shoot.cur + base_glyph_height / 7 + 16; + + af_prevent_top_blue_alignment( hints, limit ); + } + + + static void + af_latin_ignore_bottom( AF_GlyphHints hints, + AF_LatinBlue top_blue, + AF_LatinBlue bottom_blue ) + { + FT_Pos base_glyph_height; + FT_Pos limit; + + + base_glyph_height = top_blue->shoot.cur - bottom_blue->shoot.cur; + limit = bottom_blue->shoot.cur - base_glyph_height / 7 - 16; + + af_prevent_bottom_blue_alignment( hints, limit ); + } + + + static void + af_touch_contour( AF_GlyphHints hints, + FT_Int contour ) + { + AF_Point first_point = hints->contours[contour]; + AF_Point p = first_point; + + + do + { + p = p->next; + + p->flags |= AF_FLAG_IGNORE; + if ( !( p->flags & AF_FLAG_CONTROL ) ) + p->flags |= AF_FLAG_TOUCH_Y; + + } while ( p != first_point ); + } + + + static void + af_touch_top_contours( AF_GlyphHints hints, + FT_Int limit_contour ) + { + FT_Pos limit = hints->contour_y_minima[limit_contour]; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + min_y >= limit ) + af_touch_contour( hints, contour ); + } + } + + + static void + af_touch_bottom_contours( AF_GlyphHints hints, + FT_Int limit_contour ) + { + FT_Pos limit = hints->contour_y_minima[limit_contour]; + + FT_Int contour; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y = hints->contour_y_minima[contour]; + FT_Pos max_y = hints->contour_y_maxima[contour]; + + + if ( min_y < max_y && + max_y <= limit ) + af_touch_contour( hints, contour ); + } + } + + + /* Stretch tilde vertically, if necessary, and return the height */ + /* difference between the original and the stretched outline. */ + static FT_Pos + af_latin_stretch_top_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = hints->contour_y_minima[tilde_contour]; + FT_Pos max_y = hints->contour_y_maxima[tilde_contour]; + + FT_Pos min_measurement = FT_LONG_MAX; + FT_Bool measurement_taken = FALSE; + + FT_Pos height; + FT_Pos extremum_threshold; + FT_Pos target_height; + + + if ( min_y == max_y ) + return 0; + + FT_TRACE4(( "af_latin_stretch_top_tilde: min y: %ld, max y: %ld\n", + min_y, max_y )); + + height = SUB_LONG( max_y, min_y ); + extremum_threshold = height / 8; /* Value 8 is heuristic. */ + + /* Find points that are local vertical round extrema, and which */ + /* do not coincide with the vertical extreme values (i.e., we */ + /* search for the 'other' wiggles in the tilde), then measure the */ + /* distance to the vertical extreme values. Try to find the one */ + /* with the smallest distance. */ + /* */ + /* The algorithm only works for tilde shapes that don't deviate */ + /* from the standard shape too much. In particular, the wiggles */ + /* must be round extrema. */ + do + { + p = p->next; + + if ( !( p->flags & AF_FLAG_CONTROL ) && + p->prev->y == p->y && p->next->y == p->y && + p->y != min_y && p->y != max_y && + p->prev->flags & AF_FLAG_CONTROL && + p->next->flags & AF_FLAG_CONTROL ) + { + /* This point could be a candidate. Find the next and previous */ + /* on-curve points, and make sure they are both either above or */ + /* below the point, then make the measurement. */ + AF_Point prev_on = p->prev; + AF_Point next_on = p->next; + + FT_Pos measurement; + + + while ( prev_on->flags & AF_FLAG_CONTROL ) + prev_on = prev_on->prev; + while ( next_on->flags & AF_FLAG_CONTROL ) + next_on = next_on->next; + + if ( next_on->y > p->y && prev_on->y > p->y ) + measurement = p->y - min_y; + else if ( next_on->y < p->y && prev_on->y < p->y ) + measurement = max_y - p->y; + else + continue; + + /* Ignore hits that are too near to a vertical extremum. */ + if ( measurement < extremum_threshold ) + continue; + + if ( !measurement_taken || measurement < min_measurement ) + { + measurement_taken = TRUE; + min_measurement = measurement; + } + } + + } while ( p != first_point ); + + if ( !measurement_taken ) + min_measurement = 0; + + FT_TRACE4(( "af_latin_stretch_top_tilde: min measurement %ld\n", + min_measurement )); + + /* To preserve the stretched shape we prevent that the tilde */ + /* gets auto-hinted; we do this for all contours equal or */ + /* above the vertical minimum of `tilde_contour`. */ + af_touch_top_contours( hints, tilde_contour ); + + /* XXX This is an important element of the algorithm; */ + /* we need a description. */ + target_height = min_measurement + 64; + if ( height >= target_height ) + return 0; + + /* Do the scaling. */ + p = first_point; + do + { + p = p->next; + /* We adjust the height of the diacritic only, which means */ + /* we are never dealing with large numbers and can thus avoid */ + /* `FT_MulFix`. */ + p->y = ( ( p->y - min_y ) * target_height / height ) + min_y; + + } while ( p != first_point ); + + return target_height - height; + } + + + static FT_Pos + af_latin_stretch_bottom_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = hints->contour_y_minima[tilde_contour]; + FT_Pos max_y = hints->contour_y_maxima[tilde_contour]; + + FT_Pos min_measurement = FT_LONG_MAX; + FT_Bool measurement_taken = FALSE; + + FT_Pos height; + FT_Pos extremum_threshold; + FT_Pos target_height; + + + if ( min_y == max_y ) + return 0; + + FT_TRACE4(( "af_latin_stretch_bottom_tilde: min y: %ld, max y: %ld\n", + min_y, max_y )); + + height = SUB_LONG( max_y, min_y ); + extremum_threshold = height / 8; + + do + { + p = p->next; + + if ( !( p->flags & AF_FLAG_CONTROL ) && + p->prev->y == p->y && p->next->y == p->y && + p->y != min_y && p->y != max_y && + p->prev->flags & AF_FLAG_CONTROL && + p->next->flags & AF_FLAG_CONTROL ) + { + AF_Point prev_on = p->prev; + AF_Point next_on = p->next; + + FT_Pos measurement; + + + while ( prev_on->flags & AF_FLAG_CONTROL ) + prev_on = prev_on->prev; + while ( next_on->flags & AF_FLAG_CONTROL ) + next_on = next_on->next; + + if ( next_on->y > p->y && prev_on->y > p->y ) + measurement = p->y - min_y; + else if ( next_on->y < p->y && prev_on->y < p->y ) + measurement = max_y - p->y; + else + continue; + + if ( measurement < extremum_threshold ) + continue; + + if ( !measurement_taken || measurement < min_measurement ) + { + measurement_taken = TRUE; + min_measurement = measurement; + } + } + + } while ( p != first_point ); + + if ( !measurement_taken ) + min_measurement = 0; + + FT_TRACE4(( "af_latin_stretch_bottom_tilde: min measurement %ld\n", + min_measurement )); + + af_touch_bottom_contours( hints, tilde_contour ); + + target_height = min_measurement + 64; + if ( height >= target_height ) + return 0; + + p = first_point; + do + { + p = p->next; + p->y = ( ( p->y - max_y ) * target_height / height ) + max_y; + + } while ( p != first_point ); + + return target_height - height; + } + + + /* + As part of `af_latin_stretch_top_tilde`, normally all points in the + tilde are marked as touched, so the existing grid fitting will leave the + tilde misaligned with the grid. + + This function moves the tilde contour down to be grid-fitted. We assume + that if moving the tilde down would cause it to touch or overlap another + countour, the vertical adjustment step will fix it. + + Because the vertical adjustment step comes after all other grid-fitting + steps, the top edge of the contour under the tilde is usually aligned + with a horizontal grid line. The vertical gap enforced by the vertical + adjustment is exactly one pixel, so if the top edge of the contour below + the tilde is on a grid line, the resulting tilde contour will also be + grid-aligned. + + But in cases where the gap is already big enough so that the vertical + adjustment does nothing, this function ensures that even without the + intervention of the vertical adjustment step, the tilde will be + grid-aligned. + + Return the vertical alignment amount. + */ + static FT_Pos + af_latin_align_top_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = p->y; + FT_Pos max_y = p->y; + + FT_Pos min_y_rounded; + FT_Pos delta; + FT_Pos height; + + + /* Find vertical extrema of the (now stretched) tilde contour. */ + do + { + p = p->next; + if ( p->y < min_y ) + min_y = p->y; + if ( p->y > max_y ) + max_y = p->y; + + } while ( p != first_point ); + + /* Align bottom of the tilde to the grid. */ + min_y_rounded = FT_PIX_ROUND( min_y ); + delta = min_y_rounded - min_y; + height = max_y - min_y; + + /* If the tilde is less than 3 pixels tall, snap the center of it */ + /* to the grid instead of the bottom to improve readability. */ + if ( height < 64 * 3 ) + delta += ( FT_PIX_ROUND( height ) - height ) / 2; + + af_move_contour_vertically( first_point, delta ); + + return delta; + } + + + static FT_Pos + af_latin_align_bottom_tilde( AF_GlyphHints hints, + FT_Int tilde_contour ) + { + AF_Point p = hints->contours[tilde_contour]; + AF_Point first_point = p; + + FT_Pos min_y = p->y; + FT_Pos max_y = p->y; + + FT_Pos max_y_rounded; + FT_Pos delta; + FT_Pos height; + + + do + { + p = p->next; + if ( p->y < min_y ) + min_y = p->y; + if ( p->y > max_y ) + max_y = p->y; + + } while ( p != first_point ); + + max_y_rounded = FT_PIX_ROUND( max_y ); + delta = max_y_rounded - max_y; + height = max_y - min_y; + + if ( height < 64 * 3 ) + delta -= ( FT_PIX_ROUND( height ) - height ) / 2; + + af_move_contour_vertically( first_point, delta ); + + return delta; + } + + + /* Return 1 if the given contour overlaps horizontally with the bounding */ + /* box of all other contours combined. This is a helper for function */ + /* `af_glyph_hints_apply_vertical_separation_adjustments`. */ + static FT_Bool + af_check_contour_horizontal_overlap( AF_GlyphHints hints, + FT_Int contour_index ) + { + FT_Pos contour_max_x = FT_LONG_MIN; + FT_Pos contour_min_x = FT_LONG_MAX; + FT_Pos others_max_x = FT_LONG_MIN; + FT_Pos others_min_x = FT_LONG_MAX; + + FT_Int contour; + + FT_Bool horizontal_overlap; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point first_point = hints->contours[contour]; + AF_Point p = first_point; + + + /* Ignore dimensionless contours (i.e., contours with only one or */ + /* two points). */ + if ( first_point->next->next == first_point ) + continue; + + do + { + p = p->next; + + if ( contour == contour_index ) + { + if ( p->x < contour_min_x ) + contour_min_x = p->x; + if ( p->x > contour_max_x ) + contour_max_x = p->x; + } + else + { + if ( p->x < others_min_x ) + others_min_x = p->x; + if ( p->x > others_max_x ) + others_max_x = p->x; + } + } while ( p != first_point ); + } + + horizontal_overlap = + ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) || + ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) || + ( contour_max_x >= others_max_x && contour_min_x <= others_min_x ); + + return horizontal_overlap; + } + + + static void + af_glyph_hints_apply_vertical_separation_adjustments( + AF_GlyphHints hints, + AF_Dimension dim, + FT_UInt glyph_index, + FT_Pos accent_height_limit, + FT_Hash reverse_charmap ) + { + FT_Bool adjust_top = FALSE; + FT_Bool adjust_below_top = FALSE; + + FT_Bool adjust_bottom = FALSE; + FT_Bool adjust_above_bottom = FALSE; + + size_t* val; + FT_UInt32 adj_type = AF_ADJUST_NONE; + + + FT_TRACE4(( "Entering" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + + if ( dim != AF_DIMENSION_VERT ) + return; + + val = ft_hash_num_lookup( (FT_Int)glyph_index, reverse_charmap ); + if ( val ) + { + FT_UInt codepoint = *val; + + + adj_type = af_adjustment_database_lookup( codepoint ); + + if ( adj_type ) + { + adjust_top = !!( adj_type & AF_ADJUST_UP ); + adjust_below_top = !!( adj_type & AF_ADJUST_UP2 ); + + adjust_bottom = !!( adj_type & AF_ADJUST_DOWN ); + adjust_above_bottom = !!( adj_type & AF_ADJUST_DOWN2 ); + } + } + + if ( ( ( adjust_top || adjust_bottom ) && + hints->num_contours >= 2 ) || + ( ( adjust_below_top || adjust_above_bottom ) && + hints->num_contours >= 3 ) ) + { + /* Recompute vertical extrema, this time acting on already */ + /* auto-hinted outlines. */ + af_compute_vertical_extrema( hints ); + } + + if ( ( adjust_top && hints->num_contours >= 2 ) || + ( adjust_below_top && hints->num_contours >= 3 ) ) + { + FT_Int high_contour; + FT_Pos high_min_y; + FT_Pos high_max_y; + FT_Pos high_height; + + FT_Int tilde_contour; + FT_Pos tilde_min_y; + FT_Pos tilde_max_y; + FT_Pos tilde_height; + + FT_Int contour; + FT_Bool horizontal_overlap; + + FT_Pos min_distance = 64; + FT_Pos adjustment_amount; + FT_Pos calculated_amount; + FT_Pos centering_adjustment = 0; + FT_Pos pos; + + FT_Bool is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP ); + FT_Bool is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 ); + + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment: %s\n", + adjust_top ? "AF_ADJUST_TOP" : "AF_ADJUST_TOP2" )); + + high_contour = adjust_below_top + ? af_find_second_highest_contour( hints ) + : af_find_highest_contour( hints ); + + /* Check for a horizontal overlap between the high contour and the */ + /* rest. If there is no overlap, do not adjust. */ + horizontal_overlap = + af_check_contour_horizontal_overlap( hints, high_contour ); + if ( !horizontal_overlap ) + { + FT_TRACE4(( " High contour does not horizontally overlap" + " with other contours.\n" + " Skipping adjustment.\n" )); + return; + } + + high_min_y = hints->contour_y_minima[high_contour]; + high_max_y = hints->contour_y_maxima[high_contour]; + high_height = high_max_y - high_min_y; + + if ( high_height > accent_height_limit ) + { + FT_TRACE4(( " High contour height (%.2f) exceeds accent height" + " limit (%.2f).\n" + " Skipping adjustment.\n", + (double)high_height / 64, + (double)accent_height_limit / 64 )); + return; + } + + /* If the difference between the vertical minimum of the high */ + /* contour and the vertical maximum of another contour is less */ + /* than a pixel, shift up the high contour to make the distance */ + /* one pixel. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y; + FT_Pos max_y; + FT_Pos distance; + + + if ( contour == high_contour ) + continue; + + min_y = hints->contour_y_minima[contour]; + max_y = hints->contour_y_maxima[contour]; + + /* We also check that the y minimum of the 'other' contour */ + /* is below the high contour to avoid potential false hits */ + /* with contours enclosed in the high one. */ + distance = high_min_y - max_y; + if ( distance < 64 && + distance < min_distance && + min_y < high_min_y ) + min_distance = distance; + } + + adjustment_amount = 64 - min_distance; + + if ( is_top_tilde || is_below_top_tilde ) + { + tilde_contour = adjust_top + ? high_contour + : ( is_below_top_tilde + ? high_contour + : af_find_highest_contour( hints ) ); + + tilde_min_y = hints->contour_y_minima[tilde_contour]; + tilde_max_y = hints->contour_y_maxima[tilde_contour]; + tilde_height = tilde_max_y - tilde_min_y; + + /* The vertical separation adjustment potentially undoes a */ + /* tilde center alignment. If it would grid-align a tilde */ + /* less than 3 pixels in height, shift additionally to */ + /* re-center the tilde. */ + + pos = high_min_y + adjustment_amount; + if ( adjust_below_top && is_top_tilde ) + pos += high_height; + + if ( pos % 64 == 0 && tilde_height < 3 * 64 ) + { + centering_adjustment = ( FT_PIX_ROUND( tilde_height ) - + tilde_height ) / 2; + + FT_TRACE4(( " Additional tilde centering adjustment: %ld\n", + centering_adjustment )); + } + } + + if ( ( adjust_top && is_top_tilde ) || + ( adjust_below_top && is_below_top_tilde ) ) + calculated_amount = adjustment_amount + centering_adjustment; + else + calculated_amount = adjustment_amount; + + /* allow a delta of 2/64px to handle rounding differences */ + FT_TRACE4(( " Calculated adjustment amount: %ld%s\n", + calculated_amount, + ( calculated_amount < -2 || + ( adjustment_amount > 66 && calculated_amount > 66 ) ) + ? " (out of range [-2;66], not adjusting)" : "" )); + + if ( calculated_amount != 0 && + calculated_amount >= -2 && + ( calculated_amount <= 66 || adjustment_amount <= 66 ) ) + { + /* Value 8 is heuristic. */ + FT_Pos height_delta = high_height / 8; + FT_Pos min_y_limit = high_min_y - height_delta; + + + FT_TRACE4(( " Pushing high contour %ld units up\n", + calculated_amount )); + + /* While we use only a single contour (the 'high' one) for */ + /* computing `adjustment_amount`, we apply it to all contours */ + /* that are (approximately) in the same vertical range or */ + /* higher. This covers, for example, the inner contour of */ + /* the Czech ring accent or the second acute accent in the */ + /* Hungarian double acute accent. */ + af_move_contours_up( hints, min_y_limit, adjustment_amount ); + + if ( adjust_below_top && is_top_tilde ) + { + FT_TRACE4(( " Pushing top tilde %ld units up\n", + centering_adjustment )); + + af_move_contours_up( hints, + min_y_limit + high_height, + centering_adjustment ); + } + } + } + + if ( ( adjust_bottom && hints->num_contours >= 2 ) || + ( adjust_above_bottom && hints->num_contours >= 3 ) ) + { + FT_Int low_contour; + FT_Pos low_min_y; + FT_Pos low_max_y; + FT_Pos low_height; + + FT_Int tilde_contour; + FT_Pos tilde_min_y; + FT_Pos tilde_max_y; + FT_Pos tilde_height; + + FT_Int contour; + FT_Bool horizontal_overlap; + + FT_Pos min_distance = 64; + FT_Pos adjustment_amount; + FT_Pos calculated_amount; + FT_Pos centering_adjustment = 0; + FT_Pos pos; + + FT_Bool is_bottom_tilde = + !!( adj_type & AF_ADJUST_TILDE_BOTTOM ); + FT_Bool is_above_bottom_tilde = + !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 ); + + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment: %s\n", + adjust_bottom ? "AF_ADJUST_DOWN": "AF_ADJUST_DOWN2" )); + + low_contour = adjust_above_bottom + ? af_find_second_lowest_contour( hints ) + : af_find_lowest_contour( hints ); + + horizontal_overlap = + af_check_contour_horizontal_overlap( hints, low_contour ); + if ( !horizontal_overlap ) + { + FT_TRACE4(( " Low contour does not horizontally overlap" + " with other contours.\n" + " Skipping adjustment.\n" )); + return; + } + + low_min_y = hints->contour_y_minima[low_contour]; + low_max_y = hints->contour_y_maxima[low_contour]; + low_height = low_max_y - low_min_y; + + if ( low_height > accent_height_limit ) + { + FT_TRACE4(( " Low contour height (%.2f) exceeds accent height" + " limit (%.2f).\n" + " Skipping adjustment.\n", + (double)low_height / 64, + (double)accent_height_limit / 64 )); + return; + } + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + FT_Pos min_y; + FT_Pos max_y; + FT_Pos distance; + + + if ( contour == low_contour ) + continue; + + min_y = hints->contour_y_minima[contour]; + max_y = hints->contour_y_maxima[contour]; + + distance = min_y - low_max_y; + if ( distance < 64 && + distance < min_distance && + max_y > low_max_y ) + min_distance = distance; + } + + adjustment_amount = 64 - min_distance; + + if ( is_bottom_tilde || is_above_bottom_tilde ) + { + tilde_contour = adjust_bottom + ? low_contour + : ( is_above_bottom_tilde + ? low_contour + : af_find_lowest_contour( hints ) ); + + tilde_min_y = hints->contour_y_minima[tilde_contour]; + tilde_max_y = hints->contour_y_maxima[tilde_contour]; + tilde_height = tilde_max_y - tilde_min_y; + + pos = low_max_y - adjustment_amount; + if ( adjust_above_bottom && is_bottom_tilde ) + pos -= low_height; + + if ( pos % 64 == 0 && tilde_height < 3 * 64 ) + { + centering_adjustment = ( FT_PIX_ROUND( tilde_height ) - + tilde_height ) / 2; + + FT_TRACE4(( " Additional tilde centering adjustment: %ld\n", + centering_adjustment )); + } + } + + if ( ( adjust_bottom && is_bottom_tilde ) || + ( adjust_above_bottom && is_above_bottom_tilde ) ) + calculated_amount = adjustment_amount + centering_adjustment; + else + calculated_amount = adjustment_amount; + + FT_TRACE4(( " Calculated adjustment amount: %ld%s\n", + calculated_amount, + ( calculated_amount < -2 || + ( adjustment_amount > 66 && calculated_amount > 66 ) ) + ? " (out of range [-2;66], not adjusting)" : "" )); + + if ( calculated_amount != 0 && + calculated_amount >= -2 && + ( calculated_amount <= 66 || adjustment_amount <= 66 ) ) + { + FT_Pos height_delta = low_height / 8; + FT_Pos max_y_limit = low_max_y + height_delta; + + + FT_TRACE4(( " Pushing low contour %ld units down\n", + calculated_amount )); + + af_move_contours_down( hints, max_y_limit, adjustment_amount ); + + if ( adjust_above_bottom && is_bottom_tilde ) + { + FT_TRACE4(( " Pushing bottom tilde %ld units down\n", + centering_adjustment )); + + af_move_contours_down( hints, + max_y_limit - low_height, + centering_adjustment ); + } + } + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !( ( ( adjust_top || adjust_bottom ) && + hints->num_contours >= 2 ) || + ( ( adjust_below_top || adjust_above_bottom ) && + hints->num_contours >= 3 ) ) ) + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " No vertical adjustment applied\n" )); +#endif + + FT_TRACE4(( "Exiting" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + } + + +#undef FT_COMPONENT +#define FT_COMPONENT aflatin + + /* Compute the snapped width of a given stem, ignoring very thin ones. */ /* There is a lot of voodoo in this function; changing the hard-coded */ /* parameters influence the whole hinting process. */ @@ -2945,10 +4175,11 @@ stem_edge->pos = base_edge->pos + fitted_width; - FT_TRACE5(( " LINK: edge %d (opos=%.2f) linked to %.2f," + FT_TRACE5(( " LINK: edge %td (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 )); + stem_edge - hints->axis[dim].edges, + (double)stem_edge->opos / 64, (double)stem_edge->pos / 64, + (double)dist / 64, (double)fitted_width / 64 )); } @@ -2983,13 +4214,15 @@ 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_PtrDist n_edges; - AF_Edge edge; - AF_Edge anchor = NULL; - FT_Int has_serifs = 0; + AF_AxisHints axis = &hints->axis[dim]; + + AF_Edge edges = axis->edges; + AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges ); + AF_Edge edge; + FT_PtrDist n_edges; + + AF_Edge anchor = NULL; + FT_Bool has_non_stem_edges = 0; AF_StyleClass style_class = hints->metrics->style_class; AF_ScriptClass script_class = af_script_classes[style_class->script]; @@ -3069,15 +4302,17 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !anchor ) - FT_TRACE5(( " BLUE_ANCHOR: edge %d (opos=%.2f) snapped to %.2f," - " was %.2f (anchor=edge %d)\n", - edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0, - edge1->pos / 64.0, edge - edges )); + FT_TRACE5(( " BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f," + " was %.2f (anchor=edge %td)\n", + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64, edge - edges )); else - FT_TRACE5(( " BLUE: edge %d (opos=%.2f) snapped to %.2f," + FT_TRACE5(( " BLUE: edge %td (opos=%.2f) snapped to %.2f," " was %.2f\n", - edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0, - edge1->pos / 64.0 )); + edge1 - edges, + (double)edge1->opos / 64, (double)blue->fit / 64, + (double)edge1->pos / 64 )); num_actions++; #endif @@ -3114,7 +4349,7 @@ edge2 = edge->link; if ( !edge2 ) { - has_serifs++; + has_non_stem_edges = TRUE; continue; } @@ -3123,7 +4358,7 @@ /* this should not happen, but it's better to be safe */ if ( edge2->blue_edge ) { - FT_TRACE5(( " ASSERTION FAILED for edge %d\n", edge2 - edges )); + FT_TRACE5(( " ASSERTION FAILED for edge %td\n", edge2 - edges )); af_latin_align_linked_edge( hints, dim, edge2, edge ); edge->flags |= AF_EDGE_DONE; @@ -3191,11 +4426,11 @@ anchor = edge; edge->flags |= AF_EDGE_DONE; - FT_TRACE5(( " ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)" + FT_TRACE5(( " ANCHOR: edge %td (opos=%.2f) and %td (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 - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); af_latin_align_linked_edge( hints, dim, edge, edge2 ); @@ -3220,9 +4455,9 @@ if ( edge2->flags & AF_EDGE_DONE ) { - FT_TRACE5(( " ADJUST: edge %d (pos=%.2f) moved to %.2f\n", - edge - edges, edge->pos / 64.0, - ( edge2->pos - cur_len ) / 64.0 )); + FT_TRACE5(( " ADJUST: edge %td (pos=%.2f) moved to %.2f\n", + edge - edges, (double)edge->pos / 64, + (double)( edge2->pos - cur_len ) / 64 )); edge->pos = edge2->pos - cur_len; } @@ -3261,11 +4496,11 @@ edge->pos = cur_pos1 - cur_len / 2; edge2->pos = cur_pos1 + cur_len / 2; - FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (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 - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); } else @@ -3292,11 +4527,11 @@ edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; edge2->pos = edge->pos + cur_len; - FT_TRACE5(( " STEM: edge %d (opos=%.2f) linked to %d (opos=%.2f)" + FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (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 - edges, (double)edge->opos / 64, + edge2 - edges, (double)edge2->opos / 64, + (double)edge->pos / 64, (double)edge2->pos / 64 )); } #ifdef FT_DEBUG_LEVEL_TRACE @@ -3315,10 +4550,10 @@ if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", edge - edges, - edge->pos / 64.0, - edge[-1].pos / 64.0 )); + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); num_actions++; #endif @@ -3391,7 +4626,7 @@ } } - if ( has_serifs || !anchor ) + if ( has_non_stem_edges || !anchor ) { /* * now hint the remaining edges (serifs and single) in order @@ -3409,27 +4644,94 @@ if ( edge->serif ) { + AF_Edge e, top, bottom; + FT_Pos min_pos, max_pos; + + + /* Check whether we have a real serif -- if there are */ + /* other edges with overlapping (or enclosed) segments */ + /* between the primary and serif edge, we have not. */ + /* */ + /* Such a situation might happen if an accent is very */ + /* near to its base glyph (for example, Vietnamese */ + /* uppercase letters with two accents in `arial.ttf`), */ + /* and the segment detection algorithm classifies the */ + /* top of the accent incorrectly as a serif. */ delta = edge->serif->opos - edge->opos; if ( delta < 0 ) + { delta = -delta; + + top = edge; + bottom = edge->serif; + } + else + { + top = edge->serif; + bottom = edge; + } + + if ( delta < 64 + 32 ) + { + /* take care of outline orientation while computing extrema */ + min_pos = FT_MIN( FT_MIN( FT_MIN( top->first->first->v, + top->first->last->v ), + FT_MIN( top->last->first->v, + top->last->last->v ) ), + FT_MIN( FT_MIN( bottom->first->first->v, + bottom->first->last->v ), + FT_MIN( bottom->last->first->v, + bottom->last->last->v ) ) ); + max_pos = FT_MAX( FT_MAX( FT_MAX( top->first->first->v, + top->first->last->v ), + FT_MAX( top->last->first->v, + top->last->last->v ) ), + FT_MAX( FT_MAX( bottom->first->first->v, + bottom->first->last->v ), + FT_MAX( bottom->last->first->v, + bottom->last->last->v ) ) ); + + for ( e = bottom + 1; e < top; e++ ) + { + FT_Pos e_min = FT_MIN( FT_MIN( e->first->first->v, + e->first->last->v ), + FT_MIN( e->last->first->v, + e->last->last->v ) ); + FT_Pos e_max = FT_MAX( FT_MAX( e->first->first->v, + e->first->last->v ), + FT_MAX( e->last->first->v, + e->last->last->v ) ); + + if ( !( ( e_min < min_pos && e_max < min_pos ) || + ( e_min > max_pos && e_max > max_pos ) ) ) + { + delta = 1000; /* not a real serif */ + break; + } + } + + if ( delta == 1000 ) + continue; + } } if ( delta < 64 + 16 ) { af_latin_align_serif_edge( hints, edge->serif, edge ); - FT_TRACE5(( " SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)" + FT_TRACE5(( " SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)" " aligned to %.2f\n", - edge - edges, edge->opos / 64.0, - edge->serif - edges, edge->serif->opos / 64.0, - edge->pos / 64.0 )); + edge - edges, (double)edge->opos / 64, + edge->serif - edges, (double)edge->serif->opos / 64, + (double)edge->pos / 64 )); } else if ( !anchor ) { edge->pos = FT_PIX_ROUND( edge->opos ); anchor = edge; - FT_TRACE5(( " SERIF_ANCHOR: edge %d (opos=%.2f)" + FT_TRACE5(( " SERIF_ANCHOR: edge %td (opos=%.2f)" " snapped to %.2f\n", - edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); } else { @@ -3455,19 +4757,20 @@ after->pos - before->pos, after->opos - before->opos ); - FT_TRACE5(( " 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 )); + FT_TRACE5(( " SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f" + " from %td (opos=%.2f)\n", + edge - edges, (double)edge->opos / 64, + (double)edge->pos / 64, + before - edges, (double)before->opos / 64 )); } else { edge->pos = anchor->pos + ( ( edge->opos - anchor->opos + 16 ) & ~31 ); - FT_TRACE5(( " SERIF_LINK2: edge %d (opos=%.2f)" + FT_TRACE5(( " SERIF_LINK2: edge %td (opos=%.2f)" " snapped to %.2f\n", - edge - edges, edge->opos / 64.0, edge->pos / 64.0 )); + edge - edges, + (double)edge->opos / 64, (double)edge->pos / 64 )); } } @@ -3485,10 +4788,10 @@ if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", edge - edges, - edge->pos / 64.0, - edge[-1].pos / 64.0 )); + (double)edge->pos / 64, + (double)edge[-1].pos / 64 )); num_actions++; #endif @@ -3506,10 +4809,10 @@ if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( " BOUND: edge %d (pos=%.2f) moved to %.2f\n", + FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n", edge - edges, - edge->pos / 64.0, - edge[1].pos / 64.0 )); + (double)edge->pos / 64, + (double)edge[1].pos / 64 )); num_actions++; #endif @@ -3534,13 +4837,17 @@ af_latin_hints_apply( FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline* outline, - AF_LatinMetrics metrics ) + AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */ { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + FT_Error error; int dim; AF_LatinAxis axis; + FT_Pos accent_height_limit = 0; + error = af_glyph_hints_reload( hints, outline ); if ( error ) @@ -3560,11 +4867,172 @@ if ( AF_HINTS_DO_VERTICAL( hints ) ) { + size_t* val; + + FT_Int top_tilde_contour = 0; + FT_Int bottom_tilde_contour = 0; + + FT_Int below_top_tilde_contour = 0; + FT_Int above_bottom_tilde_contour = 0; + + AF_LatinBlue capital_top_blue = NULL; + AF_LatinBlue capital_bottom_blue = NULL; + + AF_LatinBlue small_top_blue = NULL; + AF_LatinBlue small_bottom_blue = NULL; + + FT_Bool have_flags = FALSE; + + FT_Bool is_top_tilde = FALSE; + FT_Bool is_bottom_tilde = FALSE; + + FT_Bool is_below_top_tilde = FALSE; + FT_Bool is_above_bottom_tilde = FALSE; + + FT_Bool ignore_capital_top = FALSE; + FT_Bool ignore_capital_bottom = FALSE; + + FT_Bool ignore_small_top = FALSE; + FT_Bool ignore_small_bottom = FALSE; + + FT_Bool do_height_check = TRUE; + + FT_Pos limit; + FT_Pos y_offset; + + + val = ft_hash_num_lookup( (FT_Int)glyph_index, + metrics->root.reverse_charmap ); + if ( val ) + { + FT_UInt codepoint = *val; + FT_UInt32 adj_type = af_adjustment_database_lookup( codepoint ); + + + if ( adj_type ) + { + have_flags = !!adj_type; + + is_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP ); + is_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM ); + + is_below_top_tilde = !!( adj_type & AF_ADJUST_TILDE_TOP2 ); + is_above_bottom_tilde = !!( adj_type & AF_ADJUST_TILDE_BOTTOM2 ); + + ignore_capital_top = !!( adj_type & AF_IGNORE_CAPITAL_TOP ); + ignore_capital_bottom = !!( adj_type & AF_IGNORE_CAPITAL_BOTTOM ); + + ignore_small_top = !!( adj_type & AF_IGNORE_SMALL_TOP ); + ignore_small_bottom = !!( adj_type & AF_IGNORE_SMALL_BOTTOM ); + + do_height_check = !( adj_type & AF_ADJUST_NO_HEIGHT_CHECK ); + } + } + + if ( is_top_tilde || is_bottom_tilde || + is_below_top_tilde || is_above_bottom_tilde ) + af_compute_vertical_extrema( hints ); + + /* Process inner tilde glyphs first. */ + if ( is_below_top_tilde ) + { + below_top_tilde_contour = af_find_second_highest_contour( hints ); + + y_offset = af_latin_stretch_top_tilde( + hints, below_top_tilde_contour ); + y_offset += af_latin_align_top_tilde( + hints, below_top_tilde_contour ); + + limit = hints->contour_y_minima[below_top_tilde_contour]; + af_move_contours_up( hints, limit, y_offset ); + } + if ( is_above_bottom_tilde ) + { + above_bottom_tilde_contour = af_find_second_lowest_contour( hints ); + + y_offset = af_latin_stretch_bottom_tilde( + hints, above_bottom_tilde_contour ); + y_offset -= af_latin_align_bottom_tilde( + hints, above_bottom_tilde_contour ); + + limit = hints->contour_y_maxima[above_bottom_tilde_contour]; + af_move_contours_down( hints, limit, y_offset ); + } + + if ( is_top_tilde ) + { + top_tilde_contour = af_find_highest_contour( hints ); + + (void)af_latin_stretch_top_tilde( hints, top_tilde_contour ); + (void)af_latin_align_top_tilde( hints, top_tilde_contour ); + } + if ( is_bottom_tilde ) + { + bottom_tilde_contour = af_find_lowest_contour( hints ); + + (void)af_latin_stretch_bottom_tilde( hints, bottom_tilde_contour ); + (void)af_latin_align_bottom_tilde( hints, bottom_tilde_contour ); + } + axis = &metrics->axis[AF_DIMENSION_VERT]; error = af_latin_hints_detect_features( hints, axis->width_count, axis->widths, AF_DIMENSION_VERT ); + + if ( have_flags ) + { + af_latin_get_base_glyph_blues( hints, + TRUE, + &capital_top_blue, + &capital_bottom_blue ); + af_latin_get_base_glyph_blues( hints, + FALSE, + &small_top_blue, + &small_bottom_blue ); + + if ( do_height_check ) + { + /* Set a heuristic limit for the accent height so that */ + /* `af_glyph_hints_apply_vertical_separation_adjustments` */ + /* can correctly ignore the case where an accent is */ + /* unexpectedly not the highest (or lowest) contour. */ + + /* Either 2/3 of the lowercase blue zone height... */ + if ( small_top_blue && small_bottom_blue ) + accent_height_limit = 2 * ( small_top_blue->shoot.cur - + small_bottom_blue->shoot.cur ) / 3; + /* or 1/2 of the uppercase blue zone height... */ + else if ( capital_top_blue && capital_bottom_blue ) + accent_height_limit = ( capital_top_blue->shoot.cur - + capital_bottom_blue->shoot.cur ) / 2; + /* or half of the standard PostScript ascender value (8/10) */ + /* of the EM value, scaled. */ + else + accent_height_limit = FT_MulFix( metrics->units_per_em * 4 / 10, + metrics->root.scaler.y_scale ); + } + } + + if ( capital_top_blue && capital_bottom_blue ) + { + if ( ignore_capital_top ) + af_latin_ignore_top( hints, + capital_top_blue, capital_bottom_blue ); + if ( ignore_capital_bottom ) + af_latin_ignore_bottom( hints, + capital_top_blue, capital_bottom_blue ); + } + if ( small_top_blue && small_bottom_blue ) + { + if ( ignore_small_top ) + af_latin_ignore_top( hints, + small_top_blue, small_bottom_blue ); + if ( ignore_small_bottom ) + af_latin_ignore_bottom( hints, + small_top_blue, small_bottom_blue ); + } + if ( error ) goto Exit; @@ -3576,24 +5044,6 @@ /* grid-fit the outline */ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { -#ifdef AF_CONFIG_OPTION_USE_WARPER - if ( dim == AF_DIMENSION_HORZ && - metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL && - AF_HINTS_DO_WARP( hints ) ) - { - AF_WarperRec warper; - FT_Fixed scale; - FT_Pos delta; - - - af_warper_compute( &warper, hints, (AF_Dimension)dim, - &scale, &delta ); - af_glyph_hints_scale_dim( hints, (AF_Dimension)dim, - scale, delta ); - continue; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ - if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { @@ -3601,6 +5051,12 @@ 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_apply_vertical_separation_adjustments( + hints, + (AF_Dimension)dim, + glyph_index, + accent_height_limit, + metrics->root.reverse_charmap ); } } @@ -3629,7 +5085,7 @@ (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */ (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */ - (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done, /* style_metrics_done */ (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */ (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */ diff --git a/src/thirdparty/freetype2/src/autofit/aflatin.h b/src/thirdparty/freetype2/src/autofit/aflatin.h index 40479538c..82b4b0d48 100644 --- a/src/thirdparty/freetype2/src/autofit/aflatin.h +++ b/src/thirdparty/freetype2/src/autofit/aflatin.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for latin writing system * (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -61,17 +61,26 @@ FT_BEGIN_HEADER ( (b)->properties & AF_BLUE_PROPERTY_LATIN_X_HEIGHT ) #define AF_LATIN_IS_LONG_BLUE( b ) \ ( (b)->properties & AF_BLUE_PROPERTY_LATIN_LONG ) +#define AF_LATIN_IS_CAPITAL_BOTTOM_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_CAPITAL_BOTTOM ) +#define AF_LATIN_IS_SMALL_BOTTOM_BLUE( b ) \ + ( (b)->properties & AF_BLUE_PROPERTY_LATIN_SMALL_BOTTOM ) #define AF_LATIN_MAX_WIDTHS 16 -#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ -#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ -#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript top */ - /* blue zone */ -#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have neutral blue zone */ -#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustment */ - /* optimization */ +#define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ +#define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ +#define AF_LATIN_BLUE_SUB_TOP ( 1U << 2 ) /* we have a subscript */ + /* top blue zone */ +#define AF_LATIN_BLUE_NEUTRAL ( 1U << 3 ) /* we have a neutral blue */ + /* zone */ +#define AF_LATIN_BLUE_ADJUSTMENT ( 1U << 4 ) /* used for scale adjustm. */ + /* optimization */ +#define AF_LATIN_BLUE_BOTTOM ( 1U << 5 ) /* we have a capital */ + /* letter bottom blue zone */ +#define AF_LATIN_BLUE_BOTTOM_SMALL ( 1U << 6 ) /* we have a small letter */ + /* bottom blue zone */ typedef struct AF_LatinBlueRec_ @@ -98,7 +107,7 @@ FT_BEGIN_HEADER /* ignored for horizontal metrics */ FT_UInt blue_count; - AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]; + AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX_LEN]; FT_Fixed org_scale; FT_Pos org_delta; @@ -116,11 +125,11 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) - af_latin_metrics_init( AF_LatinMetrics metrics, + af_latin_metrics_init( AF_StyleMetrics metrics, FT_Face face ); FT_LOCAL( void ) - af_latin_metrics_scale( AF_LatinMetrics metrics, + af_latin_metrics_scale( AF_StyleMetrics metrics, AF_Scaler scaler ); FT_LOCAL( void ) diff --git a/src/thirdparty/freetype2/src/autofit/afloader.c b/src/thirdparty/freetype2/src/autofit/afloader.c index 83743b7be..d84adc096 100644 --- a/src/thirdparty/freetype2/src/autofit/afloader.c +++ b/src/thirdparty/freetype2/src/autofit/afloader.c @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -22,7 +22,7 @@ #include "aferrors.h" #include "afmodule.h" -#include FT_INTERNAL_CALC_H +#include /* Initialize glyph loader. */ @@ -55,10 +55,8 @@ error = af_face_globals_new( face, &loader->globals, module ); if ( !error ) { - face->autohint.data = - (FT_Pointer)loader->globals; - face->autohint.finalizer = - (FT_Generic_Finalizer)af_face_globals_free; + face->autohint.data = (FT_Pointer)loader->globals; + face->autohint.finalizer = af_face_globals_free; } } @@ -105,7 +103,6 @@ globals->stem_darkening_for_ppem; FT_Fixed em_size = af_intToFixed( face->units_per_EM ); - FT_Fixed em_ratio = FT_DivFix( af_intToFixed( 1000 ), em_size ); FT_Matrix scale_down_matrix = { 0x10000L, 0, 0, 0x10000L }; @@ -142,12 +139,11 @@ darken_by_font_units_x = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdVW ) ); - darken_x = FT_DivFix( FT_MulFix( darken_by_font_units_x, - size_metrics->x_scale ), - em_ratio ); + af_loader_compute_darkening( loader, + face, + stdVW ) ; + darken_x = FT_MulFix( darken_by_font_units_x, + size_metrics->x_scale ); globals->standard_vertical_width = stdVW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; @@ -161,12 +157,11 @@ darken_by_font_units_y = - af_intToFixed( af_loader_compute_darkening( loader, - face, - stdHW ) ); - darken_y = FT_DivFix( FT_MulFix( darken_by_font_units_y, - size_metrics->y_scale ), - em_ratio ); + af_loader_compute_darkening( loader, + face, + stdHW ) ; + darken_y = FT_MulFix( darken_by_font_units_y, + size_metrics->y_scale ); globals->standard_horizontal_width = stdHW; globals->stem_darkening_for_ppem = size_metrics->x_ppem; @@ -232,9 +227,6 @@ AF_WritingSystemClass writing_system_class; - if ( !size ) - return FT_THROW( Invalid_Size_Handle ); - FT_ZERO( &scaler ); if ( !size_internal->autohint_metrics.x_scale || @@ -300,12 +292,6 @@ if ( error ) goto Exit; -#ifdef FT_OPTION_AUTOFIT2 - /* XXX: undocumented hook to activate the latin2 writing system. */ - if ( load_flags & ( 1UL << 20 ) ) - style_options = AF_STYLE_LTN2_DFLT; -#endif - /* * Glyphs (really code points) are assigned to scripts. Script * analysis is done lazily: For each glyph that passes through here, @@ -482,8 +468,8 @@ 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 ); + 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; @@ -594,7 +580,7 @@ * * XXX: Currently a crude adaption of the original algorithm. Do better? */ - FT_LOCAL_DEF( FT_Int32 ) + FT_LOCAL_DEF( FT_Fixed ) af_loader_compute_darkening( AF_Loader loader, FT_Face face, FT_Pos standard_width ) @@ -713,7 +699,7 @@ } /* Convert darken_amount from per 1000 em to true character space. */ - return af_fixedToInt( FT_DivFix( darken_amount, em_ratio ) ); + return FT_DivFix( darken_amount, em_ratio ); } diff --git a/src/thirdparty/freetype2/src/autofit/afloader.h b/src/thirdparty/freetype2/src/autofit/afloader.h index d1e0f3c09..a04b4df0b 100644 --- a/src/thirdparty/freetype2/src/autofit/afloader.h +++ b/src/thirdparty/freetype2/src/autofit/afloader.h @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -75,7 +75,7 @@ FT_BEGIN_HEADER FT_UInt gindex, FT_Int32 load_flags ); - FT_LOCAL_DEF( FT_Int32 ) + FT_LOCAL( FT_Fixed ) af_loader_compute_darkening( AF_Loader loader, FT_Face face, FT_Pos standard_width ); diff --git a/src/thirdparty/freetype2/src/autofit/afmodule.c b/src/thirdparty/freetype2/src/autofit/afmodule.c index 3e46a3655..22d85a889 100644 --- a/src/thirdparty/freetype2/src/autofit/afmodule.c +++ b/src/thirdparty/freetype2/src/autofit/afmodule.c @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -43,20 +43,20 @@ #endif - int _af_debug_disable_horz_hints; - int _af_debug_disable_vert_hints; - int _af_debug_disable_blue_hints; + int af_debug_disable_horz_hints_; + int af_debug_disable_vert_hints_; + int af_debug_disable_blue_hints_; /* we use a global object instead of a local one for debugging */ - AF_GlyphHintsRec _af_debug_hints_rec[1]; + static AF_GlyphHintsRec af_debug_hints_rec_[1]; - void* _af_debug_hints = _af_debug_hints_rec; + void* af_debug_hints_ = af_debug_hints_rec_; #endif -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_DRIVER_H -#include FT_SERVICE_PROPERTIES_H +#include +#include +#include +#include /************************************************************************** @@ -89,10 +89,8 @@ error = af_face_globals_new( face, &globals, module ); if ( !error ) { - face->autohint.data = - (FT_Pointer)globals; - face->autohint.finalizer = - (FT_Generic_Finalizer)af_face_globals_free; + face->autohint.data = (FT_Pointer)globals; + face->autohint.finalizer = af_face_globals_free; } } @@ -119,8 +117,8 @@ if ( !ft_strcmp( property_name, "fallback-script" ) ) { - FT_UInt* fallback_script; - FT_UInt ss; + AF_Script* fallback_script; + FT_UInt ss; #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES @@ -128,7 +126,7 @@ return FT_THROW( Invalid_Argument ); #endif - fallback_script = (FT_UInt*)value; + fallback_script = (AF_Script*)value; /* We translate the fallback script to a fallback style that uses */ /* `fallback-script' as its script and `AF_COVERAGE_NONE' as its */ @@ -138,8 +136,8 @@ AF_StyleClass style_class = af_style_classes[ss]; - if ( (FT_UInt)style_class->script == *fallback_script && - style_class->coverage == AF_COVERAGE_DEFAULT ) + if ( style_class->script == *fallback_script && + style_class->coverage == AF_COVERAGE_DEFAULT ) { module->fallback_style = ss; break; @@ -148,8 +146,8 @@ if ( !af_style_classes[ss] ) { - FT_TRACE0(( "af_property_set: Invalid value %d for property `%s'\n", - fallback_script, property_name )); + FT_TRACE2(( "af_property_set: Invalid value %u for property `%s'\n", + *fallback_script, property_name )); return FT_THROW( Invalid_Argument ); } @@ -157,7 +155,7 @@ } else if ( !ft_strcmp( property_name, "default-script" ) ) { - FT_UInt* default_script; + AF_Script* default_script; #ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES @@ -165,7 +163,7 @@ return FT_THROW( Invalid_Argument ); #endif - default_script = (FT_UInt*)value; + default_script = (AF_Script*)value; module->default_script = *default_script; @@ -190,35 +188,6 @@ return error; } -#ifdef AF_CONFIG_OPTION_USE_WARPER - else if ( !ft_strcmp( property_name, "warping" ) ) - { -#ifdef FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES - if ( value_is_string ) - { - const char* s = (const char*)value; - long w = ft_strtol( s, NULL, 10 ); - - - if ( w == 0 ) - module->warping = 0; - else if ( w == 1 ) - module->warping = 1; - else - return FT_THROW( Invalid_Argument ); - } - else -#endif - { - FT_Bool* warping = (FT_Bool*)value; - - - module->warping = *warping; - } - - return error; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) { FT_Int* darken_params; @@ -307,7 +276,7 @@ return error; } - FT_TRACE0(( "af_property_set: missing property `%s'\n", + FT_TRACE2(( "af_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -320,11 +289,6 @@ { FT_Error error = FT_Err_Ok; AF_Module module = (AF_Module)ft_module; - FT_UInt fallback_style = module->fallback_style; - FT_UInt default_script = module->default_script; -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_Bool warping = module->warping; -#endif if ( !ft_strcmp( property_name, "glyph-to-script-map" ) ) @@ -341,9 +305,9 @@ } else if ( !ft_strcmp( property_name, "fallback-script" ) ) { - FT_UInt* val = (FT_UInt*)value; + AF_Script* val = (AF_Script*)value; - AF_StyleClass style_class = af_style_classes[fallback_style]; + AF_StyleClass style_class = af_style_classes[module->fallback_style]; *val = style_class->script; @@ -352,10 +316,10 @@ } else if ( !ft_strcmp( property_name, "default-script" ) ) { - FT_UInt* val = (FT_UInt*)value; + AF_Script* val = (AF_Script*)value; - *val = default_script; + *val = module->default_script; return error; } @@ -371,17 +335,6 @@ return error; } -#ifdef AF_CONFIG_OPTION_USE_WARPER - else if ( !ft_strcmp( property_name, "warping" ) ) - { - FT_Bool* val = (FT_Bool*)value; - - - *val = warping; - - return error; - } -#endif /* AF_CONFIG_OPTION_USE_WARPER */ else if ( !ft_strcmp( property_name, "darkening-parameters" ) ) { FT_Int* darken_params = module->darken_params; @@ -410,7 +363,7 @@ return error; } - FT_TRACE0(( "af_property_get: missing property `%s'\n", + FT_TRACE2(( "af_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -419,8 +372,9 @@ FT_DEFINE_SERVICE_PROPERTIESREC( af_service_properties, - (FT_Properties_SetFunc)af_property_set, /* set_property */ - (FT_Properties_GetFunc)af_property_get ) /* get_property */ + af_property_set, /* FT_Properties_SetFunc set_property */ + af_property_get /* FT_Properties_GetFunc get_property */ + ) FT_DEFINE_SERVICEDESCREC1( @@ -447,9 +401,6 @@ module->fallback_style = AF_STYLE_FALLBACK; module->default_script = AF_SCRIPT_DEFAULT; -#ifdef AF_CONFIG_OPTION_USE_WARPER - module->warping = 0; -#endif module->no_stem_darkening = TRUE; module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; @@ -461,6 +412,11 @@ module->darken_params[6] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4; module->darken_params[7] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4; +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_init( module ); +#endif + return FT_Err_Ok; } @@ -470,28 +426,35 @@ { FT_UNUSED( ft_module ); +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_done( (AF_Module)ft_module ); +#endif + #ifdef FT_DEBUG_AUTOFIT - if ( _af_debug_hints_rec->memory ) - af_glyph_hints_done( _af_debug_hints_rec ); + if ( af_debug_hints_rec_->memory ) + af_glyph_hints_done( af_debug_hints_rec_ ); #endif } FT_CALLBACK_DEF( FT_Error ) - af_autofitter_load_glyph( AF_Module module, - FT_GlyphSlot slot, - FT_Size size, - FT_UInt glyph_index, - FT_Int32 load_flags ) + af_autofitter_load_glyph( FT_AutoHinter module_, + FT_GlyphSlot slot, + FT_Size size, + FT_UInt glyph_index, + FT_Int32 load_flags ) { + AF_Module module = (AF_Module)module_; + FT_Error error = FT_Err_Ok; - FT_Memory memory = module->root.library->memory; + FT_Memory memory = module->root.memory; #ifdef FT_DEBUG_AUTOFIT /* in debug mode, we use a global object that survives this routine */ - AF_GlyphHints hints = _af_debug_hints_rec; + AF_GlyphHints hints = af_debug_hints_rec_; AF_LoaderRec loader[1]; FT_UNUSED( size ); @@ -547,11 +510,11 @@ FT_DEFINE_AUTOHINTER_INTERFACE( af_autofitter_interface, - NULL, /* reset_face */ - NULL, /* get_global_hints */ - NULL, /* done_global_hints */ - (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph ) /* load_glyph */ - + NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */ + NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */ + NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */ + af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */ + ) FT_DEFINE_MODULE( autofit_module_class, @@ -565,9 +528,9 @@ (const void*)&af_autofitter_interface, - (FT_Module_Constructor)af_autofitter_init, /* module_init */ - (FT_Module_Destructor) af_autofitter_done, /* module_done */ - (FT_Module_Requester) af_get_interface /* get_interface */ + af_autofitter_init, /* FT_Module_Constructor module_init */ + af_autofitter_done, /* FT_Module_Destructor module_done */ + af_get_interface /* FT_Module_Requester get_interface */ ) diff --git a/src/thirdparty/freetype2/src/autofit/afmodule.h b/src/thirdparty/freetype2/src/autofit/afmodule.h index b410809aa..c62421ef6 100644 --- a/src/thirdparty/freetype2/src/autofit/afmodule.h +++ b/src/thirdparty/freetype2/src/autofit/afmodule.h @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (specification). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,10 +19,10 @@ #ifndef AFMODULE_H_ #define AFMODULE_H_ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_MODULE_H +#include +#include +#include "ft-hb.h" FT_BEGIN_HEADER @@ -37,16 +37,19 @@ FT_BEGIN_HEADER FT_ModuleRec root; FT_UInt fallback_style; - FT_UInt default_script; -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_Bool warping; -#endif + AF_Script default_script; FT_Bool no_stem_darkening; FT_Int darken_params[8]; +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + ft_hb_funcs_t* hb_funcs; +#endif + } AF_ModuleRec, *AF_Module; +FT_DECLARE_AUTOHINTER_INTERFACE( af_autofitter_interface ) FT_DECLARE_MODULE( autofit_module_class ) diff --git a/src/thirdparty/freetype2/src/autofit/afranges.c b/src/thirdparty/freetype2/src/autofit/afranges.c index 45c8bbfc9..fd54948f3 100644 --- a/src/thirdparty/freetype2/src/autofit/afranges.c +++ b/src/thirdparty/freetype2/src/autofit/afranges.c @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (body). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -73,9 +73,11 @@ { AF_UNIRANGE_REC( 0x0600, 0x06FF ), /* Arabic */ AF_UNIRANGE_REC( 0x0750, 0x07FF ), /* Arabic Supplement */ + AF_UNIRANGE_REC( 0x0870, 0x089F ), /* Arabic Extended-B */ AF_UNIRANGE_REC( 0x08A0, 0x08FF ), /* Arabic Extended-A */ AF_UNIRANGE_REC( 0xFB50, 0xFDFF ), /* Arabic Presentation Forms-A */ AF_UNIRANGE_REC( 0xFE70, 0xFEFF ), /* Arabic Presentation Forms-B */ + AF_UNIRANGE_REC( 0x10EC0, 0x10EFF ), /* Arabic Extended-C */ AF_UNIRANGE_REC( 0x1EE00, 0x1EEFF ), /* Arabic Mathematical Alphabetic Symbols */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -90,8 +92,9 @@ AF_UNIRANGE_REC( 0x06DF, 0x06E4 ), AF_UNIRANGE_REC( 0x06E7, 0x06E8 ), AF_UNIRANGE_REC( 0x06EA, 0x06ED ), - AF_UNIRANGE_REC( 0x08D4, 0x08E1 ), - AF_UNIRANGE_REC( 0x08D3, 0x08FF ), + AF_UNIRANGE_REC( 0x0897, 0x089F ), + AF_UNIRANGE_REC( 0x08CA, 0x08E1 ), + AF_UNIRANGE_REC( 0x08E3, 0x08FF ), AF_UNIRANGE_REC( 0xFBB2, 0xFBC1 ), AF_UNIRANGE_REC( 0xFE70, 0xFE70 ), AF_UNIRANGE_REC( 0xFE72, 0xFE72 ), @@ -101,6 +104,7 @@ AF_UNIRANGE_REC( 0xFE7A, 0xFE7A ), AF_UNIRANGE_REC( 0xFE7C, 0xFE7C ), AF_UNIRANGE_REC( 0xFE7E, 0xFE7E ), + AF_UNIRANGE_REC( 0x10EFD, 0x10EFF ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -198,8 +202,9 @@ const AF_Script_UniRangeRec af_cans_uniranges[] = { - AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ - AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0x1400, 0x167F ), /* Unified Canadian Aboriginal Syllabics */ + AF_UNIRANGE_REC( 0x18B0, 0x18FF ), /* Unified Canadian Aboriginal Syllabics Extended */ + AF_UNIRANGE_REC( 0x11AB0, 0x11ABF ), /* Unified Canadian Aboriginal Syllabics Extended-A */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -259,6 +264,9 @@ }; + /* TODO: Split off data for new 'cyrb' (subscript) and 'cyrp' */ + /* (superscript) groups (mainly from the Extended-D block), */ + /* in analogy to 'latb' and 'latp'? */ const AF_Script_UniRangeRec af_cyrl_uniranges[] = { AF_UNIRANGE_REC( 0x0400, 0x04FF ), /* Cyrillic */ @@ -266,6 +274,7 @@ AF_UNIRANGE_REC( 0x2DE0, 0x2DFF ), /* Cyrillic Extended-A */ AF_UNIRANGE_REC( 0xA640, 0xA69F ), /* Cyrillic Extended-B */ AF_UNIRANGE_REC( 0x1C80, 0x1C8F ), /* Cyrillic Extended-C */ + AF_UNIRANGE_REC( 0x1E030, 0x1E08F ), /* Cyrillic Extended-D */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -285,15 +294,16 @@ const AF_Script_UniRangeRec af_deva_uniranges[] = { - AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ + AF_UNIRANGE_REC( 0x0900, 0x093B ), /* Devanagari */ /* omitting U+093C nukta */ - AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ + AF_UNIRANGE_REC( 0x093D, 0x0950 ), /* ... continued */ /* omitting U+0951 udatta, U+0952 anudatta */ - AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ + AF_UNIRANGE_REC( 0x0953, 0x0963 ), /* ... continued */ /* omitting U+0964 danda, U+0965 double danda */ - AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ - AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ - AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0x0966, 0x097F ), /* ... continued */ + AF_UNIRANGE_REC( 0x20B9, 0x20B9 ), /* (new) Rupee sign */ + AF_UNIRANGE_REC( 0xA8E0, 0xA8FF ), /* Devanagari Extended */ + AF_UNIRANGE_REC( 0x11B00, 0x11B5F ), /* Devanagari Extended-A */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -329,6 +339,7 @@ AF_UNIRANGE_REC( 0x1380, 0x139F ), /* Ethiopic Supplement */ AF_UNIRANGE_REC( 0x2D80, 0x2DDF ), /* Ethiopic Extended */ AF_UNIRANGE_REC( 0xAB00, 0xAB2F ), /* Ethiopic Extended-A */ + AF_UNIRANGE_REC( 0x1E7E0, 0x1E7FF ), /* Ethiopic Extended-B */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -534,7 +545,7 @@ { AF_UNIRANGE_REC( 0x0EB1, 0x0EB1 ), AF_UNIRANGE_REC( 0x0EB4, 0x0EBC ), - AF_UNIRANGE_REC( 0x0EC8, 0x0ECD ), + AF_UNIRANGE_REC( 0x0EC8, 0x0ECE ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -567,12 +578,15 @@ AF_UNIRANGE_REC( 0x2C7E, 0x2C7F ), /* ... continued */ AF_UNIRANGE_REC( 0x2E00, 0x2E7F ), /* Supplemental Punctuation */ AF_UNIRANGE_REC( 0xA720, 0xA76F ), /* Latin Extended-D */ - AF_UNIRANGE_REC( 0xA771, 0xA7F7 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA771, 0xA7F0 ), /* ... continued */ + AF_UNIRANGE_REC( 0xA7F2, 0xA7F7 ), /* ... continued */ AF_UNIRANGE_REC( 0xA7FA, 0xA7FF ), /* ... continued */ AF_UNIRANGE_REC( 0xAB30, 0xAB5B ), /* Latin Extended-E */ - AF_UNIRANGE_REC( 0xAB60, 0xAB6F ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB60, 0xAB68 ), /* ... continued */ + AF_UNIRANGE_REC( 0xAB6A, 0xAB6F ), /* ... continued */ AF_UNIRANGE_REC( 0xFB00, 0xFB06 ), /* Alphab. Present. Forms (Latin Ligs) */ AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ), /* Mathematical Alphanumeric Symbols */ + AF_UNIRANGE_REC( 0x1DF00, 0x1DFFF ), /* Latin Extended-G */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -588,7 +602,7 @@ AF_UNIRANGE_REC( 0x02B9, 0x02DF ), AF_UNIRANGE_REC( 0x02E5, 0x02FF ), AF_UNIRANGE_REC( 0x0300, 0x036F ), - AF_UNIRANGE_REC( 0x1AB0, 0x1ABE ), + AF_UNIRANGE_REC( 0x1AB0, 0x1AEB ), AF_UNIRANGE_REC( 0x1DC0, 0x1DFF ), AF_UNIRANGE_REC( 0x2017, 0x2017 ), AF_UNIRANGE_REC( 0x203E, 0x203E ), @@ -625,8 +639,11 @@ AF_UNIRANGE_REC( 0x2070, 0x207F ), /* superscript digits and letters */ AF_UNIRANGE_REC( 0x2C7D, 0x2C7D ), /* modifier letter capital v */ AF_UNIRANGE_REC( 0xA770, 0xA770 ), /* modifier letter us */ + AF_UNIRANGE_REC( 0xA7F1, 0xA7F1 ), /* modifier letter capital s */ AF_UNIRANGE_REC( 0xA7F8, 0xA7F9 ), /* more modifier letters */ AF_UNIRANGE_REC( 0xAB5C, 0xAB5F ), /* more modifier letters */ + AF_UNIRANGE_REC( 0xAB69, 0xAB69 ), /* modifier letter small turned w */ + AF_UNIRANGE_REC( 0x10780, 0x107FB ), /* Latin Extended-F */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -638,7 +655,8 @@ const AF_Script_UniRangeRec af_lisu_uniranges[] = { - AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0xA4D0, 0xA4FF ), /* Lisu */ + AF_UNIRANGE_REC( 0x11FB0, 0x11FBF ), /* Lisu Supplement */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -664,6 +682,18 @@ }; + const AF_Script_UniRangeRec af_medf_uniranges[] = + { + AF_UNIRANGE_REC( 0x16E40, 0x16E9F ), /* Medefaidrin */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_medf_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_mong_uniranges[] = { AF_UNIRANGE_REC( 0x1800, 0x18AF ), /* Mongolian */ @@ -684,6 +714,7 @@ AF_UNIRANGE_REC( 0x1000, 0x109F ), /* Myanmar */ AF_UNIRANGE_REC( 0xA9E0, 0xA9FF ), /* Myanmar Extended-B */ AF_UNIRANGE_REC( 0xAA60, 0xAA7F ), /* Myanmar Extended-A */ + AF_UNIRANGE_REC( 0x116D0, 0x116FF ), /* Myanmar Extended-C */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -778,6 +809,18 @@ }; + const AF_Script_UniRangeRec af_rohg_uniranges[] = + { + AF_UNIRANGE_REC( 0x10D00, 0x10D3F ), /* Hanifi Rohingya */ + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_rohg_nonbase_uniranges[] = + { + AF_UNIRANGE_REC( 0, 0 ) + }; + + const AF_Script_UniRangeRec af_saur_uniranges[] = { AF_UNIRANGE_REC( 0xA880, 0xA8DF ), /* Saurashtra */ @@ -812,6 +855,7 @@ const AF_Script_UniRangeRec af_sinh_nonbase_uniranges[] = { + AF_UNIRANGE_REC( 0x0D81, 0x0D81 ), AF_UNIRANGE_REC( 0x0DCA, 0x0DCA ), AF_UNIRANGE_REC( 0x0DD2, 0x0DD6 ), AF_UNIRANGE_REC( 0, 0 ) @@ -835,7 +879,8 @@ const AF_Script_UniRangeRec af_taml_uniranges[] = { - AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0x0B80, 0x0BFF ), /* Tamil */ + AF_UNIRANGE_REC( 0x11FC0, 0x11FFF ), /* Tamil Supplement */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -875,6 +920,7 @@ { AF_UNIRANGE_REC( 0x0C00, 0x0C00 ), AF_UNIRANGE_REC( 0x0C04, 0x0C04 ), + AF_UNIRANGE_REC( 0x0C3C, 0x0C3C ), AF_UNIRANGE_REC( 0x0C3E, 0x0C40 ), AF_UNIRANGE_REC( 0x0C46, 0x0C56 ), AF_UNIRANGE_REC( 0x0C62, 0x0C63 ), @@ -968,6 +1014,7 @@ AF_UNIRANGE_REC( 0xA806, 0xA806 ), AF_UNIRANGE_REC( 0xA80B, 0xA80B ), AF_UNIRANGE_REC( 0xA825, 0xA826 ), + AF_UNIRANGE_REC( 0xA82C, 0xA82C ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -1024,15 +1071,21 @@ AF_UNIRANGE_REC( 0xFE10, 0xFE1F ), /* Vertical forms */ AF_UNIRANGE_REC( 0xFE30, 0xFE4F ), /* CJK Compatibility Forms */ AF_UNIRANGE_REC( 0xFF00, 0xFFEF ), /* Halfwidth and Fullwidth Forms */ + AF_UNIRANGE_REC( 0x1AFF0, 0x1AFFF ), /* Kana Extended-B */ AF_UNIRANGE_REC( 0x1B000, 0x1B0FF ), /* Kana Supplement */ AF_UNIRANGE_REC( 0x1B100, 0x1B12F ), /* Kana Extended-A */ + AF_UNIRANGE_REC( 0x1B130, 0x1B16F ), /* Small Kana Extension */ AF_UNIRANGE_REC( 0x1D300, 0x1D35F ), /* Tai Xuan Hing Symbols */ AF_UNIRANGE_REC( 0x20000, 0x2A6DF ), /* CJK Unified Ideographs Extension B */ AF_UNIRANGE_REC( 0x2A700, 0x2B73F ), /* CJK Unified Ideographs Extension C */ AF_UNIRANGE_REC( 0x2B740, 0x2B81F ), /* CJK Unified Ideographs Extension D */ AF_UNIRANGE_REC( 0x2B820, 0x2CEAF ), /* CJK Unified Ideographs Extension E */ AF_UNIRANGE_REC( 0x2CEB0, 0x2EBEF ), /* CJK Unified Ideographs Extension F */ + AF_UNIRANGE_REC( 0x2EBF0, 0x2EE5D ), /* CJK Unified Ideographs Extension I */ AF_UNIRANGE_REC( 0x2F800, 0x2FA1F ), /* CJK Compatibility Ideographs Supplement */ + AF_UNIRANGE_REC( 0x30000, 0x3134A ), /* CJK Unified Ideographs Extension G */ + AF_UNIRANGE_REC( 0x31350, 0x323AF ), /* CJK Unified Ideographs Extension H */ + AF_UNIRANGE_REC( 0x323B0, 0x33479 ), /* CJK Unified Ideographs Extension J */ AF_UNIRANGE_REC( 0, 0 ) }; diff --git a/src/thirdparty/freetype2/src/autofit/afranges.h b/src/thirdparty/freetype2/src/autofit/afranges.h index d5917aefe..fa00eb750 100644 --- a/src/thirdparty/freetype2/src/autofit/afranges.h +++ b/src/thirdparty/freetype2/src/autofit/afranges.h @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (specification). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/autofit/afscript.h b/src/thirdparty/freetype2/src/autofit/afscript.h index 2da8c7018..5c4cbbcb9 100644 --- a/src/thirdparty/freetype2/src/autofit/afscript.h +++ b/src/thirdparty/freetype2/src/autofit/afscript.h @@ -4,7 +4,7 @@ * * Auto-fitter scripts (specification only). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -243,6 +243,12 @@ HINTING_BOTTOM_TO_TOP, "\xE0\xB4\xA0 \xE0\xB4\xB1" ) /* ഠ റ */ + SCRIPT( medf, MEDF, + "Medefaidrin", + HB_SCRIPT_MEDEFAIDRIN, + HINTING_BOTTOM_TO_TOP, + "\xF0\x96\xB9\xA1 \xF0\x96\xB9\x9B \xF0\x96\xB9\xAF" ) /* 𖹡 𖹛 𖹯 */ + SCRIPT( mong, MONG, "Mongolian", HB_SCRIPT_MONGOLIAN, @@ -291,6 +297,12 @@ HINTING_BOTTOM_TO_TOP, "\xF0\x90\x92\x86 \xF0\x90\x92\xA0" ) /* 𐒆 𐒠 */ + SCRIPT( rohg, ROHG, + "Hanifi Rohingya", + HB_SCRIPT_HANIFI_ROHINGYA, + HINTING_BOTTOM_TO_TOP, + "\xF0\x90\xB4\xB0" ) /* 𐴰 */ + SCRIPT( saur, SAUR, "Saurashtra", HB_SCRIPT_SAURASHTRA, diff --git a/src/thirdparty/freetype2/src/autofit/afshaper.c b/src/thirdparty/freetype2/src/autofit/afshaper.c index a5191c691..f3c0744fd 100644 --- a/src/thirdparty/freetype2/src/autofit/afshaper.c +++ b/src/thirdparty/freetype2/src/autofit/afshaper.c @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (body). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,15 +16,14 @@ */ -#include -#include FT_FREETYPE_H -#include FT_ADVANCES_H +#include +#include #include "afglobal.h" #include "aftypes.h" #include "afshaper.h" -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ /************************************************************************** * @@ -90,17 +89,18 @@ #define SCRIPT( s, S, d, h, H, ss ) h, - static const hb_script_t scripts[] = + FT_LOCAL_ARRAY_DEF( hb_script_t ) + af_hb_scripts[] = { #include "afscript.h" }; - FT_Error - af_shaper_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles, - FT_Bool default_script ) + static FT_Error + af_shaper_get_coverage_hb( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) { hb_face_t* face; @@ -125,21 +125,32 @@ if ( !globals || !style_class || !gstyles ) return FT_THROW( Invalid_Argument ); - face = hb_font_get_face( globals->hb_font ); + face = hb( font_get_face )( globals->hb_font ); coverage_tags = coverages[style_class->coverage]; - script = scripts[style_class->script]; + script = af_hb_scripts[style_class->script]; /* Convert a HarfBuzz script tag into the corresponding OpenType */ /* tag or tags -- some Indic scripts like Devanagari have an old */ /* and a new set of features. */ - hb_ot_tags_from_script( script, - &script_tags[0], - &script_tags[1] ); + { + unsigned int tags_count = 3; + hb_tag_t tags[3]; - /* `hb_ot_tags_from_script' usually returns HB_OT_TAG_DEFAULT_SCRIPT */ - /* as the second tag. We change that to HB_TAG_NONE except for the */ - /* default script. */ + + hb( ot_tags_from_script_and_language )( script, + HB_LANGUAGE_INVALID, + &tags_count, + tags, + NULL, + NULL ); + script_tags[0] = tags_count > 0 ? tags[0] : HB_TAG_NONE; + script_tags[1] = tags_count > 1 ? tags[1] : HB_TAG_NONE; + script_tags[2] = tags_count > 2 ? tags[2] : HB_TAG_NONE; + } + + /* If the second tag is HB_OT_TAG_DEFAULT_SCRIPT, change that to */ + /* HB_TAG_NONE except for the default script. */ if ( default_script ) { if ( script_tags[0] == HB_TAG_NONE ) @@ -158,98 +169,97 @@ /* HarfBuzz maps them to `DFLT', which we don't want to handle here */ if ( script_tags[0] == HB_OT_TAG_DEFAULT_SCRIPT ) goto Exit; - - if ( script_tags[1] == HB_OT_TAG_DEFAULT_SCRIPT ) - script_tags[1] = HB_TAG_NONE; } - gsub_lookups = hb_set_create(); - hb_ot_layout_collect_lookups( face, - HB_OT_TAG_GSUB, - script_tags, - NULL, - coverage_tags, - gsub_lookups ); + gsub_lookups = hb( set_create )(); + hb( ot_layout_collect_lookups )( face, + HB_OT_TAG_GSUB, + script_tags, + NULL, + coverage_tags, + gsub_lookups ); - if ( hb_set_is_empty( gsub_lookups ) ) + if ( hb( set_is_empty )( gsub_lookups ) ) goto Exit; /* nothing to do */ - FT_TRACE4(( "GSUB lookups (style `%s'):\n" - " ", + FT_TRACE4(( "GSUB lookups (style `%s'):\n", af_style_names[style_class->style] )); + FT_TRACE4(( " " )); #ifdef FT_DEBUG_LEVEL_TRACE count = 0; #endif - gsub_glyphs = hb_set_create(); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, &idx ); ) + gsub_glyphs = hb( set_create )(); + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif /* get output coverage of GSUB feature */ - hb_ot_layout_lookup_collect_glyphs( face, - HB_OT_TAG_GSUB, - idx, - NULL, - NULL, - NULL, - gsub_glyphs ); + hb( ot_layout_lookup_collect_glyphs )( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + gsub_glyphs ); } #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) FT_TRACE4(( " (none)" )); - FT_TRACE4(( "\n\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif - FT_TRACE4(( "GPOS lookups (style `%s'):\n" - " ", + FT_TRACE4(( "GPOS lookups (style `%s'):\n", af_style_names[style_class->style] )); + FT_TRACE4(( " " )); - gpos_lookups = hb_set_create(); - hb_ot_layout_collect_lookups( face, - HB_OT_TAG_GPOS, - script_tags, - NULL, - coverage_tags, - gpos_lookups ); + gpos_lookups = hb( set_create )(); + hb( ot_layout_collect_lookups )( face, + HB_OT_TAG_GPOS, + script_tags, + NULL, + coverage_tags, + gpos_lookups ); #ifdef FT_DEBUG_LEVEL_TRACE count = 0; #endif - gpos_glyphs = hb_set_create(); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gpos_lookups, &idx ); ) + gpos_glyphs = hb( set_create )(); + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gpos_lookups, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif /* get input coverage of GPOS feature */ - hb_ot_layout_lookup_collect_glyphs( face, - HB_OT_TAG_GPOS, - idx, - NULL, - gpos_glyphs, - NULL, - NULL ); + hb( ot_layout_lookup_collect_glyphs )( face, + HB_OT_TAG_GPOS, + idx, + NULL, + gpos_glyphs, + NULL, + NULL ); } #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) FT_TRACE4(( " (none)" )); - FT_TRACE4(( "\n\n" )); + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif /* * We now check whether we can construct blue zones, using glyphs * covered by the feature only. In case there is not a single zone - * (this is, not a single character is covered), we skip this coverage. + * (that is, not a single character is covered), we skip this coverage. * */ if ( style_class->coverage != AF_COVERAGE_DEFAULT ) @@ -272,14 +282,14 @@ GET_UTF8_CHAR( ch, p ); - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_lookups, - &idx ); ) + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_lookups, + &idx ); ) { hb_codepoint_t gidx = FT_Get_Char_Index( globals->face, ch ); - if ( hb_ot_layout_lookup_would_substitute( face, idx, - &gidx, 1, 1 ) ) + if ( hb( ot_layout_lookup_would_substitute )( face, idx, + &gidx, 1, 1 ) ) { found = 1; break; @@ -304,9 +314,9 @@ * hinted and usually rendered glyph. * * Consider the superscript feature of font `pala.ttf': Some of the - * glyphs are `real', this is, they have a zero vertical offset, but + * glyphs are `real', that is, they have a zero vertical offset, but * most of them are small caps glyphs shifted up to the superscript - * position (this is, the `sups' feature is present in both the GSUB and + * position (that is, the `sups' feature is present in both the GSUB and * GPOS tables). The code for blue zones computation actually uses a * feature's y offset so that the `real' glyphs get correct hints. But * later on it is impossible to decide whether a glyph index belongs to, @@ -343,21 +353,23 @@ * */ if ( style_class->coverage != AF_COVERAGE_DEFAULT ) - hb_set_subtract( gsub_glyphs, gpos_glyphs ); + hb( set_subtract )( gsub_glyphs, gpos_glyphs ); #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE4(( " glyphs without GPOS data (`*' means already assigned)" )); count = 0; #endif - for ( idx = HB_SET_VALUE_INVALID; hb_set_next( gsub_glyphs, &idx ); ) + for ( idx = HB_SET_VALUE_INVALID; hb( set_next )( gsub_glyphs, &idx ); ) { #ifdef FT_DEBUG_LEVEL_TRACE if ( !( count % 10 ) ) - FT_TRACE4(( "\n" - " " )); + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " " )); + } - FT_TRACE4(( " %d", idx )); + FT_TRACE4(( " %u", idx )); count++; #endif @@ -377,16 +389,19 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !count ) - FT_TRACE4(( "\n" - " (none)" )); - FT_TRACE4(( "\n\n" )); + { + FT_TRACE4(( "\n" )); + FT_TRACE4(( " (none)" )); + } + FT_TRACE4(( "\n" )); + FT_TRACE4(( "\n" )); #endif Exit: - hb_set_destroy( gsub_lookups ); - hb_set_destroy( gsub_glyphs ); - hb_set_destroy( gpos_lookups ); - hb_set_destroy( gpos_glyphs ); + hb( set_destroy )( gsub_lookups ); + hb( set_destroy )( gsub_glyphs ); + hb( set_destroy )( gpos_lookups ); + hb( set_destroy )( gpos_glyphs ); return FT_Err_Ok; } @@ -423,31 +438,33 @@ }; - void* - af_shaper_buf_create( FT_Face face ) + static void* + af_shaper_buf_create_hb( AF_FaceGlobals globals ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); - return (void*)hb_buffer_create(); + return (void*)hb( buffer_create )(); } - void - af_shaper_buf_destroy( FT_Face face, - void* buf ) + static void + af_shaper_buf_destroy_hb( AF_FaceGlobals globals, + void* buf ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); - hb_buffer_destroy( (hb_buffer_t*)buf ); + hb( buffer_destroy )( (hb_buffer_t*)buf ); } - const char* - af_shaper_get_cluster( const char* p, - AF_StyleMetrics metrics, - void* buf_, - unsigned int* count ) + static const char* + af_shaper_get_cluster_hb( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) { + AF_FaceGlobals globals = metrics->globals; + AF_StyleClass style_class; const hb_feature_t* feature; FT_Int upem; @@ -458,6 +475,8 @@ hb_font_t* font; hb_codepoint_t dummy; + FT_UNUSED( globals ); + upem = (FT_Int)metrics->globals->face->units_per_EM; style_class = metrics->style_class; @@ -466,7 +485,7 @@ font = metrics->globals->hb_font; /* we shape at a size of units per EM; this means font units */ - hb_font_set_scale( font, upem, upem ); + hb( font_set_scale )( font, upem, upem ); while ( *p == ' ' ) p++; @@ -478,15 +497,15 @@ len = (int)( q - p ); /* feed character(s) to the HarfBuzz buffer */ - hb_buffer_clear_contents( buf ); - hb_buffer_add_utf8( buf, p, len, 0, len ); + hb( buffer_clear_contents )( buf ); + hb( buffer_add_utf8 )( buf, p, len, 0, len ); /* we let HarfBuzz guess the script and writing direction */ - hb_buffer_guess_segment_properties( buf ); + hb( buffer_guess_segment_properties )( buf ); /* shape buffer, which means conversion from character codes to */ /* glyph indices, possibly applying a feature */ - hb_shape( font, buf, feature, feature ? 1 : 0 ); + hb( shape )( font, buf, feature, feature ? 1 : 0 ); if ( feature ) { @@ -503,13 +522,13 @@ /* glyph indices; otherwise the affected glyph or glyphs aren't */ /* available at all in the feature */ - hb_buffer_clear_contents( hb_buf ); - hb_buffer_add_utf8( hb_buf, p, len, 0, len ); - hb_buffer_guess_segment_properties( hb_buf ); - hb_shape( font, hb_buf, NULL, 0 ); + hb( buffer_clear_contents )( hb_buf ); + hb( buffer_add_utf8 )( hb_buf, p, len, 0, len ); + hb( buffer_guess_segment_properties )( hb_buf ); + hb( shape )( font, hb_buf, NULL, 0 ); - ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); - hb_ginfo = hb_buffer_get_glyph_infos( hb_buf, &hb_gcount ); + ginfo = hb( buffer_get_glyph_infos )( buf, &gcount ); + hb_ginfo = hb( buffer_get_glyph_infos )( hb_buf, &hb_gcount ); if ( gcount == hb_gcount ) { @@ -523,12 +542,12 @@ if ( i == gcount ) { /* both buffers have identical glyph indices */ - hb_buffer_clear_contents( buf ); + hb( buffer_clear_contents )( buf ); } } } - *count = hb_buffer_get_length( buf ); + *count = hb( buffer_get_length )( buf ); #ifdef FT_DEBUG_LEVEL_TRACE if ( feature && *count > 1 ) @@ -540,23 +559,25 @@ } - FT_ULong - af_shaper_get_elem( AF_StyleMetrics metrics, - void* buf_, - unsigned int idx, - FT_Long* advance, - FT_Long* y_offset ) + static FT_ULong + af_shaper_get_elem_hb( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) { + AF_FaceGlobals globals = metrics->globals; + hb_buffer_t* buf = (hb_buffer_t*)buf_; hb_glyph_info_t* ginfo; hb_glyph_position_t* gpos; unsigned int gcount; - FT_UNUSED( metrics ); + FT_UNUSED( globals ); - ginfo = hb_buffer_get_glyph_infos( buf, &gcount ); - gpos = hb_buffer_get_glyph_positions( buf, &gcount ); + ginfo = hb( buffer_get_glyph_infos )( buf, &gcount ); + gpos = hb( buffer_get_glyph_positions )( buf, &gcount ); if ( idx >= gcount ) return 0; @@ -570,14 +591,14 @@ } -#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ - FT_Error - af_shaper_get_coverage( AF_FaceGlobals globals, - AF_StyleClass style_class, - FT_UShort* gstyles, - FT_Bool default_script ) + static FT_Error + af_shaper_get_coverage_nohb( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) { FT_UNUSED( globals ); FT_UNUSED( style_class ); @@ -588,29 +609,29 @@ } - void* - af_shaper_buf_create( FT_Face face ) + static void* + af_shaper_buf_create_nohb( AF_FaceGlobals globals ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); return NULL; } - void - af_shaper_buf_destroy( FT_Face face, - void* buf ) + static void + af_shaper_buf_destroy_nohb( AF_FaceGlobals globals, + void* buf ) { - FT_UNUSED( face ); + FT_UNUSED( globals ); FT_UNUSED( buf ); } - const char* - af_shaper_get_cluster( const char* p, - AF_StyleMetrics metrics, - void* buf_, - unsigned int* count ) + static const char* + af_shaper_get_cluster_nohb( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) { FT_Face face = metrics->globals->face; FT_ULong ch, dummy = 0; @@ -642,12 +663,12 @@ } - FT_ULong - af_shaper_get_elem( AF_StyleMetrics metrics, - void* buf_, - unsigned int idx, - FT_Long* advance, - FT_Long* y_offset ) + static FT_ULong + af_shaper_get_elem_nohb( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) { FT_Face face = metrics->globals->face; FT_ULong glyph_index = *(FT_ULong*)buf_; @@ -670,7 +691,90 @@ } -#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + /********************************************************************/ + + FT_Error + af_shaper_get_coverage( AF_FaceGlobals globals, + AF_StyleClass style_class, + FT_UShort* gstyles, + FT_Bool default_script ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + return af_shaper_get_coverage_hb( globals, + style_class, + gstyles, + default_script ); + else +#endif + return af_shaper_get_coverage_nohb( globals, + style_class, + gstyles, + default_script ); + } + + + void* + af_shaper_buf_create( AF_FaceGlobals globals ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + return af_shaper_buf_create_hb( globals ); + else +#endif + return af_shaper_buf_create_nohb( globals ); + } + + + void + af_shaper_buf_destroy( AF_FaceGlobals globals, + void* buf ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( globals ) ) + af_shaper_buf_destroy_hb( globals, buf ); + else +#endif + af_shaper_buf_destroy_nohb( globals, buf ); + } + + + const char* + af_shaper_get_cluster( const char* p, + AF_StyleMetrics metrics, + void* buf_, + unsigned int* count ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( metrics->globals ) ) + return af_shaper_get_cluster_hb( p, metrics, buf_, count ); + else +#endif + return af_shaper_get_cluster_nohb( p, metrics, buf_, count ); + } + + + FT_ULong + af_shaper_get_elem( AF_StyleMetrics metrics, + void* buf_, + unsigned int idx, + FT_Long* advance, + FT_Long* y_offset ) + { +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + if ( ft_hb_enabled( metrics->globals ) ) + return af_shaper_get_elem_hb( metrics, + buf_, + idx, + advance, + y_offset ); +#endif + return af_shaper_get_elem_nohb( metrics, + buf_, + idx, + advance, + y_offset ); + } /* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afshaper.h b/src/thirdparty/freetype2/src/autofit/afshaper.h index 06a1e0661..757368fc9 100644 --- a/src/thirdparty/freetype2/src/autofit/afshaper.h +++ b/src/thirdparty/freetype2/src/autofit/afshaper.h @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (specification). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,21 +20,17 @@ #define AFSHAPER_H_ -#include -#include FT_FREETYPE_H - - -#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ - -#include -#include -#include - -#endif +#include FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + FT_LOCAL_ARRAY( hb_script_t ) + af_hb_scripts[]; +#endif + + FT_Error af_shaper_get_coverage( AF_FaceGlobals globals, AF_StyleClass style_class, @@ -43,11 +39,11 @@ FT_BEGIN_HEADER void* - af_shaper_buf_create( FT_Face face ); + af_shaper_buf_create( AF_FaceGlobals globals ); void - af_shaper_buf_destroy( FT_Face face, - void* buf ); + af_shaper_buf_destroy( AF_FaceGlobals globals, + void* buf ); const char* af_shaper_get_cluster( const char* p, diff --git a/src/thirdparty/freetype2/src/autofit/afstyles.h b/src/thirdparty/freetype2/src/autofit/afstyles.h index 8d1d70812..206232efe 100644 --- a/src/thirdparty/freetype2/src/autofit/afstyles.h +++ b/src/thirdparty/freetype2/src/autofit/afstyles.h @@ -4,7 +4,7 @@ * * Auto-fitter styles (specification only). * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -50,36 +50,36 @@ AF_COVERAGE_ ## C ) #undef META_STYLE_LATIN -#define META_STYLE_LATIN( s, S, ds ) \ - STYLE_LATIN( s, S, c2cp, C2CP, ds, \ +#define META_STYLE_LATIN( s, S, ds ) \ + STYLE_LATIN( s, S, c2cp, C2CP, ds, \ "petite capitals from capitals", \ - PETITE_CAPITALS_FROM_CAPITALS ) \ - STYLE_LATIN( s, S, c2sc, C2SC, ds, \ + PETITE_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, c2sc, C2SC, ds, \ "small capitals from capitals", \ - SMALL_CAPITALS_FROM_CAPITALS ) \ - STYLE_LATIN( s, S, ordn, ORDN, ds, \ - "ordinals", \ - ORDINALS ) \ - STYLE_LATIN( s, S, pcap, PCAP, ds, \ - "petite capitals", \ - PETITE_CAPITALS ) \ - STYLE_LATIN( s, S, sinf, SINF, ds, \ - "scientific inferiors", \ - SCIENTIFIC_INFERIORS ) \ - STYLE_LATIN( s, S, smcp, SMCP, ds, \ - "small capitals", \ - SMALL_CAPITALS ) \ - STYLE_LATIN( s, S, subs, SUBS, ds, \ - "subscript", \ - SUBSCRIPT ) \ - STYLE_LATIN( s, S, sups, SUPS, ds, \ - "superscript", \ - SUPERSCRIPT ) \ - STYLE_LATIN( s, S, titl, TITL, ds, \ - "titling", \ - TITLING ) \ - STYLE_LATIN( s, S, dflt, DFLT, ds, \ - "default", \ + SMALL_CAPITALS_FROM_CAPITALS ) \ + STYLE_LATIN( s, S, ordn, ORDN, ds, \ + "ordinals", \ + ORDINALS ) \ + STYLE_LATIN( s, S, pcap, PCAP, ds, \ + "petite capitals", \ + PETITE_CAPITALS ) \ + STYLE_LATIN( s, S, sinf, SINF, ds, \ + "scientific inferiors", \ + SCIENTIFIC_INFERIORS ) \ + STYLE_LATIN( s, S, smcp, SMCP, ds, \ + "small capitals", \ + SMALL_CAPITALS ) \ + STYLE_LATIN( s, S, subs, SUBS, ds, \ + "subscript", \ + SUBSCRIPT ) \ + STYLE_LATIN( s, S, sups, SUPS, ds, \ + "superscript", \ + SUPERSCRIPT ) \ + STYLE_LATIN( s, S, titl, TITL, ds, \ + "titling", \ + TITLING ) \ + STYLE_LATIN( s, S, dflt, DFLT, ds, \ + "default", \ DEFAULT ) @@ -299,15 +299,6 @@ AF_BLUE_STRINGSET_LATP, AF_COVERAGE_DEFAULT ) -#ifdef FT_OPTION_AUTOFIT2 - STYLE( ltn2_dflt, LTN2_DFLT, - "Latin 2 default style", - AF_WRITING_SYSTEM_LATIN2, - AF_SCRIPT_LATN, - AF_BLUE_STRINGSET_LATN, - AF_COVERAGE_DEFAULT ) -#endif - STYLE( lisu_dflt, LISU_DFLT, "Lisu default style", AF_WRITING_SYSTEM_LATIN, @@ -322,6 +313,13 @@ AF_BLUE_STRINGSET_MLYM, AF_COVERAGE_DEFAULT ) + STYLE( medf_dflt, MEDF_DFLT, + "Medefaidrin default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_MEDF, + AF_BLUE_STRINGSET_MEDF, + AF_COVERAGE_DEFAULT ) + STYLE( mong_dflt, MONG_DFLT, "Mongolian default style", AF_WRITING_SYSTEM_LATIN, @@ -378,6 +376,13 @@ AF_BLUE_STRINGSET_OSMA, AF_COVERAGE_DEFAULT ) + STYLE( rohg_dflt, ROHG_DFLT, + "Hanifi Rohingya default style", + AF_WRITING_SYSTEM_LATIN, + AF_SCRIPT_ROHG, + AF_BLUE_STRINGSET_ROHG, + AF_COVERAGE_DEFAULT ) + STYLE( saur_dflt, SAUR_DFLT, "Saurashtra default style", AF_WRITING_SYSTEM_LATIN, diff --git a/src/thirdparty/freetype2/src/autofit/aftypes.h b/src/thirdparty/freetype2/src/autofit/aftypes.h index 579003d27..959640a12 100644 --- a/src/thirdparty/freetype2/src/autofit/aftypes.h +++ b/src/thirdparty/freetype2/src/autofit/aftypes.h @@ -4,7 +4,7 @@ * * Auto-fitter types (specification only). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -32,12 +32,12 @@ #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 +#include +#include +#include +#include +#include #include "afblue.h" @@ -58,10 +58,10 @@ FT_BEGIN_HEADER #ifdef FT_DEBUG_AUTOFIT -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; +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_; #endif /* FT_DEBUG_AUTOFIT */ @@ -93,63 +93,6 @@ extern void* _af_debug_hints; FT_Pos threshold ); - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** 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); \ - \ - \ - while ( _delta <= -AF_ANGLE_PI ) \ - _delta += AF_ANGLE_2PI; \ - \ - while ( _delta > AF_ANGLE_PI ) \ - _delta -= AF_ANGLE_2PI; \ - \ - result = _delta; \ - FT_END_STMNT - - /* * opaque handle to glyph-specific hints -- see `afhints.h' for more * details @@ -173,18 +116,17 @@ extern void* _af_debug_hints; #define AF_SCALER_FLAG_NO_HORIZONTAL 1U /* disable horizontal hinting */ #define AF_SCALER_FLAG_NO_VERTICAL 2U /* disable vertical hinting */ #define AF_SCALER_FLAG_NO_ADVANCE 4U /* disable advance hinting */ -#define AF_SCALER_FLAG_NO_WARPER 8U /* disable warper */ 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 */ + FT_Face face; /* source font face */ + FT_Fixed x_scale; /* from font units to 1/64 device pixels */ + FT_Fixed y_scale; /* from font units to 1/64 device pixels */ + FT_Pos x_delta; /* in 1/64 device pixels */ + FT_Pos y_delta; /* in 1/64 device pixels */ + FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */ + FT_UInt32 flags; /* additional control flags, see above */ } AF_ScalerRec, *AF_Scaler; @@ -257,7 +199,6 @@ extern void* _af_debug_hints; * outline according to the results of the glyph analyzer. */ -#define AFWRTSYS_H_ /* don't load header files */ #undef WRITING_SYSTEM #define WRITING_SYSTEM( ws, WS ) \ AF_WRITING_SYSTEM_ ## WS, @@ -266,14 +207,12 @@ extern void* _af_debug_hints; typedef enum AF_WritingSystem_ { -#include "afwrtsys.h" +#include "afws-iter.h" AF_WRITING_SYSTEM_MAX /* do not remove */ } AF_WritingSystem; -#undef AFWRTSYS_H_ - typedef struct AF_WritingSystemClassRec_ { @@ -468,6 +407,7 @@ extern void* _af_debug_hints; typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + /* This is the main structure that combines everything. Autofit modules */ /* specific to writing systems derive their structures from it, for */ /* example `AF_LatinMetrics'. */ @@ -480,6 +420,8 @@ extern void* _af_debug_hints; AF_FaceGlobals globals; /* to access properties */ + FT_Hash reverse_charmap; + } AF_StyleMetricsRec; diff --git a/src/thirdparty/freetype2/src/autofit/afwarp.c b/src/thirdparty/freetype2/src/autofit/afwarp.c deleted file mode 100644 index 84e9753ad..000000000 --- a/src/thirdparty/freetype2/src/autofit/afwarp.c +++ /dev/null @@ -1,373 +0,0 @@ -/**************************************************************************** - * - * afwarp.c - * - * Auto-fitter warping algorithm (body). - * - * Copyright (C) 2006-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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 idea of the warping code is to slightly scale and shift a glyph - * within a single dimension so that as much of its segments are aligned - * (more or less) on the grid. To find out the optimal scaling and - * shifting value, various parameter combinations are tried and scored. - */ - -#include "afwarp.h" - -#ifdef AF_CONFIG_OPTION_USE_WARPER - - /************************************************************************** - * - * 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 afwarp - - - /* The weights cover the range 0/64 - 63/64 of a pixel. Obviously, */ - /* values around a half pixel (which means exactly between two grid */ - /* lines) gets the worst weight. */ -#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 - - - /* Score segments for a given `scale' and `delta' in the range */ - /* `xx1' to `xx2', and store the best result in `warper'. If */ - /* the new best score is equal to the old one, prefer the */ - /* value with a smaller distortion (around `base_distort'). */ - - 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_Int num_segments ) - { - FT_Int idx_min, idx_max, idx0; - FT_Int 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; - - 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 ) - { - FT_TRACE5(( "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; - - - /* score the length of the segments for the given range */ - 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 ); - } - } - } - } - - - /* Compute optimal scaling and delta values for a given glyph and */ - /* dimension. */ - - 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_Int 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 = FT_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 ); - - /* examine a half pixel wide range around the maximum coordinates */ - 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; - } - - /* examine (at most) a pixel wide range around the natural width */ - warper->wmin = warper->x2min - warper->x1max; - warper->wmax = warper->x2max - warper->x1min; - -#if 1 - /* some heuristics to reduce the number of widths to be examined */ - { - 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; - - - /* compute min and max positions for given width, */ - /* assuring that they stay within the coordinate ranges */ - 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; - - /* give base distortion a greater weight while scoring */ - 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_CONFIG_OPTION_USE_WARPER */ - - /* ANSI C doesn't like empty source files */ - typedef int _af_warp_dummy; - -#endif /* !AF_CONFIG_OPTION_USE_WARPER */ - -/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afwarp.h b/src/thirdparty/freetype2/src/autofit/afwarp.h deleted file mode 100644 index 9a2c9a42c..000000000 --- a/src/thirdparty/freetype2/src/autofit/afwarp.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** - * - * afwarp.h - * - * Auto-fitter warping algorithm (specification). - * - * Copyright (C) 2006-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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) & ~FT_TYPEOF( 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; - - -#ifdef AF_CONFIG_OPTION_USE_WARPER - FT_LOCAL( void ) - af_warper_compute( AF_Warper warper, - AF_GlyphHints hints, - AF_Dimension dim, - FT_Fixed *a_scale, - FT_Pos *a_delta ); -#endif - - -FT_END_HEADER - - -#endif /* AFWARP_H_ */ - - -/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afwrtsys.h b/src/thirdparty/freetype2/src/autofit/afwrtsys.h deleted file mode 100644 index 5611cf441..000000000 --- a/src/thirdparty/freetype2/src/autofit/afwrtsys.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** - * - * afwrtsys.h - * - * Auto-fitter writing systems (specification only). - * - * Copyright (C) 2013-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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 AFWRTSYS_H_ -#define AFWRTSYS_H_ - - /* Since preprocessor directives can't create other preprocessor */ - /* directives, we have to include the header files manually. */ - -#include "afdummy.h" -#include "aflatin.h" -#include "afcjk.h" -#include "afindic.h" -#ifdef FT_OPTION_AUTOFIT2 -#include "aflatin2.h" -#endif - -#endif /* AFWRTSYS_H_ */ - - - /* The following part can be included multiple times. */ - /* Define `WRITING_SYSTEM' as needed. */ - - - /* Add new writing systems here. The arguments are the writing system */ - /* name in lowercase and uppercase, respectively. */ - - WRITING_SYSTEM( dummy, DUMMY ) - WRITING_SYSTEM( latin, LATIN ) - WRITING_SYSTEM( cjk, CJK ) - WRITING_SYSTEM( indic, INDIC ) -#ifdef FT_OPTION_AUTOFIT2 - WRITING_SYSTEM( latin2, LATIN2 ) -#endif - - -/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afws-decl.h b/src/thirdparty/freetype2/src/autofit/afws-decl.h new file mode 100644 index 000000000..12fa7a27a --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afws-decl.h @@ -0,0 +1,33 @@ +/**************************************************************************** + * + * afws-decl.h + * + * Auto-fitter writing system declarations (specification only). + * + * Copyright (C) 2013-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 AFWS_DECL_H_ +#define AFWS_DECL_H_ + + /* Since preprocessor directives can't create other preprocessor */ + /* directives, we have to include the header files manually. */ + +#include "afdummy.h" +#include "aflatin.h" +#include "afcjk.h" +#include "afindic.h" + +#endif /* AFWS_DECL_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/afws-iter.h b/src/thirdparty/freetype2/src/autofit/afws-iter.h new file mode 100644 index 000000000..1752697b3 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/afws-iter.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * + * afws-iter.h + * + * Auto-fitter writing systems iterator (specification only). + * + * Copyright (C) 2013-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 may be included multiple times. */ + /* Define `WRITING_SYSTEM' as needed. */ + + + /* Add new writing systems here. The arguments are the writing system */ + /* name in lowercase and uppercase, respectively. */ + + WRITING_SYSTEM( dummy, DUMMY ) + WRITING_SYSTEM( latin, LATIN ) + WRITING_SYSTEM( cjk, CJK ) + WRITING_SYSTEM( indic, INDIC ) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb-decls.h b/src/thirdparty/freetype2/src/autofit/ft-hb-decls.h new file mode 100644 index 000000000..032d4d37a --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb-decls.h @@ -0,0 +1,203 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + + + /* All HarfBuzz function declarations used by FreeType, taken */ + /* from various public HarfBuzz header files. The wrapper macro */ + /* `HB_EXTERN` is defined in `ft-hb.h`. */ + + +/* hb-blob.h */ + +HB_EXTERN(hb_blob_t *, +hb_blob_create,(const char *data, + unsigned int length, + hb_memory_mode_t mode, + void *user_data, + hb_destroy_func_t destroy)) + +HB_EXTERN(void, +hb_blob_destroy,(hb_blob_t *blob)) + + +/* hb-buffer.h */ + +HB_EXTERN(void, +hb_buffer_add_utf8,(hb_buffer_t *buffer, + const char *text, + int text_length, + unsigned int item_offset, + int item_length)) + +HB_EXTERN(void, +hb_buffer_clear_contents,(hb_buffer_t *buffer)) + +HB_EXTERN(hb_buffer_t *, +hb_buffer_create,(void)) + +HB_EXTERN(void, +hb_buffer_destroy,(hb_buffer_t *buffer)) + +HB_EXTERN(hb_glyph_info_t *, +hb_buffer_get_glyph_infos,(hb_buffer_t *buffer, + unsigned int *length)) + +HB_EXTERN(hb_glyph_position_t *, +hb_buffer_get_glyph_positions,(hb_buffer_t *buffer, + unsigned int *length)) + +HB_EXTERN(unsigned int, +hb_buffer_get_length,(const hb_buffer_t *buffer)) + +HB_EXTERN(void, +hb_buffer_guess_segment_properties,(hb_buffer_t *buffer)) + + +/* hb-face.h */ + +HB_EXTERN(hb_face_t *, +hb_face_create,(hb_blob_t *blob, + unsigned int index)) + +HB_EXTERN(hb_face_t *, +hb_face_create_for_tables,(hb_reference_table_func_t reference_table_func, + void *user_data, + hb_destroy_func_t destroy)) + +HB_EXTERN(void, +hb_face_destroy,(hb_face_t *face)) + +HB_EXTERN(void, +hb_face_set_index,(hb_face_t *face, + unsigned int index)) + +HB_EXTERN(void, +hb_face_set_upem,(hb_face_t *face, + unsigned int upem)) + + +/* hb-font.h */ + +HB_EXTERN(hb_font_t *, +hb_font_create,(hb_face_t *face)) + +HB_EXTERN(void, +hb_font_destroy,(hb_font_t *font)) + +HB_EXTERN(hb_face_t *, +hb_font_get_face,(hb_font_t *font)) + +HB_EXTERN(void, +hb_font_set_scale,(hb_font_t *font, + int x_scale, + int y_scale)) + + +/* hb-ot-layout.h */ + +HB_EXTERN(void, +hb_ot_layout_collect_lookups,(hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */)) + +HB_EXTERN(void, +hb_ot_layout_lookup_collect_glyphs,(hb_face_t *face, + hb_tag_t table_tag, + unsigned int lookup_index, + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */)) + +HB_EXTERN(hb_bool_t, +hb_ot_layout_lookup_would_substitute,(hb_face_t *face, + unsigned int lookup_index, + const hb_codepoint_t *glyphs, + unsigned int glyphs_length, + hb_bool_t zero_context)) + +HB_EXTERN(void, +hb_ot_tags_from_script_and_language,(hb_script_t script, + hb_language_t language, + unsigned int *script_count /* IN/OUT */, + hb_tag_t *script_tags /* OUT */, + unsigned int *language_count /* IN/OUT */, + hb_tag_t *language_tags /* OUT */)) + + +/* hb-set.h */ + +HB_EXTERN(void, +hb_set_add,(hb_set_t *set, + hb_codepoint_t codepoint)) + +HB_EXTERN(void, +hb_set_clear,(hb_set_t *set)) + +HB_EXTERN(hb_set_t *, +hb_set_create,(void)) + +HB_EXTERN(void, +hb_set_destroy,(hb_set_t *set)) + +HB_EXTERN(void, +hb_set_del,(hb_set_t *set, + hb_codepoint_t codepoint)) + +HB_EXTERN(hb_bool_t, +hb_set_has,(const hb_set_t *set, + hb_codepoint_t codepoint)) + +HB_EXTERN(hb_bool_t, +hb_set_is_empty,(const hb_set_t *set)) + +HB_EXTERN(hb_bool_t, +hb_set_next,(const hb_set_t *set, + hb_codepoint_t *codepoint)) + +HB_EXTERN(void, +hb_set_subtract,(hb_set_t *set, + const hb_set_t *other)) + + +/* hb-shape.h */ + +HB_EXTERN(void, +hb_shape,(hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features)) + +HB_EXTERN(hb_bool_t, +hb_version_atleast,(unsigned int major, + unsigned int minor, + unsigned int micro)) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb-ft.c b/src/thirdparty/freetype2/src/autofit/ft-hb-ft.c new file mode 100644 index 000000000..d82106b54 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb-ft.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#include +#include + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +#include "ft-hb-ft.h" + +/* The following three functions are a more or less verbatim + * copy of corresponding HarfBuzz code from hb-ft.cc + */ + +static hb_blob_t * +ft_hb_ft_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data) +{ + AF_FaceGlobals globals = (AF_FaceGlobals) user_data; + + FT_Face ft_face = globals->face; + FT_Byte *buffer; + FT_ULong length = 0; + FT_Error error; + + FT_UNUSED (face); + + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); + if (error) + return NULL; + + buffer = (FT_Byte *) ft_smalloc (length); + if (!buffer) + return NULL; + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); + if (error) + { + free (buffer); + return NULL; + } + + return hb(blob_create) ((const char *) buffer, length, + HB_MEMORY_MODE_WRITABLE, + buffer, ft_sfree); +} + +static hb_face_t * +ft_hb_ft_face_create (AF_FaceGlobals globals) +{ + FT_Face ft_face = globals->face; + + hb_face_t *face; + + if (!ft_face->stream->read) { + hb_blob_t *blob; + + blob = hb(blob_create) ((const char *) ft_face->stream->base, + (unsigned int) ft_face->stream->size, + HB_MEMORY_MODE_READONLY, + ft_face, NULL); + face = hb(face_create) (blob, ft_face->face_index); + hb(blob_destroy) (blob); + } else { + face = hb(face_create_for_tables) (ft_hb_ft_reference_table, globals, NULL); + } + + hb(face_set_index) (face, ft_face->face_index); + hb(face_set_upem) (face, ft_face->units_per_EM); + + return face; +} + +FT_LOCAL_DEF(hb_font_t *) +ft_hb_ft_font_create (AF_FaceGlobals globals) +{ + hb_font_t *font; + hb_face_t *face; + + face = ft_hb_ft_face_create (globals); + font = hb(font_create) (face); + hb(face_destroy) (face); + return font; +} + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* ANSI C doesn't like empty source files */ +typedef int ft_hb_ft_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb-ft.h b/src/thirdparty/freetype2/src/autofit/ft-hb-ft.h new file mode 100644 index 000000000..f4f1d6291 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb-ft.h @@ -0,0 +1,46 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + +#ifndef FT_HB_FT_H +#define FT_HB_FT_H + +#include "ft-hb.h" + +#include "afglobal.h" + + +FT_BEGIN_HEADER + +FT_LOCAL(hb_font_t *) +ft_hb_ft_font_create (AF_FaceGlobals globals); + + +FT_END_HEADER + +#endif /* FT_HB_FT_H */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb-types.h b/src/thirdparty/freetype2/src/autofit/ft-hb-types.h new file mode 100644 index 000000000..6176622f7 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb-types.h @@ -0,0 +1,129 @@ +/* + * Copyright © 2009, 2023 Red Hat, Inc. + * Copyright © 2015 Google, Inc. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod, Matthias Clasen + * Google Author(s): Behdad Esfahbod + */ + + + /* This file is a condensed version of the public HarfBuzz header file */ + /* `hb-common.h`, also including some additional HarfBuzz declarations */ + /* and macros. It allows FreeType to load HarfBuzz dynamically without */ + /* actually using its header files. */ + + +#ifndef FT_HB_TYPES_H +#define FT_HB_TYPES_H + +#if defined (_AIX) +# include +#elif defined (_MSC_VER) && _MSC_VER < 1600 +/* VS 2010 (_MSC_VER 1600) has stdint.h */ +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#elif defined (_MSC_VER) && _MSC_VER < 1800 +/* VS 2013 (_MSC_VER 1800) has inttypes.h */ +# include +#else +# include +#endif +#include + +typedef int hb_bool_t; +typedef uint32_t hb_codepoint_t; +#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1) +typedef uint32_t hb_tag_t; + +#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF))) +#define HB_TAG_NONE HB_TAG(0,0,0,0) +#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff) +#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T') +#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S') +#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B') + +typedef int32_t hb_position_t; +typedef uint32_t hb_mask_t; + +typedef enum { + HB_DIRECTION_INVALID = 0, + HB_DIRECTION_LTR = 4, + HB_DIRECTION_RTL, + HB_DIRECTION_TTB, + HB_DIRECTION_BTT +} hb_direction_t; +typedef enum { + HB_MEMORY_MODE_DUPLICATE, + HB_MEMORY_MODE_READONLY, + HB_MEMORY_MODE_WRITABLE, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE +} hb_memory_mode_t; + +#define HB_NO_SINGLE_HEADER_ERROR +#include "hb-script-list.h" +#undef HB_NO_SINGLE_HEADER_ERROR + +typedef const struct hb_language_impl_t *hb_language_t; +#define HB_LANGUAGE_INVALID ((hb_language_t) 0) +#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID + +typedef struct hb_feature_t { + hb_tag_t tag; + uint32_t value; + unsigned int start; + unsigned int end; +} hb_feature_t; + +#define HB_FEATURE_GLOBAL_START 0 +#define HB_FEATURE_GLOBAL_END ((unsigned int) -1) + +typedef struct hb_glyph_info_t { + hb_codepoint_t codepoint; + hb_mask_t mask; + uint32_t cluster; + uint32_t var1; + uint32_t var2; +} hb_glyph_info_t; + +typedef struct hb_glyph_position_t { + hb_position_t x_advance; + hb_position_t y_advance; + hb_position_t x_offset; + hb_position_t y_offset; + uint32_t var; +} hb_glyph_position_t; + +typedef struct hb_blob_t hb_blob_t; +typedef struct hb_buffer_t hb_buffer_t; +typedef struct hb_face_t hb_face_t; +typedef struct hb_font_t hb_font_t; +typedef struct hb_set_t hb_set_t; + +typedef void (*hb_destroy_func_t) (void *data); +typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data); + +#endif /* FT_HB_TYPES_H */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb.c b/src/thirdparty/freetype2/src/autofit/ft-hb.c new file mode 100644 index 000000000..3c145d046 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb.c @@ -0,0 +1,197 @@ +/**************************************************************************** + * + * ft-hb.c + * + * FreeType-HarfBuzz bridge (body). + * + * Copyright (C) 2025 by + * Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + +#if !defined( _WIN32 ) && !defined( _GNU_SOURCE ) +# define _GNU_SOURCE 1 /* for RTLD_DEFAULT */ +#endif + +#include +#include + +#include "afglobal.h" + +#include "ft-hb.h" + + +#if defined( FT_CONFIG_OPTION_USE_HARFBUZZ ) && \ + defined( FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC ) + +#ifndef FT_LIBHARFBUZZ +# ifdef _WIN32 +# define FT_LIBHARFBUZZ "libharfbuzz-0.dll" +# else +# ifdef __APPLE__ +# define FT_LIBHARFBUZZ "libharfbuzz.0.dylib" +# else +# define FT_LIBHARFBUZZ "libharfbuzz.so.0" +# endif +# endif +#endif + +#ifdef _WIN32 + +# include + +#else /* !_WIN32 */ + +# include + + /* The GCC pragma suppresses the warning "ISO C forbids */ + /* assignment between function pointer and 'void *'", which */ + /* inevitably gets emitted with `-Wpedantic`; see the man */ + /* page of function `dlsym` for more information. */ +# if defined( __GNUC__ ) +# pragma GCC diagnostic push +# ifndef __cplusplus +# pragma GCC diagnostic ignored "-Wpedantic" +# endif +# endif + +#endif /* !_WIN32 */ + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + FT_Error error; + + ft_hb_funcs_t *funcs = NULL; + ft_hb_version_atleast_func_t version_atleast = NULL; + +#ifdef _WIN32 + HANDLE lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)GetProcAddress( lib, #name ) +#else + void *lib; +# define DLSYM( lib, name ) \ + (ft_ ## name ## _func_t)dlsym( lib, #name ) +#endif + + + af_module->hb_funcs = NULL; + + if ( FT_NEW( funcs ) ) + return; + FT_ZERO( funcs ); + +#ifdef _WIN32 + + lib = LoadLibraryA( FT_LIBHARFBUZZ ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + +#else /* !_WIN32 */ + +# ifdef RTLD_DEFAULT +# define FT_RTLD_FLAGS RTLD_LAZY | RTLD_GLOBAL + lib = RTLD_DEFAULT; + version_atleast = DLSYM( lib, hb_version_atleast ); +# else +# define FT_RTLD_FLAGS RTLD_LAZY +# endif + + if ( !version_atleast ) + { + /* Load the HarfBuzz library. + * + * We never close the library, since we opened it with RTLD_GLOBAL. + * This is important for the case where we are using HarfBuzz as a + * shared library, and we want to use the symbols from the library in + * other shared libraries or clients. HarfBuzz holds onto global + * variables, and closing the library will cause them to be + * invalidated. + */ + lib = dlopen( FT_LIBHARFBUZZ, FT_RTLD_FLAGS ); + if ( !lib ) + goto Fail; + version_atleast = DLSYM( lib, hb_version_atleast ); + } + +#endif /* !_WIN32 */ + + if ( !version_atleast ) + goto Fail; + + /* Load all symbols we use. */ +#define HB_EXTERN( ret, name, args ) \ + { \ + funcs->name = DLSYM( lib, name ); \ + if ( !funcs->name ) \ + goto Fail; \ + } +#include "ft-hb-decls.h" +#undef HB_EXTERN + +#undef DLSYM + + af_module->hb_funcs = funcs; + return; + + Fail: + if ( funcs ) + FT_FREE( funcs ); + } + + + FT_LOCAL_DEF( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ) + { + FT_Memory memory = af_module->root.memory; + + + if ( af_module->hb_funcs ) + { + FT_FREE( af_module->hb_funcs ); + af_module->hb_funcs = NULL; + } + } + + + FT_LOCAL_DEF( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) + { + return globals->module->hb_funcs != NULL; + } + +#ifndef _WIN32 +# if defined( __GNUC__ ) +# pragma GCC diagnostic pop +# endif +#endif + +#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + FT_LOCAL_DEF( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ) + { + FT_UNUSED( globals ); + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + return TRUE; +#else + return FALSE; +#endif + } + +#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/ft-hb.h b/src/thirdparty/freetype2/src/autofit/ft-hb.h new file mode 100644 index 000000000..95914deb8 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/ft-hb.h @@ -0,0 +1,82 @@ +/**************************************************************************** + * + * ft-hb.h + * + * FreeType-HarfBuzz bridge (specification). + * + * Copyright (C) 2025 by + * Behdad Esfahbod. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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_HB_H +#define FT_HB_H + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ + +# include "ft-hb-types.h" + +# ifdef FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC + +# define HB_EXTERN( ret, name, args ) \ + typedef ret (*ft_ ## name ## _func_t) args; +# include "ft-hb-decls.h" +# undef HB_EXTERN + + typedef struct ft_hb_funcs_t + { +# define HB_EXTERN( ret, name, args ) \ + ft_ ## name ## _func_t name; +# include "ft-hb-decls.h" +# undef HB_EXTERN + } ft_hb_funcs_t; + + struct AF_ModuleRec_; + + FT_LOCAL( void ) + ft_hb_funcs_init( struct AF_ModuleRec_ *af_module ); + + FT_LOCAL( void ) + ft_hb_funcs_done( struct AF_ModuleRec_ *af_module ); + +# define hb( x ) globals->module->hb_funcs->hb_ ## x + +# else /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + +# define HB_EXTERN( ret, name, args ) \ + ret name args; +# include "ft-hb-decls.h" +# undef HB_EXTERN + +# define hb( x ) hb_ ## x + +# endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ_DYNAMIC */ + +#endif /* FT_CONFIG_OPTION_USE_HARFBUZZ */ + + + struct AF_FaceGlobalsRec_; + + FT_LOCAL( FT_Bool ) + ft_hb_enabled( struct AF_FaceGlobalsRec_ *globals ); + + +FT_END_HEADER + +#endif /* FT_HB_H */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/autofit/hb-script-list.h b/src/thirdparty/freetype2/src/autofit/hb-script-list.h new file mode 100644 index 000000000..88e270d34 --- /dev/null +++ b/src/thirdparty/freetype2/src/autofit/hb-script-list.h @@ -0,0 +1,484 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#ifndef HB_SCRIPT_LIST_H +#define HB_SCRIPT_LIST_H + +/* This file belongs to the middle of hb-common.h. + * The reason it has been surgically extracted is because + * FreeType imports types and enums from hb-common.h, + * and since this enum is large and growing, we want to + * make it easy to just copy the file over to FreeType. + * https://github.com/harfbuzz/harfbuzz/issues/5271 + */ + +/* Dummy lines to make our checks happy. */ +#if 0 +#include "hb-common.h" +HB_BEGIN_DECLS +HB_END_DECLS +#endif + + +/** + * hb_script_t: + * @HB_SCRIPT_COMMON: `Zyyy` + * @HB_SCRIPT_INHERITED: `Zinh` + * @HB_SCRIPT_UNKNOWN: `Zzzz` + * @HB_SCRIPT_ARABIC: `Arab` + * @HB_SCRIPT_ARMENIAN: `Armn` + * @HB_SCRIPT_BENGALI: `Beng` + * @HB_SCRIPT_CYRILLIC: `Cyrl` + * @HB_SCRIPT_DEVANAGARI: `Deva` + * @HB_SCRIPT_GEORGIAN: `Geor` + * @HB_SCRIPT_GREEK: `Grek` + * @HB_SCRIPT_GUJARATI: `Gujr` + * @HB_SCRIPT_GURMUKHI: `Guru` + * @HB_SCRIPT_HANGUL: `Hang` + * @HB_SCRIPT_HAN: `Hani` + * @HB_SCRIPT_HEBREW: `Hebr` + * @HB_SCRIPT_HIRAGANA: `Hira` + * @HB_SCRIPT_KANNADA: `Knda` + * @HB_SCRIPT_KATAKANA: `Kana` + * @HB_SCRIPT_LAO: `Laoo` + * @HB_SCRIPT_LATIN: `Latn` + * @HB_SCRIPT_MALAYALAM: `Mlym` + * @HB_SCRIPT_ORIYA: `Orya` + * @HB_SCRIPT_TAMIL: `Taml` + * @HB_SCRIPT_TELUGU: `Telu` + * @HB_SCRIPT_THAI: `Thai` + * @HB_SCRIPT_TIBETAN: `Tibt` + * @HB_SCRIPT_BOPOMOFO: `Bopo` + * @HB_SCRIPT_BRAILLE: `Brai` + * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans` + * @HB_SCRIPT_CHEROKEE: `Cher` + * @HB_SCRIPT_ETHIOPIC: `Ethi` + * @HB_SCRIPT_KHMER: `Khmr` + * @HB_SCRIPT_MONGOLIAN: `Mong` + * @HB_SCRIPT_MYANMAR: `Mymr` + * @HB_SCRIPT_OGHAM: `Ogam` + * @HB_SCRIPT_RUNIC: `Runr` + * @HB_SCRIPT_SINHALA: `Sinh` + * @HB_SCRIPT_SYRIAC: `Syrc` + * @HB_SCRIPT_THAANA: `Thaa` + * @HB_SCRIPT_YI: `Yiii` + * @HB_SCRIPT_DESERET: `Dsrt` + * @HB_SCRIPT_GOTHIC: `Goth` + * @HB_SCRIPT_OLD_ITALIC: `Ital` + * @HB_SCRIPT_BUHID: `Buhd` + * @HB_SCRIPT_HANUNOO: `Hano` + * @HB_SCRIPT_TAGALOG: `Tglg` + * @HB_SCRIPT_TAGBANWA: `Tagb` + * @HB_SCRIPT_CYPRIOT: `Cprt` + * @HB_SCRIPT_LIMBU: `Limb` + * @HB_SCRIPT_LINEAR_B: `Linb` + * @HB_SCRIPT_OSMANYA: `Osma` + * @HB_SCRIPT_SHAVIAN: `Shaw` + * @HB_SCRIPT_TAI_LE: `Tale` + * @HB_SCRIPT_UGARITIC: `Ugar` + * @HB_SCRIPT_BUGINESE: `Bugi` + * @HB_SCRIPT_COPTIC: `Copt` + * @HB_SCRIPT_GLAGOLITIC: `Glag` + * @HB_SCRIPT_KHAROSHTHI: `Khar` + * @HB_SCRIPT_NEW_TAI_LUE: `Talu` + * @HB_SCRIPT_OLD_PERSIAN: `Xpeo` + * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo` + * @HB_SCRIPT_TIFINAGH: `Tfng` + * @HB_SCRIPT_BALINESE: `Bali` + * @HB_SCRIPT_CUNEIFORM: `Xsux` + * @HB_SCRIPT_NKO: `Nkoo` + * @HB_SCRIPT_PHAGS_PA: `Phag` + * @HB_SCRIPT_PHOENICIAN: `Phnx` + * @HB_SCRIPT_CARIAN: `Cari` + * @HB_SCRIPT_CHAM: `Cham` + * @HB_SCRIPT_KAYAH_LI: `Kali` + * @HB_SCRIPT_LEPCHA: `Lepc` + * @HB_SCRIPT_LYCIAN: `Lyci` + * @HB_SCRIPT_LYDIAN: `Lydi` + * @HB_SCRIPT_OL_CHIKI: `Olck` + * @HB_SCRIPT_REJANG: `Rjng` + * @HB_SCRIPT_SAURASHTRA: `Saur` + * @HB_SCRIPT_SUNDANESE: `Sund` + * @HB_SCRIPT_VAI: `Vaii` + * @HB_SCRIPT_AVESTAN: `Avst` + * @HB_SCRIPT_BAMUM: `Bamu` + * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp` + * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi` + * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli` + * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti` + * @HB_SCRIPT_JAVANESE: `Java` + * @HB_SCRIPT_KAITHI: `Kthi` + * @HB_SCRIPT_LISU: `Lisu` + * @HB_SCRIPT_MEETEI_MAYEK: `Mtei` + * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb` + * @HB_SCRIPT_OLD_TURKIC: `Orkh` + * @HB_SCRIPT_SAMARITAN: `Samr` + * @HB_SCRIPT_TAI_THAM: `Lana` + * @HB_SCRIPT_TAI_VIET: `Tavt` + * @HB_SCRIPT_BATAK: `Batk` + * @HB_SCRIPT_BRAHMI: `Brah` + * @HB_SCRIPT_MANDAIC: `Mand` + * @HB_SCRIPT_CHAKMA: `Cakm` + * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc` + * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero` + * @HB_SCRIPT_MIAO: `Plrd` + * @HB_SCRIPT_SHARADA: `Shrd` + * @HB_SCRIPT_SORA_SOMPENG: `Sora` + * @HB_SCRIPT_TAKRI: `Takr` + * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30 + * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30 + * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30 + * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30 + * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30 + * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30 + * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30 + * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30 + * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30 + * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30 + * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30 + * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30 + * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30 + * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30 + * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30 + * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30 + * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30 + * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30 + * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30 + * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30 + * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30 + * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30 + * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30 + * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30 + * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30 + * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30 + * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30 + * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30 + * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30 + * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0 + * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0 + * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0 + * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0 + * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0 + * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0 + * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0 + * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0 + * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0 + * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0 + * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0 + * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0 + * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0 + * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0 + * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0 + * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0 + * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0 + * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0 + * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0 + * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0 + * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0 + * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7 + * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7 + * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7 + * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7 + * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0 + * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0 + * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0 + * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 + * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 + * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 + * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0 + * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0 + * @HB_SCRIPT_GARAY: `Gara`, Since: 10.0.0 + * @HB_SCRIPT_GURUNG_KHEMA: `Gukh`, Since: 10.0.0 + * @HB_SCRIPT_KIRAT_RAI: `Krai`, Since: 10.0.0 + * @HB_SCRIPT_OL_ONAL: `Onao`, Since: 10.0.0 + * @HB_SCRIPT_SUNUWAR: `Sunu`, Since: 10.0.0 + * @HB_SCRIPT_TODHRI: `Todr`, Since: 10.0.0 + * @HB_SCRIPT_TULU_TIGALARI: `Tutg`, Since: 10.0.0 + * @HB_SCRIPT_INVALID: No script set + * + * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding + * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/). + * + * See also the Script (sc) property of the Unicode Character Database. + * + **/ + +/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */ +typedef enum +{ + HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/ + HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/ + HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/ + + HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/ + HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/ + HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/ + HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/ + HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/ + HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/ + HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/ + HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/ + HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/ + HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/ + HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/ + HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/ + HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/ + HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/ + HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/ + HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/ + HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/ + HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/ + HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/ + HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/ + HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/ + HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/ + + HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/ + + HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/ + HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/ + HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/ + HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/ + HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/ + HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/ + HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/ + HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/ + HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/ + HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/ + HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/ + HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/ + HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/ + HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/ + + HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/ + HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/ + HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/ + + HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/ + HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/ + HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/ + HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/ + + HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/ + HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/ + HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/ + HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/ + HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/ + HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/ + HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/ + + HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/ + HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/ + HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/ + HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/ + HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/ + HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/ + HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/ + HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/ + + HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/ + HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/ + HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/ + HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/ + HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/ + + HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/ + HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/ + HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/ + HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/ + HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/ + HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/ + HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/ + HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/ + HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/ + HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/ + HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/ + + HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/ + HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/ + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/ + HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/ + HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/ + HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/ + HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/ + HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/ + HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/ + HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/ + HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/ + HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/ + HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/ + + HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/ + HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/ + HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/ + + HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/ + HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/ + HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/ + HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/ + HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/ + HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ + HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/ + + /* + * Since: 0.9.30 + */ + HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ + HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ + HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ + HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/ + HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/ + HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/ + HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/ + HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/ + HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/ + HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/ + HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/ + HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/ + HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/ + HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/ + HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/ + HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/ + HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/ + HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/ + HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/ + HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/ + HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/ + HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/ + HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/ + + HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/ + HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/ + HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/ + HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/ + HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/ + HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/ + + /* + * Since 1.3.0 + */ + HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/ + HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/ + HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/ + HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/ + HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/ + HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/ + + /* + * Since 1.6.0 + */ + HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/ + HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/ + HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/ + HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/ + + /* + * Since 1.8.0 + */ + HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/ + HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/ + HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/ + HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/ + HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/ + HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/ + HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/ + + /* + * Since 2.4.0 + */ + HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/ + HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/ + HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/ + HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/ + + /* + * Since 2.6.7 + */ + HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/ + HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/ + HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/ + HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/ + + /* + * Since 3.0.0 + */ + HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/ + HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/ + HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/ + HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/ + HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/ + + /* + * Since 3.4.0 + */ + HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + + /* + * Since 5.2.0 + */ + HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/ + HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/ + + /* + * Since 10.0.0 + */ + HB_SCRIPT_GARAY = HB_TAG ('G','a','r','a'), /*16.0*/ + HB_SCRIPT_GURUNG_KHEMA = HB_TAG ('G','u','k','h'), /*16.0*/ + HB_SCRIPT_KIRAT_RAI = HB_TAG ('K','r','a','i'), /*16.0*/ + HB_SCRIPT_OL_ONAL = HB_TAG ('O','n','a','o'), /*16.0*/ + HB_SCRIPT_SUNUWAR = HB_TAG ('S','u','n','u'), /*16.0*/ + HB_SCRIPT_TODHRI = HB_TAG ('T','o','d','r'), /*16.0*/ + HB_SCRIPT_TULU_TIGALARI = HB_TAG ('T','u','t','g'), /*16.0*/ + + /* No script set. */ + HB_SCRIPT_INVALID = HB_TAG_NONE, + + /*< private >*/ + + /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t + * without risking undefined behavior. We have two, for historical reasons. + * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed + * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well. + * + * See this thread for technicalities: + * + * https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html + */ + _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/ + _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/ + +} hb_script_t; + + +#endif /* HB_SCRIPT_LIST_H */ diff --git a/src/thirdparty/freetype2/src/base/ftadvanc.c b/src/thirdparty/freetype2/src/base/ftadvanc.c index 0dfba5703..ff0fc5105 100644 --- a/src/thirdparty/freetype2/src/base/ftadvanc.c +++ b/src/thirdparty/freetype2/src/base/ftadvanc.c @@ -4,7 +4,7 @@ * * Quick computation of advance widths (body). * - * Copyright (C) 2008-2019 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,15 +16,14 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_ADVANCES_H -#include FT_INTERNAL_OBJECTS_H +#include +#include static FT_Error - _ft_face_scale_advances( FT_Face face, + ft_face_scale_advances_( FT_Face face, FT_Fixed* advances, FT_UInt count, FT_Int32 flags ) @@ -97,7 +96,7 @@ error = func( face, gindex, 1, flags, padvance ); if ( !error ) - return _ft_face_scale_advances( face, padvance, 1, flags ); + return ft_face_scale_advances_( face, padvance, 1, flags ); if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) return error; @@ -143,7 +142,7 @@ { error = func( face, start, count, flags, padvances ); if ( !error ) - return _ft_face_scale_advances( face, padvances, count, flags ); + return ft_face_scale_advances_( face, padvances, count, flags ); if ( FT_ERR_NEQ( error, Unimplemented_Feature ) ) return error; diff --git a/src/thirdparty/freetype2/src/base/ftbase.h b/src/thirdparty/freetype2/src/base/ftbase.h index 35b1c47fd..66f091165 100644 --- a/src/thirdparty/freetype2/src/base/ftbase.h +++ b/src/thirdparty/freetype2/src/base/ftbase.h @@ -4,7 +4,7 @@ * * Private functions used in the `base' module (specification). * - * Copyright (C) 2008-2019 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. * * This file is part of the FreeType project, and may only be used, @@ -20,17 +20,21 @@ #define FTBASE_H_ -#include -#include FT_INTERNAL_OBJECTS_H +#include FT_BEGIN_HEADER + FT_DECLARE_GLYPH( ft_bitmap_glyph_class ) + FT_DECLARE_GLYPH( ft_outline_glyph_class ) + FT_DECLARE_GLYPH( ft_svg_glyph_class ) + + #ifdef FT_CONFIG_OPTION_MAC_FONTS /* MacOS resource fork cannot exceed 16MB at least for Carbon code; */ - /* see https://support.microsoft.com/en-us/kb/130437 */ + /* see https://jeffpar.github.io/kbarchive/kb/130/Q130437/ */ #define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL diff --git a/src/thirdparty/freetype2/src/base/ftbbox.c b/src/thirdparty/freetype2/src/base/ftbbox.c index a0b2c46f7..feccdee5d 100644 --- a/src/thirdparty/freetype2/src/base/ftbbox.c +++ b/src/thirdparty/freetype2/src/base/ftbbox.c @@ -4,7 +4,7 @@ * * FreeType bbox computation (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -24,14 +24,13 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_BBOX_H -#include FT_IMAGE_H -#include FT_OUTLINE_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include +#include +#include typedef struct TBBox_Rec_ @@ -83,10 +82,13 @@ * @Return: * Always 0. Needed for the interface only. */ - static int - BBox_Move_To( FT_Vector* to, - TBBox_Rec* user ) + FT_CALLBACK_DEF( int ) + BBox_Move_To( const FT_Vector* to, + void* user_ ) { + TBBox_Rec* user = (TBBox_Rec*)user_; + + FT_UPDATE_BBOX( to, user->bbox ); user->last = *to; @@ -117,10 +119,13 @@ * @Return: * Always 0. Needed for the interface only. */ - static int - BBox_Line_To( FT_Vector* to, - TBBox_Rec* user ) + FT_CALLBACK_DEF( int ) + BBox_Line_To( const FT_Vector* to, + void* user_ ) { + TBBox_Rec* user = (TBBox_Rec*)user_; + + user->last = *to; return 0; @@ -206,11 +211,14 @@ * 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 ) + FT_CALLBACK_DEF( int ) + BBox_Conic_To( const FT_Vector* control, + const FT_Vector* to, + void* user_ ) { + TBBox_Rec* user = (TBBox_Rec*)user_; + + /* in case `to' is implicit and not included in bbox yet */ FT_UPDATE_BBOX( to, user->bbox ); @@ -294,10 +302,10 @@ if ( shift > 2 ) shift = 2; - q1 <<= shift; - q2 <<= shift; - q3 <<= shift; - q4 <<= shift; + q1 *= 1 << shift; + q2 *= 1 << shift; + q3 *= 1 << shift; + q4 *= 1 << shift; } else { @@ -411,12 +419,15 @@ * 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 ) + FT_CALLBACK_DEF( int ) + BBox_Cubic_To( const FT_Vector* control1, + const FT_Vector* control2, + const FT_Vector* to, + void* user_ ) { + TBBox_Rec* user = (TBBox_Rec*)user_; + + /* We don't need to check `to' since it is always an on-point, */ /* thus within the bbox. Only segments with an off-point outside */ /* the bbox can possibly reach new extreme values. */ @@ -478,7 +489,7 @@ return FT_THROW( Invalid_Outline ); /* if outline is empty, return (0,0,0,0) */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) + if ( outline->n_points == 0 || outline->n_contours == 0 ) { abbox->xMin = abbox->xMax = 0; abbox->yMin = abbox->yMax = 0; diff --git a/src/thirdparty/freetype2/src/base/ftbdf.c b/src/thirdparty/freetype2/src/base/ftbdf.c index c0fccd7b7..f15da313d 100644 --- a/src/thirdparty/freetype2/src/base/ftbdf.c +++ b/src/thirdparty/freetype2/src/base/ftbdf.c @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_BDF_H +#include +#include /* documentation is in ftbdf.h */ diff --git a/src/thirdparty/freetype2/src/base/ftbitmap.c b/src/thirdparty/freetype2/src/base/ftbitmap.c index 0e0a76fe4..2c8e44b90 100644 --- a/src/thirdparty/freetype2/src/base/ftbitmap.c +++ b/src/thirdparty/freetype2/src/base/ftbitmap.c @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_BITMAP_H -#include FT_IMAGE_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include /************************************************************************** @@ -67,11 +66,8 @@ { FT_Memory memory; FT_Error error = FT_Err_Ok; - - FT_Int pitch; - FT_ULong size; - - FT_Int source_pitch_sign, target_pitch_sign; + FT_Int pitch; + FT_Int flip; if ( !library ) @@ -83,53 +79,29 @@ if ( source == target ) return FT_Err_Ok; - source_pitch_sign = source->pitch < 0 ? -1 : 1; - target_pitch_sign = target->pitch < 0 ? -1 : 1; - - if ( !source->buffer ) - { - *target = *source; - if ( source_pitch_sign != target_pitch_sign ) - target->pitch = -target->pitch; - - return FT_Err_Ok; - } + flip = ( source->pitch < 0 && target->pitch > 0 ) || + ( source->pitch > 0 && target->pitch < 0 ); memory = library->memory; - pitch = source->pitch; + FT_FREE( target->buffer ); + *target = *source; + + if ( flip ) + target->pitch = -target->pitch; + + if ( !source->buffer ) + return FT_Err_Ok; + + pitch = source->pitch; 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 ); + FT_MEM_QALLOC_MULT( target->buffer, target->rows, pitch ); if ( !error ) { - unsigned char *p; - - - p = target->buffer; - *target = *source; - target->buffer = p; - - if ( source_pitch_sign == target_pitch_sign ) - FT_MEM_COPY( target->buffer, source->buffer, size ); - else + if ( flip ) { /* take care of bitmap flow */ FT_UInt i; @@ -147,6 +119,9 @@ t -= pitch; } } + else + FT_MEM_COPY( target->buffer, source->buffer, + (FT_Long)source->rows * pitch ); } return error; @@ -481,7 +456,7 @@ * A gamma of 2.2 is fair to assume. And then, we need to * undo the premultiplication too. * - * https://accessibility.kde.org/hsl-adjusted.php + * http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html#SideNotes * * We do the computation with integers only, applying a gamma of 2.0. * We guarantee 32-bit arithmetic to avoid overflow but the resulting @@ -489,9 +464,9 @@ * */ - l = ( 4732UL /* 0.0722 * 65536 */ * bgra[0] * bgra[0] + - 46871UL /* 0.7152 * 65536 */ * bgra[1] * bgra[1] + - 13933UL /* 0.2126 * 65536 */ * bgra[2] * bgra[2] ) >> 16; + l = ( 4731UL /* 0.072186 * 65536 */ * bgra[0] * bgra[0] + + 46868UL /* 0.715158 * 65536 */ * bgra[1] * bgra[1] + + 13937UL /* 0.212656 * 65536 */ * bgra[2] * bgra[2] ) >> 16; /* * Final transparency can be determined as follows. @@ -543,39 +518,31 @@ case FT_PIXEL_MODE_LCD_V: case FT_PIXEL_MODE_BGRA: { - FT_Int pad, old_target_pitch, target_pitch; - FT_ULong old_size; + FT_Int width = (FT_Int)source->width; + FT_Int neg = ( target->pitch == 0 && source->pitch < 0 ) || + target->pitch < 0; - old_target_pitch = target->pitch; - if ( old_target_pitch < 0 ) - old_target_pitch = -old_target_pitch; - - old_size = target->rows * (FT_UInt)old_target_pitch; + FT_Bitmap_Done( library, target ); target->pixel_mode = FT_PIXEL_MODE_GRAY; target->rows = source->rows; target->width = source->width; - pad = 0; - if ( alignment > 0 ) + if ( alignment ) { - pad = (FT_Int)source->width % alignment; - if ( pad != 0 ) - pad = alignment - pad; + FT_Int rem = width % alignment; + + + if ( rem ) + width = alignment > 0 ? width - rem + alignment + : width - rem - alignment; } - target_pitch = (FT_Int)source->width + pad; - - if ( target_pitch > 0 && - (FT_ULong)target->rows > FT_ULONG_MAX / (FT_ULong)target_pitch ) - return FT_THROW( Invalid_Argument ); - - if ( FT_QREALLOC( target->buffer, - old_size, target->rows * (FT_UInt)target_pitch ) ) + if ( FT_QALLOC_MULT( target->buffer, target->rows, width ) ) return error; - target->pitch = target->pitch < 0 ? -target_pitch : target_pitch; + target->pitch = neg ? -width : width; } break; @@ -908,14 +875,14 @@ final_rows = ( final_ury - final_lly ) >> 6; #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( "FT_Bitmap_Blend:\n" - " source bitmap: (%d, %d) -- (%d, %d); %d x %d\n", + FT_TRACE5(( "FT_Bitmap_Blend:\n" )); + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", source_llx / 64, source_lly / 64, source_urx / 64, source_ury / 64, source_->width, source_->rows )); if ( target->width && target->rows ) - FT_TRACE5(( " target bitmap: (%d, %d) -- (%d, %d); %d x %d\n", + FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", target_llx / 64, target_lly / 64, target_urx / 64, target_ury / 64, target->width, target->rows )); @@ -923,7 +890,7 @@ FT_TRACE5(( " target bitmap: empty\n" )); if ( final_width && final_rows ) - FT_TRACE5(( " final bitmap: (%d, %d) -- (%d, %d); %d x %d\n", + FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", final_llx / 64, final_lly / 64, final_urx / 64, final_ury / 64, final_width, final_rows )); @@ -957,7 +924,7 @@ if ( FT_LONG_MAX / target->pitch < (int)target->rows ) { - FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n", final_width, final_rows )); return FT_THROW( Invalid_Argument ); } @@ -985,7 +952,7 @@ if ( FT_LONG_MAX / new_pitch < (int)final_rows ) { - FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%d x %d)\n", + FT_TRACE5(( "FT_Blend_Bitmap: target bitmap too large (%u x %u)\n", final_width, final_rows )); return FT_THROW( Invalid_Argument ); } diff --git a/src/thirdparty/freetype2/src/base/ftcalc.c b/src/thirdparty/freetype2/src/base/ftcalc.c index 315dc4418..7d6e12e25 100644 --- a/src/thirdparty/freetype2/src/base/ftcalc.c +++ b/src/thirdparty/freetype2/src/base/ftcalc.c @@ -4,7 +4,7 @@ * * Arithmetic computations (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -32,31 +32,17 @@ */ -#include -#include FT_GLYPH_H -#include FT_TRIGONOMETRY_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include +#include +#include - -#ifdef FT_MULFIX_ASSEMBLER -#undef FT_MulFix + /* cancel inlining macro from internal/ftcalc.h */ +#ifdef FT_MulFix +# undef FT_MulFix #endif -/* we need to emulate a 64-bit data type if a real one isn't available */ - -#ifndef FT_LONG64 - - typedef struct FT_Int64_ - { - FT_UInt32 lo; - FT_UInt32 hi; - - } FT_Int64; - -#endif /* !FT_LONG64 */ - /************************************************************************** * @@ -70,24 +56,26 @@ /* transfer sign, leaving a positive number; */ /* we need an unsigned value to safely negate INT_MIN (or LONG_MIN) */ -#define FT_MOVE_SIGN( x, x_unsigned, s ) \ - FT_BEGIN_STMNT \ - if ( x < 0 ) \ - { \ - x_unsigned = 0U - (x_unsigned); \ - s = -s; \ - } \ +#define FT_MOVE_SIGN( utype, x, x_unsigned, s ) \ + FT_BEGIN_STMNT \ + if ( x < 0 ) \ + { \ + x_unsigned = 0U - (utype)x; \ + s = -s; \ + } \ + else \ + x_unsigned = (utype)x; \ FT_END_STMNT /* The following three functions are available regardless of whether */ - /* FT_LONG64 is defined. */ + /* FT_INT64 is defined. */ /* documentation is in freetype.h */ FT_EXPORT_DEF( FT_Fixed ) FT_RoundFix( FT_Fixed a ) { - return ( ADD_LONG( a, 0x8000L - ( a < 0 ) ) ) & ~0xFFFFL; + return ADD_LONG( a, 0x8000L - ( a < 0 ) ) & ~0xFFFFL; } @@ -96,7 +84,7 @@ FT_EXPORT_DEF( FT_Fixed ) FT_CeilFix( FT_Fixed a ) { - return ( ADD_LONG( a, 0xFFFFL ) ) & ~0xFFFFL; + return ADD_LONG( a, 0xFFFFL ) & ~0xFFFFL; } @@ -110,7 +98,7 @@ #ifndef FT_MSB - FT_BASE_DEF ( FT_Int ) + FT_BASE_DEF( FT_Int ) FT_MSB( FT_UInt32 z ) { FT_Int shift = 0; @@ -165,7 +153,7 @@ } -#ifdef FT_LONG64 +#ifdef FT_INT64 /* documentation is in freetype.h */ @@ -180,13 +168,9 @@ FT_Long d_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - c = (FT_UInt64)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); d = c > 0 ? ( a * b + ( c >> 1 ) ) / c : 0x7FFFFFFFUL; @@ -209,13 +193,9 @@ FT_Long d_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - c = (FT_UInt64)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, c_, c, s ); d = c > 0 ? a * b / c : 0x7FFFFFFFUL; @@ -232,18 +212,18 @@ FT_MulFix( FT_Long a_, FT_Long b_ ) { -#ifdef FT_MULFIX_ASSEMBLER +#ifdef FT_CONFIG_OPTION_INLINE_MULFIX - return FT_MULFIX_ASSEMBLER( (FT_Int32)a_, (FT_Int32)b_ ); + return FT_MulFix_64( a_, b_ ); #else - FT_Int64 ab = (FT_Int64)a_ * (FT_Int64)b_; + FT_Int64 ab = MUL_INT64( a_, b_ ); /* this requires arithmetic right shift of signed numbers */ - return (FT_Long)( ( ab + 0x8000L - ( ab < 0 ) ) >> 16 ); + return (FT_Long)( ( ab + 0x8000L + ( ab >> 63 ) ) >> 16 ); -#endif /* FT_MULFIX_ASSEMBLER */ +#endif /* FT_CONFIG_OPTION_INLINE_MULFIX */ } @@ -258,11 +238,8 @@ FT_Long q_; - a = (FT_UInt64)a_; - b = (FT_UInt64)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt64, a_, a, s ); + FT_MOVE_SIGN( FT_UInt64, b_, b, s ); q = b > 0 ? ( ( a << 16 ) + ( b >> 1 ) ) / b : 0x7FFFFFFFUL; @@ -273,7 +250,7 @@ } -#else /* !FT_LONG64 */ +#else /* !FT_INT64 */ static void @@ -423,13 +400,9 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - c = (FT_UInt32)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); if ( c == 0 ) a = 0x7FFFFFFFUL; @@ -471,13 +444,9 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - c = (FT_UInt32)c_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); - FT_MOVE_SIGN( c_, c, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, c_, c, s ); if ( c == 0 ) a = 0x7FFFFFFFUL; @@ -576,11 +545,8 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); if ( a + ( b >> 8 ) <= 8190UL ) a = ( a * b + 0x8000UL ) >> 16; @@ -615,11 +581,8 @@ /* XXX: this function does not allow 64-bit arguments */ - a = (FT_UInt32)a_; - b = (FT_UInt32)b_; - - FT_MOVE_SIGN( a_, a, s ); - FT_MOVE_SIGN( b_, b, s ); + FT_MOVE_SIGN( FT_UInt32, a_, a, s ); + FT_MOVE_SIGN( FT_UInt32, b_, b, s ); if ( b == 0 ) { @@ -652,7 +615,7 @@ } -#endif /* !FT_LONG64 */ +#endif /* !FT_INT64 */ /* documentation is in ftglyph.h */ @@ -750,65 +713,43 @@ FT_BASE_DEF( FT_Bool ) FT_Matrix_Check( const FT_Matrix* matrix ) { - FT_Matrix m; - FT_Fixed val[4]; - FT_Fixed nonzero_minval, maxval; - FT_Fixed temp1, temp2; - FT_UInt i; + FT_Fixed xx, xy, yx, yy; + FT_Fixed val; + FT_Int shift; + FT_ULong temp1, temp2; if ( !matrix ) return 0; - val[0] = FT_ABS( matrix->xx ); - val[1] = FT_ABS( matrix->xy ); - val[2] = FT_ABS( matrix->yx ); - val[3] = FT_ABS( matrix->yy ); + xx = matrix->xx; + xy = matrix->xy; + yx = matrix->yx; + yy = matrix->yy; + val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy ); - /* - * To avoid overflow, we ensure that each value is not larger than - * - * int(sqrt(2^31 / 4)) = 23170 ; - * - * we also check that no value becomes zero if we have to scale. - */ - - maxval = 0; - nonzero_minval = FT_LONG_MAX; - - for ( i = 0; i < 4; i++ ) - { - if ( val[i] > maxval ) - maxval = val[i]; - if ( val[i] && val[i] < nonzero_minval ) - nonzero_minval = val[i]; - } - - /* we only handle 32bit values */ - if ( maxval > 0x7FFFFFFFL ) + /* we only handle non-zero 32-bit values */ + if ( !val || val > 0x7FFFFFFFL ) return 0; - if ( maxval > 23170 ) + /* Scale matrix to avoid the temp1 overflow, which is */ + /* more stringent than avoiding the temp2 overflow. */ + + shift = FT_MSB( val ) - 12; + + if ( shift > 0 ) { - FT_Fixed scale = FT_DivFix( maxval, 23170 ); - - - if ( !FT_DivFix( nonzero_minval, scale ) ) - return 0; /* value range too large */ - - m.xx = FT_DivFix( matrix->xx, scale ); - m.xy = FT_DivFix( matrix->xy, scale ); - m.yx = FT_DivFix( matrix->yx, scale ); - m.yy = FT_DivFix( matrix->yy, scale ); + xx >>= shift; + xy >>= shift; + yx >>= shift; + yy >>= shift; } - else - m = *matrix; - temp1 = FT_ABS( m.xx * m.yy - m.xy * m.yx ); - temp2 = m.xx * m.xx + m.xy * m.xy + m.yx * m.yx + m.yy * m.yy; + temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx ); + temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) + + (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy ); - if ( temp1 == 0 || - temp2 / temp1 > 50 ) + if ( temp1 <= temp2 ) return 0; return 1; @@ -852,11 +793,8 @@ FT_Int sx = 1, sy = 1, shift; - x = (FT_UInt32)x_; - y = (FT_UInt32)y_; - - FT_MOVE_SIGN( x_, x, sx ); - FT_MOVE_SIGN( y_, y, sy ); + FT_MOVE_SIGN( FT_UInt32, x_, x, sx ); + FT_MOVE_SIGN( FT_UInt32, y_, y, sy ); /* trivial cases */ if ( x == 0 ) @@ -936,44 +874,72 @@ } -#if 0 - /* documentation is in ftcalc.h */ - FT_BASE_DEF( FT_Int32 ) - FT_SqrtFixed( FT_Int32 x ) + FT_BASE_DEF( FT_UInt32 ) + FT_SqrtFixed( FT_UInt32 v ) { - FT_UInt32 root, rem_hi, rem_lo, test_div; - FT_Int count; + if ( v == 0 ) + return 0; +#ifndef FT_INT64 - root = 0; - - if ( x > 0 ) + /* Algorithm by Christophe Meessen (1993) with overflow fixed and */ + /* rounding added. Any unsigned fixed 16.16 argument is acceptable. */ + /* However, this algorithm is slower than the Babylonian method with */ + /* a good initial guess. We only use it for large 32-bit values when */ + /* 64-bit computations are not desirable. */ + else if ( v > 0x10000U ) { - rem_hi = 0; - rem_lo = (FT_UInt32)x; - count = 24; + FT_UInt32 r = v >> 1; + FT_UInt32 q = ( v & 1 ) << 15; + FT_UInt32 b = 0x20000000; + FT_UInt32 t; + + do { - rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 ); - rem_lo <<= 2; - root <<= 1; - test_div = ( root << 1 ) + 1; - - if ( rem_hi >= test_div ) + t = q + b; + if ( r >= t ) { - rem_hi -= test_div; - root += 1; + r -= t; + q = t + b; /* equivalent to q += 2*b */ } - } while ( --count ); + r <<= 1; + b >>= 1; + + } while ( b > 0x10 ); /* exactly 25 cycles */ + + return ( q + 0x40 ) >> 7; } + else + { + FT_UInt32 r = ( v << 16 ) - 1; - return (FT_Int32)root; +#else /* FT_INT64 */ + + else + { + FT_UInt64 r = ( (FT_UInt64)v << 16 ) - 1; + +#endif /* FT_INT64 */ + + FT_UInt32 q = 1 << ( ( 17 + FT_MSB( v ) ) >> 1 ); + FT_UInt32 t; + + + /* Babylonian method with rounded-up division */ + do + { + t = q; + q = ( t + (FT_UInt32)( r / t ) + 1 ) >> 1; + + } while ( q != t ); /* less than 6 cycles */ + + return q; + } } -#endif /* 0 */ - /* documentation is in ftcalc.h */ @@ -986,7 +952,7 @@ /* we silently ignore overflow errors since such large values */ /* lead to even more (harmless) rendering errors later on */ -#ifdef FT_LONG64 +#ifdef FT_INT64 FT_Int64 delta = SUB_INT64( MUL_INT64( in_x, out_y ), MUL_INT64( in_y, out_x ) ); @@ -996,43 +962,36 @@ #else - FT_Int result; + FT_Int64 z1, z2; + FT_Int result; - if ( ADD_LONG( FT_ABS( in_x ), FT_ABS( out_y ) ) <= 131071L && - ADD_LONG( FT_ABS( in_y ), FT_ABS( out_x ) ) <= 131071L ) + if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 92681UL ) { - FT_Long z1 = MUL_LONG( in_x, out_y ); - FT_Long z2 = MUL_LONG( in_y, out_x ); - - - if ( z1 > z2 ) - result = +1; - else if ( z1 < z2 ) - result = -1; - else - result = 0; + z1.lo = (FT_UInt32)in_x * (FT_UInt32)out_y; + z1.hi = (FT_UInt32)( (FT_Int32)z1.lo >> 31 ); /* sign-expansion */ } - else /* products might overflow 32 bits */ - { - FT_Int64 z1, z2; - - - /* XXX: this function does not allow 64-bit arguments */ + else ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 ); + + if ( (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 92681UL ) + { + z2.lo = (FT_UInt32)in_y * (FT_UInt32)out_x; + z2.hi = (FT_UInt32)( (FT_Int32)z2.lo >> 31 ); /* sign-expansion */ + } + else ft_multo64( (FT_UInt32)in_y, (FT_UInt32)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; - } + if ( (FT_Int32)z1.hi > (FT_Int32)z2.hi ) + result = +1; + else if ( (FT_Int32)z1.hi < (FT_Int32)z2.hi ) + result = -1; + else if ( z1.lo > z2.lo ) + result = +1; + else if ( z1.lo < z2.lo ) + result = -1; + else + result = 0; /* XXX: only the sign of return value, +1/0/-1 must be used */ return result; @@ -1062,7 +1021,7 @@ /* */ /* This approach has the advantage that the angle between */ /* `in' and `out' is not checked. In case one of the two */ - /* vectors is `dominant', this is, much larger than the */ + /* vectors is `dominant', that is, much larger than the */ /* other vector, we thus always have a flat corner. */ /* */ /* hypotenuse */ diff --git a/src/thirdparty/freetype2/src/base/ftcid.c b/src/thirdparty/freetype2/src/base/ftcid.c index 190b23f35..35cd0fcd2 100644 --- a/src/thirdparty/freetype2/src/base/ftcid.c +++ b/src/thirdparty/freetype2/src/base/ftcid.c @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information. * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_CID_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_CID_H +#include +#include +#include /* documentation is in ftcid.h */ diff --git a/src/thirdparty/freetype2/src/base/ftcolor.c b/src/thirdparty/freetype2/src/base/ftcolor.c index 8cb057a36..90b02b7d2 100644 --- a/src/thirdparty/freetype2/src/base/ftcolor.c +++ b/src/thirdparty/freetype2/src/base/ftcolor.c @@ -4,7 +4,7 @@ * * FreeType's glyph color management (body). * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_COLOR_H +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -57,9 +56,7 @@ FT_Color* *apalette ) { FT_Error error; - - TT_Face ttface; - SFNT_Service sfnt; + TT_Face ttface = (TT_Face)face; if ( !face ) @@ -73,14 +70,17 @@ return FT_Err_Ok; } - ttface = (TT_Face)face; - sfnt = (SFNT_Service)ttface->sfnt; + if ( palette_index != ttface->palette_index ) + { + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; - error = sfnt->set_palette( ttface, palette_index ); - if ( error ) - return error; - ttface->palette_index = palette_index; + error = sfnt->set_palette( ttface, palette_index ); + if ( error ) + return error; + + ttface->palette_index = palette_index; + } if ( apalette ) *apalette = ttface->palette; diff --git a/src/thirdparty/freetype2/src/base/ftdbgmem.c b/src/thirdparty/freetype2/src/base/ftdbgmem.c index 55cd269e1..7f54e759b 100644 --- a/src/thirdparty/freetype2/src/base/ftdbgmem.c +++ b/src/thirdparty/freetype2/src/base/ftdbgmem.c @@ -4,7 +4,7 @@ * * Memory debugger (body). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,11 +18,11 @@ #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 +#include +#include +#include +#include +#include #ifdef FT_DEBUG_MEMORY @@ -35,8 +35,8 @@ #include FT_CONFIG_STANDARD_LIBRARY_H - FT_BASE_DEF( const char* ) _ft_debug_file = NULL; - FT_BASE_DEF( long ) _ft_debug_lineno = 0; + FT_BASE_DEF( const char* ) ft_debug_file_ = NULL; + FT_BASE_DEF( long ) ft_debug_lineno_ = 0; extern void FT_DumpMemory( FT_Memory memory ); @@ -139,7 +139,6 @@ } FT_MemTableRec; -#define FT_MEM_SIZE_MIN 7 #define FT_MEM_SIZE_MAX 13845163 #define FT_FILENAME( x ) ( (x) ? (x) : "unknown file" ) @@ -302,46 +301,6 @@ } - static FT_MemTable - ft_mem_table_new( FT_Memory memory ) - { - FT_MemTable table; - - - table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); - if ( !table ) - 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 * (FT_Long)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 ) { @@ -350,8 +309,6 @@ FT_Long leaks = 0; - FT_DumpMemory( table->memory ); - /* remove all blocks from the table, revealing leaked ones */ for ( i = 0; i < table->size; i++ ) { @@ -413,8 +370,6 @@ 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", @@ -459,8 +414,8 @@ /* 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 ); + hash = (FT_UInt32)(FT_PtrDist)(void*)ft_debug_file_ + + (FT_UInt32)( 5 * ft_debug_lineno_ ); pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; for (;;) @@ -469,8 +424,8 @@ if ( !node ) break; - if ( node->file_name == _ft_debug_file && - node->line_no == _ft_debug_lineno ) + if ( node->file_name == ft_debug_file_ && + node->line_no == ft_debug_lineno_ ) goto Exit; pnode = &node->link; @@ -481,8 +436,8 @@ 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->file_name = ft_debug_file_; + node->line_no = ft_debug_lineno_; node->cur_blocks = 0; node->max_blocks = 0; @@ -539,7 +494,7 @@ "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 ); + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); } } @@ -621,10 +576,12 @@ 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)", + "freeing memory block at %p more than once\n" + " at (%s:%ld)!\n" + " Block was allocated at (%s:%ld)\n" + " and released at (%s:%ld).", address, - FT_FILENAME( _ft_debug_file ), _ft_debug_lineno, + 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 ); @@ -646,8 +603,8 @@ /* 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; + node->free_file_name = ft_debug_file_; + node->free_line_no = ft_debug_lineno_; } else { @@ -669,7 +626,7 @@ ft_mem_debug_panic( "trying to free unknown block at %p in (%s:%ld)\n", address, - FT_FILENAME( _ft_debug_file ), _ft_debug_lineno ); + FT_FILENAME( ft_debug_file_ ), ft_debug_lineno_ ); } } @@ -703,8 +660,8 @@ table->alloc_count++; } - _ft_debug_file = ""; - _ft_debug_lineno = 0; + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; return (FT_Pointer)block; } @@ -719,8 +676,8 @@ if ( !block ) ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", - FT_FILENAME( _ft_debug_file ), - _ft_debug_lineno ); + FT_FILENAME( ft_debug_file_ ), + ft_debug_lineno_ ); ft_mem_table_remove( table, (FT_Byte*)block, 0 ); @@ -729,8 +686,8 @@ table->alloc_count--; - _ft_debug_file = ""; - _ft_debug_lineno = 0; + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; } @@ -745,8 +702,8 @@ FT_Pointer new_block; FT_Long delta; - const char* file_name = FT_FILENAME( _ft_debug_file ); - FT_Long line_no = _ft_debug_lineno; + const char* file_name = FT_FILENAME( ft_debug_file_ ); + FT_Long line_no = ft_debug_lineno_; /* unlikely, but possible */ @@ -809,8 +766,8 @@ ft_mem_table_remove( table, (FT_Byte*)block, delta ); - _ft_debug_file = ""; - _ft_debug_lineno = 0; + ft_debug_file_ = ""; + ft_debug_lineno_ = 0; if ( !table->keep_alive ) ft_mem_table_free( table, block ); @@ -819,17 +776,30 @@ } - extern FT_Int + extern void ft_mem_debug_init( FT_Memory memory ) { FT_MemTable table; - FT_Int result = 0; - if ( ft_getenv( "FT2_DEBUG_MEMORY" ) ) + if ( !ft_getenv( "FT2_DEBUG_MEMORY" ) ) + return; + + table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); + + if ( table ) { - table = ft_mem_table_new( memory ); - if ( table ) + FT_ZERO( table ); + + table->memory = memory; + table->memory_user = memory->user; + table->alloc = memory->alloc; + table->realloc = memory->realloc; + table->free = memory->free; + + ft_mem_table_resize( table ); + + if ( table->size ) { const char* p; @@ -874,33 +844,36 @@ if ( keep_alive > 0 ) table->keep_alive = 1; } - - result = 1; } + else + memory->free( memory, table ); } - return result; } extern void ft_mem_debug_done( FT_Memory memory ) { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) + if ( memory->free == ft_mem_debug_free ) { + FT_MemTable table = (FT_MemTable)memory->user; + + + FT_DumpMemory( memory ); + + ft_mem_table_destroy( table ); + memory->free = table->free; memory->realloc = table->realloc; memory->alloc = table->alloc; + memory->user = table->memory_user; - ft_mem_table_destroy( table ); - memory->user = NULL; + memory->free( memory, table ); } } - static int + FT_COMPARE_DEF( int ) ft_mem_source_compare( const void* p1, const void* p2 ) { @@ -920,11 +893,9 @@ extern void FT_DumpMemory( FT_Memory memory ) { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) + if ( memory->free == ft_mem_debug_free ) { + FT_MemTable table = (FT_MemTable)memory->user; FT_MemSource* bucket = table->sources; FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS; FT_MemSource* sources; @@ -991,7 +962,7 @@ #else /* !FT_DEBUG_MEMORY */ /* ANSI C doesn't like empty source files */ - typedef int _debug_mem_dummy; + typedef int debug_mem_dummy_; #endif /* !FT_DEBUG_MEMORY */ diff --git a/src/thirdparty/freetype2/src/base/ftdebug.c b/src/thirdparty/freetype2/src/base/ftdebug.c index ec7233787..c615f29e5 100644 --- a/src/thirdparty/freetype2/src/base/ftdebug.c +++ b/src/thirdparty/freetype2/src/base/ftdebug.c @@ -4,7 +4,7 @@ * * Debugging and logging component (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -41,9 +41,54 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_DEBUG_H +#include +#include +#include +#include + + +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Variables used to control logging. + * + * 1. `ft_default_trace_level` stores the value of trace levels, which are + * provided to FreeType using the `FT2_DEBUG` environment variable. + * + * 2. `ft_fileptr` stores the `FILE*` handle. + * + * 3. `ft_component` is a string that holds the name of `FT_COMPONENT`. + * + * 4. The flag `ft_component_flag` prints the name of `FT_COMPONENT` along + * with the actual log message if set to true. + * + * 5. The flag `ft_timestamp_flag` prints time along with the actual log + * message if set to true. + * + * 6. `ft_have_newline_char` is used to differentiate between a log + * message with and without a trailing newline character. + * + * 7. `ft_custom_trace_level` stores the custom trace level value, which + * is provided by the user at run-time. + * + * We use `static` to avoid 'unused variable' warnings. + * + */ + static const char* ft_default_trace_level = NULL; + static FILE* ft_fileptr = NULL; + static const char* ft_component = NULL; + static FT_Bool ft_component_flag = FALSE; + static FT_Bool ft_timestamp_flag = FALSE; + static FT_Bool ft_have_newline_char = TRUE; + static const char* ft_custom_trace_level = NULL; + + /* declared in ftdebug.h */ + + dlg_handler ft_default_log_handler = NULL; + FT_Custom_Log_Handler custom_output_handler = NULL; + +#endif /* FT_DEBUG_LOGGING */ #ifdef FT_DEBUG_LEVEL_ERROR @@ -107,7 +152,6 @@ #endif /* FT_DEBUG_LEVEL_ERROR */ - #ifdef FT_DEBUG_LEVEL_TRACE /* array of trace levels, initialized to 0; */ @@ -126,7 +170,7 @@ static const char* ft_trace_toggles[trace_count + 1] = { -#include FT_INTERNAL_TRACE_H +#include NULL }; @@ -196,9 +240,18 @@ FT_BASE_DEF( void ) ft_debug_init( void ) { - const char* ft2_debug = ft_getenv( "FT2_DEBUG" ); + const char* ft2_debug = NULL; +#ifdef FT_DEBUG_LOGGING + if ( ft_custom_trace_level != NULL ) + ft2_debug = ft_custom_trace_level; + else + ft2_debug = ft_default_trace_level; +#else + ft2_debug = ft_getenv( "FT2_DEBUG" ); +#endif + if ( ft2_debug ) { const char* p = ft2_debug; @@ -211,6 +264,49 @@ if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' ) continue; +#ifdef FT_DEBUG_LOGGING + + /* check extra arguments for logging */ + if ( *p == '-' ) + { + const char* r = ++p; + + + if ( *r == 'v' ) + { + const char* s = ++r; + + + ft_component_flag = TRUE; + + if ( *s == 't' ) + { + ft_timestamp_flag = TRUE; + p++; + } + + p++; + } + + else if ( *r == 't' ) + { + const char* s = ++r; + + + ft_timestamp_flag = TRUE; + + if ( *s == 'v' ) + { + ft_component_flag = TRUE; + p++; + } + + p++; + } + } + +#endif /* FT_DEBUG_LOGGING */ + /* read toggle name, followed by ':' */ q = p; while ( *p && *p != ':' ) @@ -312,8 +408,237 @@ /* nothing */ } - #endif /* !FT_DEBUG_LEVEL_TRACE */ +#ifdef FT_DEBUG_LOGGING + + /************************************************************************** + * + * Initialize and de-initialize 'dlg' library. + * + */ + + FT_BASE_DEF( void ) + ft_logging_init( void ) + { + ft_default_log_handler = ft_log_handler; + ft_default_trace_level = ft_getenv( "FT2_DEBUG" ); + + if ( ft_getenv( "FT_LOGGING_FILE" ) ) + ft_fileptr = ft_fopen( ft_getenv( "FT_LOGGING_FILE" ), "w" ); + else + ft_fileptr = stderr; + + ft_debug_init(); + + /* Set the default output handler for 'dlg'. */ + dlg_set_handler( ft_default_log_handler, NULL ); + } + + + FT_BASE_DEF( void ) + ft_logging_deinit( void ) + { + if ( ft_fileptr != stderr ) + ft_fclose( ft_fileptr ); + } + + + /************************************************************************** + * + * An output log handler for FreeType. + * + */ + FT_BASE_DEF( void ) + ft_log_handler( const struct dlg_origin* origin, + const char* string, + void* data ) + { + char features_buf[128]; + char* bufp = features_buf; + + FT_UNUSED( data ); + + + if ( ft_have_newline_char ) + { + const char* features = NULL; + size_t features_length = 0; + + +#define FEATURES_TIMESTAMP "[%h:%m] " +#define FEATURES_COMPONENT "[%t] " +#define FEATURES_TIMESTAMP_COMPONENT "[%h:%m %t] " + + if ( ft_timestamp_flag && ft_component_flag ) + { + features = FEATURES_TIMESTAMP_COMPONENT; + features_length = sizeof ( FEATURES_TIMESTAMP_COMPONENT ); + } + else if ( ft_timestamp_flag ) + { + features = FEATURES_TIMESTAMP; + features_length = sizeof ( FEATURES_TIMESTAMP ); + } + else if ( ft_component_flag ) + { + features = FEATURES_COMPONENT; + features_length = sizeof ( FEATURES_COMPONENT ); + } + + if ( ft_component_flag || ft_timestamp_flag ) + { + ft_strncpy( features_buf, features, features_length ); + bufp += features_length - 1; + } + + if ( ft_component_flag ) + { + size_t tag_length = ft_strlen( *origin->tags ); + size_t i; + + + /* To vertically align tracing messages we compensate the */ + /* different FT_COMPONENT string lengths by inserting an */ + /* appropriate amount of space characters. */ + for ( i = 0; + i < FT_MAX_TRACE_LEVEL_LENGTH - tag_length; + i++ ) + *bufp++ = ' '; + } + } + + /* Finally add the format string for the tracing message. */ + *bufp++ = '%'; + *bufp++ = 'c'; + *bufp = '\0'; + + dlg_generic_outputf_stream( ft_fileptr, + (const char*)features_buf, + origin, + string, + dlg_default_output_styles, + true ); + + if ( ft_strrchr( string, '\n' ) ) + ft_have_newline_char = TRUE; + else + ft_have_newline_char = FALSE; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_add_tag( const char* tag ) + { + ft_component = tag; + + dlg_add_tag( tag, NULL ); + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + ft_remove_tag( const char* tag ) + { + dlg_remove_tag( tag, NULL ); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = level; + + ft_debug_init(); + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + ft_component_flag = FALSE; + ft_timestamp_flag = FALSE; + ft_custom_trace_level = NULL; + + ft_debug_init(); + } + + + /************************************************************************** + * + * Functions to handle a custom log handler. + * + */ + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + custom_output_handler = handler; + } + + + /* documentation is in ftlogging.h */ + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + custom_output_handler = NULL; + } + + + /* documentation is in ftdebug.h */ + FT_BASE_DEF( void ) + FT_Logging_Callback( const char* fmt, + ... ) + { + va_list ap; + + + va_start( ap, fmt ); + custom_output_handler( ft_component, fmt, ap ); + va_end( ap ); + } + +#else /* !FT_DEBUG_LOGGING */ + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Level( const char* level ) + { + FT_UNUSED( level ); + } + + + FT_EXPORT_DEF( void ) + FT_Trace_Set_Default_Level( void ) + { + /* nothing */ + } + + + FT_EXPORT_DEF( void ) + FT_Set_Log_Handler( FT_Custom_Log_Handler handler ) + { + FT_UNUSED( handler ); + } + + + FT_EXPORT_DEF( void ) + FT_Set_Default_Log_Handler( void ) + { + /* nothing */ + } + +#endif /* !FT_DEBUG_LOGGING */ + + /* END */ diff --git a/src/thirdparty/freetype2/src/base/fterrors.c b/src/thirdparty/freetype2/src/base/fterrors.c index 84fe59028..27e9c5134 100644 --- a/src/thirdparty/freetype2/src/base/fterrors.c +++ b/src/thirdparty/freetype2/src/base/fterrors.c @@ -4,7 +4,7 @@ * * FreeType API for error code handling. * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,9 +16,8 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_ERRORS_H +#include +#include /* documentation is in fterrors.h */ @@ -38,7 +37,7 @@ #define FT_ERRORDEF( e, v, s ) case v: return s; #define FT_ERROR_END_LIST } -#include FT_ERRORS_H +#include #endif /* defined( FT_CONFIG_OPTION_ERROR_STRINGS ) || ... */ diff --git a/src/thirdparty/freetype2/src/base/ftfntfmt.c b/src/thirdparty/freetype2/src/base/ftfntfmt.c index 54ba53741..7f4f14ffd 100644 --- a/src/thirdparty/freetype2/src/base/ftfntfmt.c +++ b/src/thirdparty/freetype2/src/base/ftfntfmt.c @@ -4,7 +4,7 @@ * * FreeType utility file for font formats (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_FONT_FORMATS_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_FONT_FORMAT_H +#include +#include +#include /* documentation is in ftfntfmt.h */ diff --git a/src/thirdparty/freetype2/src/base/ftfstype.c b/src/thirdparty/freetype2/src/base/ftfstype.c index 45e2d8089..3a95752ff 100644 --- a/src/thirdparty/freetype2/src/base/ftfstype.c +++ b/src/thirdparty/freetype2/src/base/ftfstype.c @@ -4,7 +4,7 @@ * * FreeType utility file to access FSType data (body). * - * Copyright (C) 2008-2019 by + * Copyright (C) 2008-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -15,11 +15,10 @@ * */ -#include -#include FT_TYPE1_TABLES_H -#include FT_TRUETYPE_TABLES_H -#include FT_INTERNAL_SERVICE_H -#include FT_SERVICE_POSTSCRIPT_INFO_H +#include +#include +#include +#include /* documentation is in freetype.h */ diff --git a/src/thirdparty/freetype2/src/base/ftgasp.c b/src/thirdparty/freetype2/src/base/ftgasp.c index 720fb113c..2202240b5 100644 --- a/src/thirdparty/freetype2/src/base/ftgasp.c +++ b/src/thirdparty/freetype2/src/base/ftgasp.c @@ -4,7 +4,7 @@ * * Access of TrueType's `gasp' table (body). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,9 +16,8 @@ */ -#include -#include FT_GASP_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include +#include FT_EXPORT_DEF( FT_Int ) diff --git a/src/thirdparty/freetype2/src/base/ftgloadr.c b/src/thirdparty/freetype2/src/base/ftgloadr.c index bfeed461a..47781bc4d 100644 --- a/src/thirdparty/freetype2/src/base/ftgloadr.c +++ b/src/thirdparty/freetype2/src/base/ftgloadr.c @@ -4,7 +4,7 @@ * * The FreeType glyph loader (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_GLYPH_LOADER_H -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include +#include #undef FT_COMPONENT #define FT_COMPONENT gloader @@ -93,6 +92,7 @@ base->outline.n_points = 0; base->outline.n_contours = 0; + base->outline.flags = 0; base->num_subglyphs = 0; *current = *base; @@ -146,9 +146,9 @@ 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; + current->points = FT_OFFSET( base->points, base->n_points ); + current->tags = FT_OFFSET( base->tags, base->n_points ); + current->contours = FT_OFFSET( base->contours, base->n_contours ); /* handle extra points table - if any */ if ( loader->use_extra ) @@ -169,6 +169,10 @@ FT_Memory memory = loader->memory; + if ( loader->max_points == 0 || + loader->base.extra_points != NULL ) + return FT_Err_Ok; + if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) ) { loader->use_extra = 1; @@ -189,7 +193,7 @@ FT_GlyphLoad current = &loader->current; - current->subglyphs = base->subglyphs + base->num_subglyphs; + current->subglyphs = FT_OFFSET( base->subglyphs, base->num_subglyphs ); } @@ -208,9 +212,13 @@ FT_Outline* current = &loader->current.outline; FT_Bool adjust = 0; - FT_UInt new_max, old_max; + FT_UInt new_max, old_max, min_new_max; + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + /* check points & tags */ new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points + n_points; @@ -218,10 +226,18 @@ if ( new_max > old_max ) { - new_max = FT_PAD_CEIL( new_max, 8 ); - if ( new_max > FT_OUTLINE_POINTS_MAX ) - return FT_THROW( Array_Too_Large ); + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( new_max > FT_OUTLINE_POINTS_MAX ) + new_max = FT_OUTLINE_POINTS_MAX; if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) || FT_RENEW_ARRAY( base->tags, old_max, new_max ) ) @@ -244,16 +260,28 @@ loader->max_points = new_max; } + error = FT_GlyphLoader_CreateExtra( loader ); + if ( error ) + goto Exit; + /* check contours */ old_max = loader->max_contours; new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours + n_contours; if ( new_max > old_max ) { - new_max = FT_PAD_CEIL( new_max, 4 ); - if ( new_max > FT_OUTLINE_CONTOURS_MAX ) - return FT_THROW( Array_Too_Large ); + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + min_new_max = old_max + ( old_max >> 1 ); + if ( new_max < min_new_max ) + new_max = min_new_max; + new_max = FT_PAD_CEIL( new_max, 4 ); + if ( new_max > FT_OUTLINE_CONTOURS_MAX ) + new_max = FT_OUTLINE_CONTOURS_MAX; if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) ) goto Exit; @@ -327,34 +355,25 @@ FT_BASE_DEF( void ) FT_GlyphLoader_Add( FT_GlyphLoader loader ) { - FT_GlyphLoad base; - FT_GlyphLoad current; - - FT_Int n_curr_contours; - FT_Int n_base_points; - FT_Int n; + FT_Outline* base; + FT_Outline* current; + FT_Int 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; + base = &loader->base.outline; + current = &loader->current.outline; /* 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 ); + for ( n = 0; n < current->n_contours; n++ ) + current->contours[n] += base->n_points; + + base->n_points += current->n_points; + base->n_contours += current->n_contours; + + loader->base.num_subglyphs += loader->current.num_subglyphs; /* prepare for another new glyph image */ FT_GlyphLoader_Prepare( loader ); diff --git a/src/thirdparty/freetype2/src/base/ftglyph.c b/src/thirdparty/freetype2/src/base/ftglyph.c index e6b132790..75babb1aa 100644 --- a/src/thirdparty/freetype2/src/base/ftglyph.c +++ b/src/thirdparty/freetype2/src/base/ftglyph.c @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -28,13 +28,15 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_GLYPH_H -#include FT_OUTLINE_H -#include FT_BITMAP_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include +#include +#include + +#include "ftbase.h" /************************************************************************** @@ -276,6 +278,240 @@ ) +#ifdef FT_CONFIG_OPTION_SVG + + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** FT_SvgGlyph support ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_init( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_ULong doc_length; + FT_SVG_Document document; + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( glyph )->library->memory; + + + if ( slot->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( slot->other == NULL ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + document = (FT_SVG_Document)slot->other; + + if ( document->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + /* allocate a new document */ + doc_length = document->svg_document_length; + if ( FT_QALLOC( glyph->svg_document, doc_length ) ) + goto Exit; + glyph->svg_document_length = doc_length; + + glyph->glyph_index = slot->glyph_index; + + glyph->metrics = document->metrics; + glyph->units_per_EM = document->units_per_EM; + + glyph->start_glyph_id = document->start_glyph_id; + glyph->end_glyph_id = document->end_glyph_id; + + glyph->transform = document->transform; + glyph->delta = document->delta; + + /* copy the document into glyph */ + FT_MEM_COPY( glyph->svg_document, document->svg_document, doc_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_done( FT_Glyph svg_glyph ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Memory memory = svg_glyph->library->memory; + + + /* just free the memory */ + FT_FREE( glyph->svg_document ); + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_copy( FT_Glyph svg_source, + FT_Glyph svg_target ) + { + FT_SvgGlyph source = (FT_SvgGlyph)svg_source; + FT_SvgGlyph target = (FT_SvgGlyph)svg_target; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_GLYPH( source )->library->memory; + + + if ( svg_source->format != FT_GLYPH_FORMAT_SVG ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + if ( source->svg_document_length == 0 ) + { + error = FT_THROW( Invalid_Slot_Handle ); + goto Exit; + } + + target->glyph_index = source->glyph_index; + + target->svg_document_length = source->svg_document_length; + + target->metrics = source->metrics; + target->units_per_EM = source->units_per_EM; + + target->start_glyph_id = source->start_glyph_id; + target->end_glyph_id = source->end_glyph_id; + + target->transform = source->transform; + target->delta = source->delta; + + /* allocate space for the SVG document */ + if ( FT_QALLOC( target->svg_document, target->svg_document_length ) ) + goto Exit; + + /* copy the document */ + FT_MEM_COPY( target->svg_document, + source->svg_document, + target->svg_document_length ); + + Exit: + return error; + } + + + FT_CALLBACK_DEF( void ) + ft_svg_glyph_transform( FT_Glyph svg_glyph, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = glyph->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, glyph->delta.x ), + FT_MulFix( matrix->xy, glyph->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, glyph->delta.x ), + FT_MulFix( matrix->yy, glyph->delta.y ) ), + delta->y ); + + glyph->delta.x = x; + glyph->delta.y = y; + + glyph->transform = a; + } + + + FT_CALLBACK_DEF( FT_Error ) + ft_svg_glyph_prepare( FT_Glyph svg_glyph, + FT_GlyphSlot slot ) + { + FT_SvgGlyph glyph = (FT_SvgGlyph)svg_glyph; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = svg_glyph->library->memory; + + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + return error; + + document->svg_document = glyph->svg_document; + document->svg_document_length = glyph->svg_document_length; + + document->metrics = glyph->metrics; + document->units_per_EM = glyph->units_per_EM; + + document->start_glyph_id = glyph->start_glyph_id; + document->end_glyph_id = glyph->end_glyph_id; + + document->transform = glyph->transform; + document->delta = glyph->delta; + + slot->format = FT_GLYPH_FORMAT_SVG; + slot->glyph_index = glyph->glyph_index; + slot->other = document; + + return error; + } + + + FT_DEFINE_GLYPH( + ft_svg_glyph_class, + + sizeof ( FT_SvgGlyphRec ), + FT_GLYPH_FORMAT_SVG, + + ft_svg_glyph_init, /* FT_Glyph_InitFunc glyph_init */ + ft_svg_glyph_done, /* FT_Glyph_DoneFunc glyph_done */ + ft_svg_glyph_copy, /* FT_Glyph_CopyFunc glyph_copy */ + ft_svg_glyph_transform, /* FT_Glyph_TransformFunc glyph_transform */ + NULL, /* FT_Glyph_GetBBoxFunc glyph_bbox */ + ft_svg_glyph_prepare /* FT_Glyph_PrepareFunc glyph_prepare */ + ) + +#endif /* FT_CONFIG_OPTION_SVG */ + + /*************************************************************************/ /*************************************************************************/ /**** ****/ @@ -376,6 +612,12 @@ else if ( format == FT_GLYPH_FORMAT_OUTLINE ) clazz = &ft_outline_glyph_class; +#ifdef FT_CONFIG_OPTION_SVG + /* if it is an SVG glyph */ + else if ( format == FT_GLYPH_FORMAT_SVG ) + clazz = &ft_svg_glyph_class; +#endif + else { /* try to find a renderer that supports the glyph image format */ @@ -440,7 +682,10 @@ Exit2: /* if an error occurred, destroy the glyph */ if ( error ) + { FT_Done_Glyph( glyph ); + *aglyph = NULL; + } else *aglyph = glyph; @@ -452,9 +697,9 @@ /* documentation is in ftglyph.h */ FT_EXPORT_DEF( FT_Error ) - FT_Glyph_Transform( FT_Glyph glyph, - FT_Matrix* matrix, - FT_Vector* delta ) + FT_Glyph_Transform( FT_Glyph glyph, + const FT_Matrix* matrix, + const FT_Vector* delta ) { FT_Error error = FT_Err_Ok; @@ -532,10 +777,10 @@ /* 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_Glyph_To_Bitmap( FT_Glyph* the_glyph, + FT_Render_Mode render_mode, + const FT_Vector* origin, + FT_Bool destroy ) { FT_GlyphSlotRec dummy; FT_GlyphSlot_InternalRec dummy_internal; @@ -584,7 +829,7 @@ #if 1 /* if `origin' is set, translate the glyph image */ if ( origin ) - FT_Glyph_Transform( glyph, 0, origin ); + FT_Glyph_Transform( glyph, NULL, origin ); #else FT_UNUSED( origin ); #endif @@ -594,6 +839,16 @@ if ( !error ) error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode ); +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz == &ft_svg_glyph_class ) + { + FT_Memory memory = library->memory; + + + FT_FREE( dummy.other ); + } +#endif + #if 1 if ( !destroy && origin ) { @@ -602,7 +857,7 @@ v.x = -origin->x; v.y = -origin->y; - FT_Glyph_Transform( glyph, 0, &v ); + FT_Glyph_Transform( glyph, NULL, &v ); } #endif diff --git a/src/thirdparty/freetype2/src/base/ftgxval.c b/src/thirdparty/freetype2/src/base/ftgxval.c index 0677d26fa..1961cf4fb 100644 --- a/src/thirdparty/freetype2/src/base/ftgxval.c +++ b/src/thirdparty/freetype2/src/base/ftgxval.c @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Masatake YAMATO, Redhat K.K, * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -25,11 +25,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_GX_VALIDATE_H +#include +#include /* documentation is in ftgxval.h */ diff --git a/src/thirdparty/freetype2/src/base/fthash.c b/src/thirdparty/freetype2/src/base/fthash.c index 387e6d26d..ab248ace8 100644 --- a/src/thirdparty/freetype2/src/base/fthash.c +++ b/src/thirdparty/freetype2/src/base/fthash.c @@ -39,9 +39,9 @@ */ -#include -#include FT_INTERNAL_HASH_H -#include FT_INTERNAL_MEMORY_H +#include +#include +#include #define INITIAL_HT_SIZE 241 @@ -234,7 +234,8 @@ hash_insert( FT_Hashkey key, size_t data, FT_Hash hash, - FT_Memory memory ) + FT_Memory memory, + FT_Bool overwrite ) { FT_Hashnode nn; FT_Hashnode* bp = hash_bucket( key, hash ); @@ -244,7 +245,7 @@ nn = *bp; if ( !nn ) { - if ( FT_NEW( nn ) ) + if ( FT_QNEW( nn ) ) goto Exit; *bp = nn; @@ -260,7 +261,7 @@ hash->used++; } - else + else if ( overwrite ) nn->data = data; Exit: @@ -279,7 +280,7 @@ hk.str = key; - return hash_insert( hk, data, hash, memory ); + return hash_insert( hk, data, hash, memory, TRUE ); } @@ -294,7 +295,37 @@ hk.num = num; - return hash_insert( hk, data, hash, memory ); + return hash_insert( hk, data, hash, memory, TRUE ); + } + + + FT_Error + ft_hash_str_insert_no_overwrite( const char* key, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.str = key; + + return hash_insert( hk, data, hash, memory, FALSE ); + } + + + FT_Error + ft_hash_num_insert_no_overwrite( FT_Int num, + size_t data, + FT_Hash hash, + FT_Memory memory ) + { + FT_Hashkey hk; + + + hk.num = num; + + return hash_insert( hk, data, hash, memory, FALSE ); } @@ -336,4 +367,68 @@ } + FT_Bool + ft_hash_num_iterator( FT_UInt *idx, + FT_Int *key, + size_t *value, + FT_Hash hash ) + { + FT_Hashnode nn = NULL; + + + while ( 1 ) + { + if ( *idx >= hash->size ) + return 0; + + nn = hash->table[*idx]; + if ( nn ) + break; + + (*idx)++; + } + + if ( key ) + *key = nn->key.num; + if ( value ) + *value = nn->data; + + (*idx)++; + + return 1; + } + + + FT_Bool + ft_hash_str_iterator( FT_UInt *idx, + const char* *key, + size_t *value, + FT_Hash hash ) + { + FT_Hashnode nn = NULL; + + + while ( 1 ) + { + if ( *idx >= hash->size ) + return 0; + + nn = hash->table[*idx]; + if ( nn ) + break; + + (*idx)++; + } + + if ( key ) + *key = nn->key.str; + if ( value ) + *value = nn->data; + + (*idx)++; + + return 1; + } + + /* END */ diff --git a/src/thirdparty/freetype2/src/base/ftinit.c b/src/thirdparty/freetype2/src/base/ftinit.c index c73cd78b8..37d7f87bc 100644 --- a/src/thirdparty/freetype2/src/base/ftinit.c +++ b/src/thirdparty/freetype2/src/base/ftinit.c @@ -4,7 +4,7 @@ * * FreeType initialization layer (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -39,9 +39,9 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_MODULE_H +#include +#include +#include /************************************************************************** @@ -202,6 +202,10 @@ FT_Memory memory; +#ifdef FT_DEBUG_LOGGING + ft_logging_init(); +#endif + /* check of `alibrary' delayed to `FT_New_Library' */ /* First of all, allocate a new system object -- this function is part */ @@ -248,6 +252,10 @@ /* discard memory manager */ FT_Done_Memory( memory ); +#ifdef FT_DEBUG_LOGGING + ft_logging_deinit(); +#endif + return FT_Err_Ok; } diff --git a/src/thirdparty/freetype2/src/base/ftlcdfil.c b/src/thirdparty/freetype2/src/base/ftlcdfil.c index d9f4af429..d026da8b0 100644 --- a/src/thirdparty/freetype2/src/base/ftlcdfil.c +++ b/src/thirdparty/freetype2/src/base/ftlcdfil.c @@ -4,7 +4,7 @@ * * FreeType API for color filtering of subpixel bitmap glyphs (body). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_LCD_FILTER_H -#include FT_IMAGE_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING @@ -33,7 +32,7 @@ /* add padding according to filter weights */ - FT_BASE_DEF (void) + FT_BASE_DEF( void ) ft_lcd_padding( FT_BBox* cbox, FT_GlyphSlot slot, FT_Render_Mode mode ) @@ -358,7 +357,7 @@ FT_EXPORT_DEF( FT_Error ) FT_Library_SetLcdGeometry( FT_Library library, - FT_Vector* sub ) + FT_Vector sub[3] ) { FT_UNUSED( library ); FT_UNUSED( sub ); @@ -369,7 +368,7 @@ #else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ /* add padding to accommodate outline shifts */ - FT_BASE_DEF (void) + FT_BASE_DEF( void ) ft_lcd_padding( FT_BBox* cbox, FT_GlyphSlot slot, FT_Render_Mode mode ) @@ -429,7 +428,7 @@ ft_memcpy( library->lcd_geometry, sub, 3 * sizeof( FT_Vector ) ); - return FT_THROW( Unimplemented_Feature ); + return FT_Err_Ok; } #endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ diff --git a/src/thirdparty/freetype2/src/base/ftmac.c b/src/thirdparty/freetype2/src/base/ftmac.c index 5f23ceea9..37d97be18 100644 --- a/src/thirdparty/freetype2/src/base/ftmac.c +++ b/src/thirdparty/freetype2/src/base/ftmac.c @@ -8,7 +8,7 @@ * This file is for Mac OS X only; see builds/mac/ftoldmac.c for * classic platforms built by MPW. * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -65,10 +65,10 @@ */ -#include -#include FT_FREETYPE_H -#include FT_TRUETYPE_TAGS_H -#include FT_INTERNAL_STREAM_H +#include +#include +#include +#include #include "ftbase.h" @@ -106,7 +106,7 @@ /* Don't want warnings about our own use of deprecated functions. */ #define FT_DEPRECATED_ATTRIBUTE -#include FT_MAC_H +#include #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */ #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault @@ -315,7 +315,7 @@ NULL, NULL, NULL ) ) return ( OSType ) 0; - return ((FInfo *)(info.finderInfo))->fdType; + return ( (FInfo *)( info.finderInfo ) )->fdType; } @@ -463,7 +463,7 @@ if ( ps_name_len != 0 ) { - ft_memcpy(ps_name, names[0] + 1, ps_name_len); + ft_memcpy( ps_name, names[0] + 1, ps_name_len ); ps_name[ps_name_len] = 0; } if ( style->indexes[face_index] > 1 && @@ -561,7 +561,7 @@ if ( lwfn_file_name[0] ) { err = lookup_lwfn_by_fond( pathname, lwfn_file_name, - buff, sizeof ( buff ) ); + buff, sizeof ( buff ) ); if ( !err ) have_lwfn = 1; } @@ -632,7 +632,7 @@ old_total_size = total_size; } - if ( FT_ALLOC( buffer, (FT_Long)total_size ) ) + if ( FT_QALLOC( buffer, (FT_Long)total_size ) ) goto Error; /* Second pass: append all POST data to the buffer, add PFB fields. */ @@ -753,7 +753,7 @@ if ( FT_MAC_RFORK_MAX_LEN < sfnt_size ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) + if ( FT_QALLOC( sfnt_data, (FT_Long)sfnt_size ) ) { ReleaseResource( sfnt ); return error; @@ -812,6 +812,7 @@ ResourceIndex res_index; Handle fond; short num_faces_in_res; + FT_Long count; if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) ) @@ -821,8 +822,10 @@ if ( ResError() ) return FT_THROW( Cannot_Open_Resource ); + res_index = 1; num_faces_in_res = 0; - for ( res_index = 1; ; res_index++ ) + count = face_index; + while ( count >= 0 ) { short num_faces_in_fond; @@ -834,15 +837,21 @@ 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 ); + if ( count < num_faces_in_fond ) + error = FT_New_Face_From_FOND( library, fond, count, aface ); - face_index -= num_faces_in_fond; + res_index++; + count -= num_faces_in_fond; } CloseResFile( res_ref ); + if ( !error && aface && *aface ) - (*aface)->num_faces = num_faces_in_res; + { + (*aface)->num_faces = num_faces_in_res; + (*aface)->face_index = face_index; + } + return error; } @@ -1082,7 +1091,7 @@ #else /* !FT_MACINTOSH */ /* ANSI C doesn't like empty source files */ - typedef int _ft_mac_dummy; + typedef int ft_mac_dummy_; #endif /* !FT_MACINTOSH */ diff --git a/src/thirdparty/freetype2/src/base/ftmm.c b/src/thirdparty/freetype2/src/base/ftmm.c index ba9e67f00..9e6700140 100644 --- a/src/thirdparty/freetype2/src/base/ftmm.c +++ b/src/thirdparty/freetype2/src/base/ftmm.c @@ -4,7 +4,7 @@ * * Multiple Master font support (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_MULTIPLE_MASTERS_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_METRICS_VARIATIONS_H +#include +#include +#include +#include /************************************************************************** @@ -186,6 +185,14 @@ error = FT_ERR( Invalid_Argument ); if ( service->set_mm_design ) error = service->set_mm_design( face, num_coords, coords ); + + if ( !error ) + { + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } } /* enforce recomputation of auto-hinting data */ @@ -221,6 +228,14 @@ error = FT_ERR( Invalid_Argument ); if ( service->set_mm_weightvector ) error = service->set_mm_weightvector( face, len, weightvector ); + + if ( !error ) + { + if ( len ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } } /* enforce recomputation of auto-hinting data */ @@ -277,6 +292,9 @@ if ( num_coords && !coords ) return FT_THROW( Invalid_Argument ); + if ( !num_coords && !FT_IS_VARIATION( face ) ) + return FT_Err_Ok; /* nothing to be done */ + error = ft_face_get_mm_service( face, &service_mm ); if ( !error ) { @@ -284,6 +302,36 @@ if ( service_mm->set_var_design ) error = service_mm->set_var_design( face, num_coords, coords ); + if ( !error || error == -1 || error == -2 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( error != -1 ) + { + if ( error == -2 ) /* -2 means is_variable. */ + { + face->face_flags |= FT_FACE_FLAG_VARIATION; + error = FT_Err_Ok; + } + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + /* internal error code -1 means `no change'; we can exit immediately */ if ( error == -1 ) return FT_Err_Ok; @@ -360,6 +408,30 @@ if ( service_mm->set_mm_blend ) error = service_mm->set_mm_blend( face, num_coords, coords ); + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( num_coords ) + face->face_flags |= FT_FACE_FLAG_VARIATION; + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + /* internal error code -1 means `no change'; we can exit immediately */ if ( error == -1 ) return FT_Err_Ok; @@ -411,6 +483,36 @@ if ( service_mm->set_mm_blend ) error = service_mm->set_mm_blend( face, num_coords, coords ); + if ( !error || error == -1 || error == -2 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + if ( error != -1 ) + { + if ( error == -2 ) /* -2 means is_variable. */ + { + face->face_flags |= FT_FACE_FLAG_VARIATION; + error = FT_Err_Ok; + } + else + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + } + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + /* internal error code -1 means `no change'; we can exit immediately */ if ( error == -1 ) return FT_Err_Ok; @@ -536,8 +638,35 @@ if ( !error ) { error = FT_ERR( Invalid_Argument ); - if ( service_mm->set_instance ) - error = service_mm->set_instance( face, instance_index ); + if ( service_mm->set_named_instance ) + error = service_mm->set_named_instance( face, instance_index ); + + if ( !error || error == -1 ) + { + FT_Bool is_variation_old = FT_IS_VARIATION( face ); + + + face->face_flags &= ~FT_FACE_FLAG_VARIATION; + face->face_index = ( instance_index << 16 ) | + ( face->face_index & 0xFFFFL ); + + if ( service_mm->construct_ps_name ) + { + if ( error == -1 ) + { + /* The PS name of a named instance and a non-named instance */ + /* usually differs, even if the axis values are identical. */ + if ( is_variation_old != FT_IS_VARIATION( face ) ) + service_mm->construct_ps_name( face ); + } + else + service_mm->construct_ps_name( face ); + } + } + + /* internal error code -1 means `no change'; we can exit immediately */ + if ( error == -1 ) + return FT_Err_Ok; } if ( !error ) @@ -555,11 +684,32 @@ face->autohint.data = NULL; } + return error; + } + + + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + FT_Error error; + + FT_Service_MultiMasters service_mm = NULL; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + error = ft_face_get_mm_service( face, &service_mm ); if ( !error ) { - face->face_index = ( instance_index << 16 ) | - ( face->face_index & 0xFFFFL ); - face->face_flags &= ~FT_FACE_FLAG_VARIATION; + /* no error if `get_default_named_instance` is not available */ + if ( service_mm->get_default_named_instance ) + error = service_mm->get_default_named_instance( face, + instance_index ); + else + error = FT_Err_Ok; } return error; diff --git a/src/thirdparty/freetype2/src/base/ftobjs.c b/src/thirdparty/freetype2/src/base/ftobjs.c index e301f8f11..cced4fed0 100644 --- a/src/thirdparty/freetype2/src/base/ftobjs.c +++ b/src/thirdparty/freetype2/src/base/ftobjs.c @@ -4,7 +4,7 @@ * * The FreeType private base classes (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,32 +16,33 @@ */ -#include -#include FT_LIST_H -#include FT_OUTLINE_H -#include FT_FONT_FORMATS_H +#include +#include +#include +#include -#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_INTERNAL_POSTSCRIPT_AUX_H /* for PS_Driver */ +#include +#include +#include +#include +#include +#include /* for SFNT_Load_Table_Func */ +#include /* for PS_Driver */ +#include -#include FT_TRUETYPE_TABLES_H -#include FT_TRUETYPE_TAGS_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include -#include FT_SERVICE_PROPERTIES_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 +#include +#include +#include +#include +#include +#include +#include -#include FT_DRIVER_H +#include #ifdef FT_CONFIG_OPTION_MAC_FONTS #include "ftbase.h" @@ -50,7 +51,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE -#include FT_BITMAP_H +#include #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ /* We disable the warning `conversion from XXX to YYY, */ @@ -79,6 +80,9 @@ #pragma warning( pop ) #endif + /* This array must stay in sync with the @FT_Pixel_Mode enumeration */ + /* (in file `ftimage.h`). */ + static const char* const pixel_modes[] = { "none", @@ -88,7 +92,8 @@ "gray 4-bit bitmap", "LCD 8-bit bitmap", "vertical LCD 8-bit bitmap", - "BGRA 32-bit color image bitmap" + "BGRA 32-bit color image bitmap", + "SDF 8-bit bitmap" }; #endif /* FT_DEBUG_LEVEL_TRACE */ @@ -194,6 +199,7 @@ FT_Error error; FT_Memory memory; FT_Stream stream = NULL; + FT_UInt mode; *astream = NULL; @@ -205,49 +211,56 @@ return FT_THROW( Invalid_Argument ); memory = library->memory; + mode = args->flags & + ( FT_OPEN_MEMORY | FT_OPEN_STREAM | FT_OPEN_PATHNAME ); - if ( FT_NEW( stream ) ) - goto Exit; - - stream->memory = memory; - - if ( args->flags & FT_OPEN_MEMORY ) + if ( mode == FT_OPEN_MEMORY ) { /* create a memory-based stream */ + if ( FT_NEW( stream ) ) + goto Exit; + FT_Stream_OpenMemory( stream, (const FT_Byte*)args->memory_base, (FT_ULong)args->memory_size ); + stream->memory = memory; } #ifndef FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT - else if ( args->flags & FT_OPEN_PATHNAME ) + else if ( mode == FT_OPEN_PATHNAME ) { /* create a normal system stream */ + if ( FT_NEW( stream ) ) + goto Exit; + + stream->memory = memory; error = FT_Stream_Open( stream, args->pathname ); - stream->pathname.pointer = args->pathname; + if ( error ) + FT_FREE( stream ); } - else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + else if ( ( mode == 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; + stream = args->stream; + stream->memory = memory; + error = FT_Err_Ok; } #endif else + { error = FT_THROW( Invalid_Argument ); + if ( ( args->flags & FT_OPEN_STREAM ) && args->stream ) + FT_Stream_Close( args->stream ); + } - if ( error ) - FT_FREE( stream ); - else - stream->memory = memory; /* just to be certain */ - - *astream = stream; + if ( !error ) + *astream = stream; Exit: return error; @@ -317,6 +330,19 @@ if ( !error && clazz->init_slot ) error = clazz->init_slot( slot ); +#ifdef FT_CONFIG_OPTION_SVG + /* if SVG table exists, allocate the space in `slot->other` */ + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + FT_SVG_Document document = NULL; + + + if ( FT_NEW( document ) ) + goto Exit; + slot->other = document; + } +#endif + Exit: return error; } @@ -361,7 +387,18 @@ FT_Pos width, height, pitch; - if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) + if ( slot->format == FT_GLYPH_FORMAT_SVG ) + { + FT_Module module; + SVG_Service svg_service; + + + module = FT_Get_Module( slot->library, "ot-svg" ); + svg_service = (SVG_Service)module->clazz->module_interface; + + return (FT_Bool)svg_service->preset_slot( module, slot, FALSE ); + } + else if ( slot->format != FT_GLYPH_FORMAT_OUTLINE ) return 1; if ( origin ) @@ -471,7 +508,7 @@ case FT_PIXEL_MODE_LCD_V: height *= 3; - /* fall through */ + FALL_THROUGH; case FT_PIXEL_MODE_GRAY: default: @@ -524,7 +561,7 @@ else slot->internal->flags |= FT_GLYPH_OWN_BITMAP; - (void)FT_ALLOC( slot->bitmap.buffer, size ); + FT_MEM_ALLOC( slot->bitmap.buffer, size ); return error; } @@ -536,6 +573,8 @@ ft_glyphslot_free_bitmap( slot ); /* clear all public fields in the glyph slot */ + slot->glyph_index = 0; + FT_ZERO( &slot->metrics ); FT_ZERO( &slot->outline ); @@ -551,11 +590,32 @@ slot->subglyphs = NULL; slot->control_data = NULL; slot->control_len = 0; - slot->other = NULL; - slot->format = FT_GLYPH_FORMAT_NONE; + +#ifndef FT_CONFIG_OPTION_SVG + slot->other = NULL; +#else + if ( !( slot->face->face_flags & FT_FACE_FLAG_SVG ) ) + slot->other = NULL; + else + { + if ( slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_Memory memory = slot->face->memory; + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + } +#endif + + slot->format = FT_GLYPH_FORMAT_NONE; slot->linearHoriAdvance = 0; slot->linearVertAdvance = 0; + slot->advance.x = 0; + slot->advance.y = 0; slot->lsb_delta = 0; slot->rsb_delta = 0; } @@ -568,6 +628,24 @@ FT_Driver_Class clazz = driver->clazz; FT_Memory memory = driver->root.memory; +#ifdef FT_CONFIG_OPTION_SVG + if ( slot->face->face_flags & FT_FACE_FLAG_SVG ) + { + /* Free memory in case SVG was there. */ + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal && slot->internal->flags & FT_GLYPH_OWN_GZIP_SVG ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + + + FT_FREE( doc->svg_document ); + + slot->internal->flags &= ~FT_GLYPH_OWN_GZIP_SVG; + } + + FT_FREE( slot->other ); + } +#endif if ( clazz->done_slot ) clazz->done_slot( slot ); @@ -735,6 +813,29 @@ } + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( void ) + FT_Get_Transform( FT_Face face, + FT_Matrix* matrix, + FT_Vector* delta ) + { + FT_Face_Internal internal; + + + if ( !face ) + return; + + internal = face->internal; + + if ( matrix ) + *matrix = internal->transform_matrix; + + if ( delta ) + *delta = internal->transform_delta; + } + + static FT_Renderer ft_lookup_glyph_renderer( FT_GlyphSlot slot ); @@ -804,7 +905,6 @@ FT_Library library; FT_Bool autohint = FALSE; FT_Module hinter; - TT_Face ttface = (TT_Face)face; if ( !face || !face->size || !face->glyph ) @@ -820,6 +920,11 @@ library = driver->root.library; hinter = library->auto_hinter; + /* undefined scale means no scale */ + if ( face->size->metrics.x_ppem == 0 || + face->size->metrics.y_ppem == 0 ) + load_flags |= FT_LOAD_NO_SCALE; + /* resolve load flags dependencies */ if ( load_flags & FT_LOAD_NO_RECURSE ) @@ -877,6 +982,7 @@ { FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); FT_Bool is_light_type1; + TT_Face ttface = (TT_Face)face; /* only the new Adobe engine (for both CFF and Type 1) is `light'; */ @@ -888,8 +994,7 @@ /* the check for `num_locations' assures that we actually */ /* test for instructions in a TTF and not in a CFF-based OTF */ /* */ - /* since `maxSizeOfInstructions' might be unreliable, we */ - /* check the size of the `fpgm' and `prep' tables, too -- */ + /* we check the size of the `fpgm' and `prep' tables, too -- */ /* the assumption is that there don't exist real TTFs where */ /* both `fpgm' and `prep' tables are missing */ if ( ( mode == FT_RENDER_MODE_LIGHT && @@ -897,9 +1002,8 @@ !is_light_type1 ) ) || ( FT_IS_SFNT( face ) && ttface->num_locations && - ttface->max_profile.maxSizeOfInstructions == 0 && ttface->font_program_size == 0 && - ttface->cvt_program_size == 0 ) ) + ttface->cvt_program_size <= 7 ) ) autohint = TRUE; } } @@ -909,11 +1013,22 @@ FT_AutoHinter_Interface hinting; - /* try to load embedded bitmaps first if available */ - /* */ - /* XXX: This is really a temporary hack that should disappear */ - /* promptly with FreeType 2.1! */ - /* */ + /* XXX: The use of the `FT_LOAD_XXX_ONLY` flags is not very */ + /* elegant. */ + + /* try to load SVG documents if available */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + FT_HAS_SVG( face ) ) + { + error = driver->clazz->load_glyph( slot, face->size, + glyph_index, + load_flags | FT_LOAD_SVG_ONLY ); + + if ( !error && slot->format == FT_GLYPH_FORMAT_SVG ) + goto Load_Ok; + } + + /* try to load embedded bitmaps if available */ if ( FT_HAS_FIXED_SIZES( face ) && ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) { @@ -1055,19 +1170,49 @@ } #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( "FT_Load_Glyph: index %d, flags 0x%x\n", + FT_TRACE5(( "FT_Load_Glyph: index %u, flags 0x%x\n", glyph_index, load_flags )); - FT_TRACE5(( " x advance: %f\n", slot->advance.x / 64.0 )); - FT_TRACE5(( " y advance: %f\n", slot->advance.y / 64.0 )); - FT_TRACE5(( " linear x advance: %f\n", - slot->linearHoriAdvance / 65536.0 )); - FT_TRACE5(( " linear y advance: %f\n", - slot->linearVertAdvance / 65536.0 )); - FT_TRACE5(( " bitmap %dx%d, %s (mode %d)\n", + FT_TRACE5(( " bitmap %ux%u %s, %s (mode %d)\n", slot->bitmap.width, slot->bitmap.rows, + slot->outline.points ? + slot->bitmap.buffer ? "rendered" + : "preset" + : + slot->internal->flags & FT_GLYPH_OWN_BITMAP ? "owned" + : "unowned", pixel_modes[slot->bitmap.pixel_mode], slot->bitmap.pixel_mode )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " x advance: %f\n", (double)slot->advance.x / 64 )); + FT_TRACE5(( " y advance: %f\n", (double)slot->advance.y / 64 )); + FT_TRACE5(( " linear x advance: %f\n", + (double)slot->linearHoriAdvance / 65536 )); + FT_TRACE5(( " linear y advance: %f\n", + (double)slot->linearVertAdvance / 65536 )); + + { + FT_Glyph_Metrics* metrics = &slot->metrics; + + + FT_TRACE5(( " metrics:\n" )); + FT_TRACE5(( " width: %f\n", (double)metrics->width / 64 )); + FT_TRACE5(( " height: %f\n", (double)metrics->height / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " horiBearingX: %f\n", + (double)metrics->horiBearingX / 64 )); + FT_TRACE5(( " horiBearingY: %f\n", + (double)metrics->horiBearingY / 64 )); + FT_TRACE5(( " horiAdvance: %f\n", + (double)metrics->horiAdvance / 64 )); + FT_TRACE5(( "\n" )); + FT_TRACE5(( " vertBearingX: %f\n", + (double)metrics->vertBearingX / 64 )); + FT_TRACE5(( " vertBearingY: %f\n", + (double)metrics->vertBearingY / 64 )); + FT_TRACE5(( " vertAdvance: %f\n", + (double)metrics->vertAdvance / 64 )); + } #endif Exit: @@ -1099,17 +1244,21 @@ /* destructor for sizes list */ static void destroy_size( FT_Memory memory, - FT_Size size, - FT_Driver driver ) + void* size_, + void* driver_ ) { - /* finalize client-specific data */ - if ( size->generic.finalizer ) - size->generic.finalizer( size ); + FT_Size size = (FT_Size)size_; + FT_Driver driver = (FT_Driver)driver_; + /* finalize format-specific stuff */ if ( driver->clazz->done_size ) driver->clazz->done_size( size ); + /* finalize client-specific data */ + if ( size->generic.finalizer ) + size->generic.finalizer( size ); + FT_FREE( size->internal ); FT_FREE( size ); } @@ -1147,10 +1296,12 @@ /* destructor for faces list */ static void destroy_face( FT_Memory memory, - FT_Face face, - FT_Driver driver ) + void* face_, + void* driver_ ) { - FT_Driver_Class clazz = driver->clazz; + FT_Face face = (FT_Face)face_; + FT_Driver driver = (FT_Driver)driver_; + FT_Driver_Class clazz = driver->clazz; /* discard auto-hinting data */ @@ -1164,15 +1315,11 @@ /* discard all sizes for this face */ FT_List_Finalize( &face->sizes_list, - (FT_List_Destructor)destroy_size, + destroy_size, memory, driver ); face->size = NULL; - /* now discard client data */ - if ( face->generic.finalizer ) - face->generic.finalizer( face ); - /* discard charmaps */ destroy_charmaps( face, memory ); @@ -1187,6 +1334,10 @@ face->stream = NULL; + /* now discard client data */ + if ( face->generic.finalizer ) + face->generic.finalizer( face ); + /* get rid of it */ if ( face->internal ) { @@ -1200,27 +1351,15 @@ Destroy_Driver( FT_Driver driver ) { FT_List_Finalize( &driver->faces_list, - (FT_List_Destructor)destroy_face, + destroy_face, driver->root.memory, driver ); } - /************************************************************************** - * - * @Function: - * find_unicode_charmap - * - * @Description: - * 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 + /* documentation is in ftobjs.h */ + + FT_BASE_DEF( FT_Error ) find_unicode_charmap( FT_Face face ) { FT_CharMap* first; @@ -1349,7 +1488,7 @@ static FT_Error open_face( FT_Driver driver, FT_Stream *astream, - FT_Bool external_stream, + FT_Bool *anexternal_stream, FT_Long face_index, FT_Int num_params, FT_Parameter* params, @@ -1375,7 +1514,7 @@ face->stream = *astream; /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */ - if ( external_stream ) + if ( *anexternal_stream ) face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; if ( FT_NEW( internal ) ) @@ -1405,7 +1544,10 @@ (FT_Int)face_index, num_params, params ); - *astream = face->stream; /* Stream may have been changed. */ + /* Stream may have been changed. */ + *astream = face->stream; + *anexternal_stream = + ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0; if ( error ) goto Fail; @@ -1529,14 +1671,13 @@ static void memory_stream_close( FT_Stream stream ) { - FT_Memory memory = stream->memory; + FT_Memory memory = (FT_Memory)stream->descriptor.pointer; FT_FREE( stream->base ); - stream->size = 0; - stream->base = NULL; stream->close = NULL; + FT_FREE( stream ); } @@ -1567,7 +1708,8 @@ FT_Stream_OpenMemory( stream, base, size ); - stream->close = close; + stream->descriptor.pointer = memory; + stream->close = close; *astream = stream; @@ -1588,28 +1730,37 @@ { FT_Open_Args args; FT_Error error; - FT_Stream stream = NULL; FT_Memory memory = library->memory; + args.driver = NULL; + args.flags = 0; + + if ( driver_name ) + { + args.driver = FT_Get_Module( library, driver_name ); + if ( !args.driver ) + { + FT_FREE( base ); + return FT_THROW( Missing_Module ); + } + + args.flags = args.flags | FT_OPEN_DRIVER; + } + + /* `memory_stream_close` also frees the stream object. */ error = new_memory_stream( library, base, size, memory_stream_close, - &stream ); + &args.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 ); - } + args.flags |= FT_OPEN_STREAM; #ifdef FT_MACINTOSH /* At this point, the face index has served its purpose; */ @@ -1621,21 +1772,7 @@ face_index &= 0x7FFF0000L; /* retain GX data */ #endif - error = ft_open_face_internal( library, &args, face_index, aface, 0 ); - - if ( !error ) - (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; - else -#ifdef FT_MACINTOSH - FT_Stream_Free( stream, 0 ); -#else - { - FT_Stream_Close( stream ); - FT_FREE( stream ); - } -#endif - - return error; + return ft_open_face_internal( library, &args, face_index, aface, 0 ); } @@ -1764,7 +1901,7 @@ if ( error ) goto Exit; - if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) ) + if ( FT_QALLOC( sfnt_ps, (FT_Long)length ) ) goto Exit; error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length ); @@ -1778,7 +1915,7 @@ sfnt_ps, length, FT_MIN( face_index, 0 ), - is_sfnt_cid ? "cid" : "type1", + is_sfnt_cid ? "t1cid" : "type1", aface ); Exit: { @@ -1842,15 +1979,15 @@ /* FT2 allocator takes signed long buffer length, * too large value causing overflow should be checked */ - FT_TRACE4(( " POST fragment #%d: length=0x%08x" - " total pfb_len=0x%08x\n", + FT_TRACE4(( " POST fragment #%d: length=0x%08lx" + " total pfb_len=0x%08lx\n", i, temp, pfb_len + temp + 6 )); if ( FT_MAC_RFORK_MAX_LEN < temp || FT_MAC_RFORK_MAX_LEN - temp < pfb_len + 6 ) { FT_TRACE2(( " MacOS resource length cannot exceed" - " 0x%08x\n", + " 0x%08lx\n", FT_MAC_RFORK_MAX_LEN )); error = FT_THROW( Invalid_Offset ); @@ -1861,20 +1998,20 @@ } FT_TRACE2(( " total buffer size to concatenate" - " %d POST fragments: 0x%08x\n", + " %ld POST fragments: 0x%08lx\n", resource_cnt, pfb_len + 2 )); if ( pfb_len + 2 < 6 ) { FT_TRACE2(( " too long fragment length makes" - " pfb_len confused: pfb_len=0x%08x\n", + " pfb_len confused: pfb_len=0x%08lx\n", pfb_len )); error = FT_THROW( Array_Too_Large ); goto Exit; } - if ( FT_ALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) + if ( FT_QALLOC( pfb_data, (FT_Long)pfb_len + 2 ) ) goto Exit; pfb_data[0] = 0x80; @@ -1910,7 +2047,7 @@ goto Exit2; FT_TRACE3(( "POST fragment[%d]:" - " offsets=0x%08x, rlen=0x%08x, flags=0x%04x\n", + " offsets=0x%08lx, rlen=0x%08lx, flags=0x%04x\n", i, offsets[i], rlen, flags )); error = FT_ERR( Array_Too_Large ); @@ -1937,8 +2074,8 @@ else { FT_TRACE3(( " Write POST fragment #%d header (4-byte) to buffer" - " %p + 0x%08x\n", - i, pfb_data, pfb_lenpos )); + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_lenpos )); if ( pfb_lenpos + 3 > pfb_len + 2 ) goto Exit2; @@ -1952,8 +2089,8 @@ break; FT_TRACE3(( " Write POST fragment #%d header (6-byte) to buffer" - " %p + 0x%08x\n", - i, pfb_data, pfb_pos )); + " %p + 0x%08lx\n", + i, (void*)pfb_data, pfb_pos )); if ( pfb_pos + 6 > pfb_len + 2 ) goto Exit2; @@ -1974,9 +2111,9 @@ if ( pfb_pos > pfb_len || pfb_pos + rlen > pfb_len ) goto Exit2; - FT_TRACE3(( " Load POST fragment #%d (%d byte) to buffer" - " %p + 0x%08x\n", - i, rlen, pfb_data, pfb_pos )); + FT_TRACE3(( " Load POST fragment #%d (%lu byte) to buffer" + " %p + 0x%08lx\n", + i, rlen, (void*)pfb_data, pfb_pos )); error = FT_Stream_Read( stream, (FT_Byte *)pfb_data + pfb_pos, rlen ); if ( error ) @@ -2039,7 +2176,7 @@ FT_Byte* sfnt_data = NULL; FT_Error error; FT_ULong flag_offset; - FT_Long rlen; + FT_ULong rlen; int is_cff; FT_Long face_index_in_resource = 0; @@ -2054,11 +2191,11 @@ if ( error ) goto Exit; - if ( FT_READ_LONG( rlen ) ) + if ( FT_READ_ULONG( rlen ) ) goto Exit; - if ( rlen < 1 ) + if ( !rlen ) return FT_THROW( Cannot_Open_Resource ); - if ( (FT_ULong)rlen > FT_MAC_RFORK_MAX_LEN ) + if ( rlen > FT_MAC_RFORK_MAX_LEN ) return FT_THROW( Invalid_Offset ); error = open_face_PS_from_sfnt_stream( library, @@ -2074,10 +2211,11 @@ if ( error ) goto Exit; - if ( FT_ALLOC( sfnt_data, rlen ) ) + if ( FT_QALLOC( sfnt_data, rlen ) ) return error; - error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, (FT_ULong)rlen ); - if ( error ) { + error = FT_Stream_Read( stream, (FT_Byte *)sfnt_data, rlen ); + if ( error ) + { FT_FREE( sfnt_data ); goto Exit; } @@ -2085,7 +2223,7 @@ is_cff = rlen > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); error = open_face_from_buffer( library, sfnt_data, - (FT_ULong)rlen, + rlen, face_index_in_resource, is_cff ? "cff" : "truetype", aface ); @@ -2150,7 +2288,10 @@ face_index_internal, aface ); FT_FREE( data_offsets ); if ( !error ) - (*aface)->num_faces = count; + { + (*aface)->num_faces = count; + (*aface)->face_index = face_index_internal; + } } return error; @@ -2243,7 +2384,7 @@ is_darwin_vfs = ft_raccess_rule_by_darwin_vfs( library, i ); if ( is_darwin_vfs && vfs_rfork_has_no_font ) { - FT_TRACE3(( "Skip rule %d: darwin vfs resource fork" + FT_TRACE3(( "Skip rule %u: darwin vfs resource fork" " is already checked and" " no font is found\n", i )); @@ -2252,7 +2393,7 @@ if ( errors[i] ) { - FT_TRACE3(( "Error 0x%x has occurred in rule %d\n", + FT_TRACE3(( "Error 0x%x has occurred in rule %u\n", errors[i], i )); continue; } @@ -2260,7 +2401,7 @@ args2.flags = FT_OPEN_PATHNAME; args2.pathname = file_names[i] ? file_names[i] : args->pathname; - FT_TRACE3(( "Try rule %d: %s (offset=%d) ...", + FT_TRACE3(( "Try rule %u: %s (offset=%ld) ...", i, args2.pathname, offsets[i] )); error = FT_Stream_New( library, &args2, &stream2 ); @@ -2389,6 +2530,16 @@ #endif + /* only use lower 31 bits together with sign bit */ + if ( face_index > 0 ) + face_index &= 0x7FFFFFFFL; + else + { + face_index = -face_index; + face_index &= 0x7FFFFFFFL; + face_index = -face_index; + } + #ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE3(( "FT_Open_Face: " )); if ( face_index < 0 ) @@ -2404,7 +2555,7 @@ /* test for valid `library' delayed to `FT_Stream_New' */ - if ( ( !aface && face_index >= 0 ) || !args ) + if ( !args ) return FT_THROW( Invalid_Argument ); external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) && @@ -2415,6 +2566,14 @@ if ( error ) goto Fail3; + /* Do this error check after `FT_Stream_New` to ensure that the */ + /* 'close' callback is called. */ + if ( !aface && face_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail3; + } + memory = library->memory; /* If the font driver is specified in the `args' structure, use */ @@ -2436,7 +2595,7 @@ params = args->params; } - error = open_face( driver, &stream, external_stream, face_index, + error = open_face( driver, &stream, &external_stream, face_index, num_params, params, &face ); if ( !error ) goto Success; @@ -2472,7 +2631,7 @@ params = args->params; } - error = open_face( driver, &stream, external_stream, face_index, + error = open_face( driver, &stream, &external_stream, face_index, num_params, params, &face ); if ( !error ) goto Success; @@ -2548,7 +2707,7 @@ FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" )); /* add the face object to its driver's list */ - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Fail; node->data = face; @@ -2663,10 +2822,10 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( !error && face_index < 0 ) { - FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n" - " and %ld named instance%s for face %ld\n", + FT_TRACE3(( "FT_Open_Face: The font has %ld face%s\n", face->num_faces, - face->num_faces == 1 ? "" : "s", + face->num_faces == 1 ? "" : "s" )); + FT_TRACE3(( " and %ld named instance%s for face %ld\n", face->style_flags >> 16, ( face->style_flags >> 16 ) == 1 ? "" : "s", -face_index - 1 )); @@ -2704,8 +2863,8 @@ /* documentation is in freetype.h */ FT_EXPORT_DEF( FT_Error ) - FT_Attach_Stream( FT_Face face, - FT_Open_Args* parameters ) + FT_Attach_Stream( FT_Face face, + const FT_Open_Args* parameters ) { FT_Stream stream; FT_Error error; @@ -2833,7 +2992,7 @@ memory = face->memory; /* Allocate new size object and perform basic initialisation */ - if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) ) + if ( FT_ALLOC( size, clazz->size_object_size ) || FT_QNEW( node ) ) goto Exit; size->face = face; @@ -2858,6 +3017,8 @@ if ( error ) { FT_FREE( node ); + if ( size ) + FT_FREE( size->internal ); FT_FREE( size ); } @@ -3068,10 +3229,12 @@ } - FT_BASE_DEF( void ) + FT_BASE_DEF( FT_Error ) FT_Request_Metrics( FT_Face face, FT_Size_Request req ) { + FT_Error error = FT_Err_Ok; + FT_Size_Metrics* metrics; @@ -3126,34 +3289,49 @@ scaled_h = FT_REQUEST_HEIGHT( req ); /* determine scales */ + if ( req->height || !req->width ) + { + if ( h == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + + metrics->y_scale = FT_DivFix( scaled_h, h ); + } + if ( req->width ) { + if ( w == 0 ) + { + FT_ERROR(( "FT_Request_Metrics: Divide by zero\n" )); + error = FT_ERR( Divide_By_Zero ); + goto Exit; + } + 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 ); + metrics->x_scale = metrics->y_scale; scaled_w = FT_MulDiv( scaled_h, w, h ); } + if ( !req->height ) + { + metrics->y_scale = metrics->x_scale; + scaled_h = FT_MulDiv( scaled_w, h, w ); + } + + 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; + } + Calculate_Ppem: /* calculate the ppems */ if ( req->type != FT_SIZE_REQUEST_TYPE_NOMINAL ) @@ -3162,8 +3340,18 @@ 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 ); + scaled_w = ( scaled_w + 32 ) >> 6; + scaled_h = ( scaled_h + 32 ) >> 6; + if ( scaled_w > (FT_Long)FT_USHORT_MAX || + scaled_h > (FT_Long)FT_USHORT_MAX ) + { + FT_ERROR(( "FT_Request_Metrics: Resulting ppem size too large\n" )); + error = FT_ERR( Invalid_Pixel_Size ); + goto Exit; + } + + metrics->x_ppem = (FT_UShort)scaled_w; + metrics->y_ppem = (FT_UShort)scaled_h; ft_recompute_scaled_metrics( face, metrics ); } @@ -3173,6 +3361,9 @@ metrics->x_scale = 1L << 16; metrics->y_scale = 1L << 16; } + + Exit: + return error; } @@ -3213,16 +3404,20 @@ FT_Size_Metrics* metrics = &face->size->metrics; - FT_TRACE5(( " x scale: %d (%f)\n", - metrics->x_scale, metrics->x_scale / 65536.0 )); - FT_TRACE5(( " y scale: %d (%f)\n", - metrics->y_scale, metrics->y_scale / 65536.0 )); - FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); - FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); - FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); - FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); - FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); - FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } #endif @@ -3236,7 +3431,7 @@ FT_Request_Size( FT_Face face, FT_Size_Request req ) { - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Driver_Class clazz; FT_ULong strike_index; @@ -3244,6 +3439,9 @@ if ( !face ) return FT_THROW( Invalid_Face_Handle ); + if ( !face->size ) + return FT_THROW( Invalid_Size_Handle ); + if ( !req || req->width < 0 || req->height < 0 || req->type >= FT_SIZE_REQUEST_TYPE_MAX ) return FT_THROW( Invalid_Argument ); @@ -3272,13 +3470,15 @@ */ error = FT_Match_Size( face, req, 0, &strike_index ); if ( error ) - return error; + goto Exit; return FT_Select_Size( face, (FT_Int)strike_index ); } else { - FT_Request_Metrics( face, req ); + error = FT_Request_Metrics( face, req ); + if ( error ) + goto Exit; FT_TRACE5(( "FT_Request_Size:\n" )); } @@ -3288,19 +3488,24 @@ FT_Size_Metrics* metrics = &face->size->metrics; - FT_TRACE5(( " x scale: %d (%f)\n", - metrics->x_scale, metrics->x_scale / 65536.0 )); - FT_TRACE5(( " y scale: %d (%f)\n", - metrics->y_scale, metrics->y_scale / 65536.0 )); - FT_TRACE5(( " ascender: %f\n", metrics->ascender / 64.0 )); - FT_TRACE5(( " descender: %f\n", metrics->descender / 64.0 )); - FT_TRACE5(( " height: %f\n", metrics->height / 64.0 )); - FT_TRACE5(( " max advance: %f\n", metrics->max_advance / 64.0 )); - FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); - FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); + FT_TRACE5(( " x scale: %ld (%f)\n", + metrics->x_scale, (double)metrics->x_scale / 65536 )); + FT_TRACE5(( " y scale: %ld (%f)\n", + metrics->y_scale, (double)metrics->y_scale / 65536 )); + FT_TRACE5(( " ascender: %f\n", + (double)metrics->ascender / 64 )); + FT_TRACE5(( " descender: %f\n", + (double)metrics->descender / 64 )); + FT_TRACE5(( " height: %f\n", + (double)metrics->height / 64 )); + FT_TRACE5(( " max advance: %f\n", + (double)metrics->max_advance / 64 )); + FT_TRACE5(( " x ppem: %d\n", metrics->x_ppem )); + FT_TRACE5(( " y ppem: %d\n", metrics->y_ppem )); } #endif + Exit: return error; } @@ -3450,7 +3655,7 @@ if ( akerning->x != orig_x_rounded || akerning->y != orig_y_rounded ) FT_TRACE5(( "FT_Get_Kerning: horizontal kerning" - " (%d, %d) scaled down to (%d, %d) pixels\n", + " (%ld, %ld) scaled down to (%ld, %ld) pixels\n", orig_x_rounded / 64, orig_y_rounded / 64, akerning->x / 64, akerning->y / 64 )); } @@ -3625,9 +3830,9 @@ FT_CharMap last_charmap = face->charmaps[face->num_charmaps - 1]; - if ( FT_RENEW_ARRAY( face->charmaps, - face->num_charmaps, - face->num_charmaps - 1 ) ) + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps - 1 ) ) return; /* remove it from our list of charmaps */ @@ -3659,7 +3864,7 @@ FT_CharMap charmap, FT_CMap *acmap ) { - FT_Error error = FT_Err_Ok; + FT_Error error; FT_Face face; FT_Memory memory; FT_CMap cmap = NULL; @@ -3684,9 +3889,9 @@ } /* add it to our list of charmaps */ - if ( FT_RENEW_ARRAY( face->charmaps, - face->num_charmaps, - face->num_charmaps + 1 ) ) + if ( FT_QRENEW_ARRAY( face->charmaps, + face->num_charmaps, + face->num_charmaps + 1 ) ) goto Fail; face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap; @@ -3722,7 +3927,7 @@ if ( charcode > 0xFFFFFFFFUL ) { FT_TRACE1(( "FT_Get_Char_Index: too large charcode" )); - FT_TRACE1(( " 0x%x is truncated\n", charcode )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); } result = cmap->clazz->char_index( cmap, (FT_UInt32)charcode ); @@ -3898,13 +4103,13 @@ { FT_TRACE1(( "FT_Face_GetCharVariantIndex:" " too large charcode" )); - FT_TRACE1(( " 0x%x is truncated\n", charcode )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); } if ( variantSelector > 0xFFFFFFFFUL ) { FT_TRACE1(( "FT_Face_GetCharVariantIndex:" " too large variantSelector" )); - FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); } result = vcmap->clazz->char_var_index( vcmap, ucmap, @@ -3941,13 +4146,13 @@ { FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" " too large charcode" )); - FT_TRACE1(( " 0x%x is truncated\n", charcode )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); } if ( variantSelector > 0xFFFFFFFFUL ) { FT_TRACE1(( "FT_Face_GetCharVariantIsDefault:" " too large variantSelector" )); - FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); } result = vcmap->clazz->char_var_default( vcmap, @@ -4010,7 +4215,7 @@ if ( charcode > 0xFFFFFFFFUL ) { FT_TRACE1(( "FT_Face_GetVariantsOfChar: too large charcode" )); - FT_TRACE1(( " 0x%x is truncated\n", charcode )); + FT_TRACE1(( " 0x%lx is truncated\n", charcode )); } result = vcmap->clazz->charvariant_list( vcmap, memory, @@ -4044,7 +4249,7 @@ if ( variantSelector > 0xFFFFFFFFUL ) { FT_TRACE1(( "FT_Get_Char_Index: too large variantSelector" )); - FT_TRACE1(( " 0x%x is truncated\n", variantSelector )); + FT_TRACE1(( " 0x%lx is truncated\n", variantSelector )); } result = vcmap->clazz->variantchar_list( vcmap, memory, @@ -4380,7 +4585,7 @@ FT_ListNode node = NULL; - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Exit; { @@ -4392,8 +4597,7 @@ render->glyph_format = clazz->glyph_format; /* allocate raster object if needed */ - if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && - clazz->raster_class->raster_new ) + if ( clazz->raster_class && clazz->raster_class->raster_new ) { error = clazz->raster_class->raster_new( memory, &render->raster ); if ( error ) @@ -4403,6 +4607,11 @@ render->render = clazz->render_glyph; } +#ifdef FT_CONFIG_OPTION_SVG + if ( clazz->glyph_format == FT_GLYPH_FORMAT_SVG ) + render->render = clazz->render_glyph; +#endif + /* add to list */ node->data = module; FT_List_Add( &library->renderers, node ); @@ -4440,8 +4649,7 @@ /* release raster object, if any */ - if ( render->clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE && - render->raster ) + if ( render->raster ) render->clazz->raster_class->raster_done( render->raster ); /* remove from list */ @@ -4536,9 +4744,6 @@ switch ( slot->format ) { - case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */ - break; - default: if ( slot->internal->load_flags & FT_LOAD_COLOR ) { @@ -4626,7 +4831,7 @@ else renderer = FT_Lookup_Renderer( library, slot->format, &node ); - error = FT_ERR( Unimplemented_Feature ); + error = FT_ERR( Cannot_Render_Glyph ); while ( renderer ) { error = renderer->render( renderer, slot, render_mode, NULL ); @@ -4642,6 +4847,11 @@ /* format. */ renderer = FT_Lookup_Renderer( library, slot->format, &node ); } + + /* it is not an error if we cannot render a bitmap glyph */ + if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && + slot->format == FT_GLYPH_FORMAT_BITMAP ) + error = FT_Err_Ok; } } @@ -4714,11 +4924,11 @@ /* we use FT_TRACE7 in this block */ if ( !error && - ft_trace_levels[trace_checksum] >= 7 ) + ft_trace_levels[trace_checksum] >= 7 && + slot->bitmap.buffer ) { if ( slot->bitmap.rows < 128U && - slot->bitmap.width < 128U && - slot->bitmap.buffer ) + slot->bitmap.width < 128U ) { int rows = (int)slot->bitmap.rows; int width = (int)slot->bitmap.width; @@ -4820,9 +5030,9 @@ static void Destroy_Module( FT_Module module ) { - FT_Memory memory = module->memory; - FT_Module_Class* clazz = module->clazz; - FT_Library library = module->library; + const FT_Module_Class* clazz = module->clazz; + FT_Library library = module->library; + FT_Memory memory = module->memory; if ( library && library->auto_hinter == module ) @@ -4901,9 +5111,9 @@ goto Exit; /* base initialization */ + module->clazz = clazz; 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 */ @@ -5129,16 +5339,16 @@ if ( cur == limit ) { - FT_ERROR(( "%s: can't find module `%s'\n", - func_name, module_name )); + FT_TRACE2(( "%s: can't find module `%s'\n", + func_name, module_name )); return FT_THROW( Missing_Module ); } /* check whether we have a service interface */ if ( !cur[0]->clazz->get_interface ) { - FT_ERROR(( "%s: module `%s' doesn't support properties\n", - func_name, module_name )); + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5147,8 +5357,8 @@ FT_SERVICE_ID_PROPERTIES ); if ( !interface ) { - FT_ERROR(( "%s: module `%s' doesn't support properties\n", - func_name, module_name )); + FT_TRACE2(( "%s: module `%s' doesn't support properties\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5161,8 +5371,8 @@ if ( missing_func ) { - FT_ERROR(( "%s: property service of module `%s' is broken\n", - func_name, module_name )); + FT_TRACE2(( "%s: property service of module `%s' is broken\n", + func_name, module_name )); return FT_THROW( Unimplemented_Feature ); } @@ -5272,10 +5482,12 @@ if ( !memory || !alibrary ) return FT_THROW( Invalid_Argument ); +#ifndef FT_DEBUG_LOGGING #ifdef FT_DEBUG_LEVEL_ERROR /* init debugging support */ ft_debug_init(); -#endif +#endif /* FT_DEBUG_LEVEL_ERROR */ +#endif /* !FT_DEBUG_LOGGING */ /* first of all, allocate the library object */ if ( FT_NEW( library ) ) @@ -5547,4 +5759,145 @@ } + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_Paint( FT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colr_glyph_paint ) + return sfnt->get_colr_glyph_paint( ttface, + base_glyph, + root_transform, + paint ); + else + return 0; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Color_Glyph_ClipBox( FT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !clip_box ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_color_glyph_clipbox ) + return sfnt->get_color_glyph_clipbox( ttface, + base_glyph, + clip_box ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint_Layers( FT_Face face, + FT_LayerIterator* layer_iterator, + FT_OpaquePaint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint || !layer_iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint_layers ) + return sfnt->get_paint_layers( ttface, layer_iterator, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Paint( FT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !paint ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_paint ) + return sfnt->get_paint( ttface, opaque_paint, paint ); + else + return 0; + } + + + /* documentation is in freetype.h */ + + FT_EXPORT_DEF( FT_Bool ) + FT_Get_Colorline_Stops ( FT_Face face, + FT_ColorStop * color_stop, + FT_ColorStopIterator *iterator ) + { + TT_Face ttface; + SFNT_Service sfnt; + + + if ( !face || !color_stop || !iterator ) + return 0; + + if ( !FT_IS_SFNT( face ) ) + return 0; + + ttface = (TT_Face)face; + sfnt = (SFNT_Service)ttface->sfnt; + + if ( sfnt->get_colorline_stops ) + return sfnt->get_colorline_stops ( ttface, color_stop, iterator ); + else + return 0; + } + + /* END */ diff --git a/src/thirdparty/freetype2/src/base/ftotval.c b/src/thirdparty/freetype2/src/base/ftotval.c index 007576ce6..503126f4b 100644 --- a/src/thirdparty/freetype2/src/base/ftotval.c +++ b/src/thirdparty/freetype2/src/base/ftotval.c @@ -4,7 +4,7 @@ * * FreeType API for validating OpenType tables (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -15,12 +15,11 @@ * */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_OPENTYPE_VALIDATE_H -#include FT_OPENTYPE_VALIDATE_H +#include +#include +#include /* documentation is in ftotval.h */ diff --git a/src/thirdparty/freetype2/src/base/ftoutln.c b/src/thirdparty/freetype2/src/base/ftoutln.c index 0e2ba3475..8a15b03eb 100644 --- a/src/thirdparty/freetype2/src/base/ftoutln.c +++ b/src/thirdparty/freetype2/src/base/ftoutln.c @@ -4,7 +4,7 @@ * * FreeType outline management (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_OUTLINE_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H -#include FT_TRIGONOMETRY_H +#include +#include +#include +#include +#include /************************************************************************** @@ -54,12 +53,14 @@ FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; FT_Error error; FT_Int n; /* index of contour in outline */ - FT_UInt first; /* index of first point in contour */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + FT_Int tag; /* current point's state */ FT_Int shift; @@ -74,18 +75,17 @@ shift = func_interface->shift; delta = func_interface->delta; - first = 0; + last = -1; for ( n = 0; n < outline->n_contours; n++ ) { - FT_Int last; /* index of last point in contour */ + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); - - FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); - - last = outline->contours[n]; - if ( last < 0 ) + first = last + 1; + last = outline->contours[n]; + if ( last < first ) goto Invalid_Outline; + limit = outline->points + last; v_start = outline->points[first]; @@ -131,7 +131,7 @@ } FT_TRACE5(( " move to (%.2f, %.2f)\n", - v_start.x / 64.0, v_start.y / 64.0 )); + (double)v_start.x / 64, (double)v_start.y / 64 )); error = func_interface->move_to( &v_start, user ); if ( error ) goto Exit; @@ -153,7 +153,7 @@ vec.y = SCALED( point->y ); FT_TRACE5(( " line to (%.2f, %.2f)\n", - vec.x / 64.0, vec.y / 64.0 )); + (double)vec.x / 64, (double)vec.y / 64 )); error = func_interface->line_to( &vec, user ); if ( error ) goto Exit; @@ -182,8 +182,10 @@ { FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", - vec.x / 64.0, vec.y / 64.0, - v_control.x / 64.0, v_control.y / 64.0 )); + (double)vec.x / 64, + (double)vec.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); error = func_interface->conic_to( &v_control, &vec, user ); if ( error ) goto Exit; @@ -198,8 +200,10 @@ FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", - v_middle.x / 64.0, v_middle.y / 64.0, - v_control.x / 64.0, v_control.y / 64.0 )); + (double)v_middle.x / 64, + (double)v_middle.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); error = func_interface->conic_to( &v_control, &v_middle, user ); if ( error ) goto Exit; @@ -210,8 +214,10 @@ FT_TRACE5(( " conic to (%.2f, %.2f)" " with control (%.2f, %.2f)\n", - v_start.x / 64.0, v_start.y / 64.0, - v_control.x / 64.0, v_control.y / 64.0 )); + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)v_control.x / 64, + (double)v_control.y / 64 )); error = func_interface->conic_to( &v_control, &v_start, user ); goto Close; @@ -243,9 +249,12 @@ FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", - vec.x / 64.0, vec.y / 64.0, - vec1.x / 64.0, vec1.y / 64.0, - vec2.x / 64.0, vec2.y / 64.0 )); + (double)vec.x / 64, + (double)vec.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; @@ -254,9 +263,12 @@ FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", - v_start.x / 64.0, v_start.y / 64.0, - vec1.x / 64.0, vec1.y / 64.0, - vec2.x / 64.0, vec2.y / 64.0 )); + (double)v_start.x / 64, + (double)v_start.y / 64, + (double)vec1.x / 64, + (double)vec1.y / 64, + (double)vec2.x / 64, + (double)vec2.y / 64 )); error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); goto Close; } @@ -265,17 +277,15 @@ /* close the contour with a line segment */ FT_TRACE5(( " line to (%.2f, %.2f)\n", - v_start.x / 64.0, v_start.y / 64.0 )); + (double)v_start.x / 64, (double)v_start.y / 64 )); error = func_interface->line_to( &v_start, user ); Close: if ( error ) goto Exit; - - first = (FT_UInt)last + 1; } - FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); + FT_TRACE5(( "FT_Outline_Decompose: Done\n" )); return FT_Err_Ok; Invalid_Outline: @@ -322,8 +332,8 @@ FT_NEW_ARRAY( anoutline->contours, numContours ) ) goto Fail; - anoutline->n_points = (FT_Short)numPoints; - anoutline->n_contours = (FT_Short)numContours; + anoutline->n_points = (FT_UShort)numPoints; + anoutline->n_contours = (FT_UShort)numContours; anoutline->flags |= FT_OUTLINE_OWNER; return FT_Err_Ok; @@ -349,15 +359,17 @@ FT_Int n; + FT_TRACE5(( "FT_Outline_Check: contours = %d, points = %d\n", + n_contours, n_points )); /* empty glyph? */ if ( n_points == 0 && n_contours == 0 ) return FT_Err_Ok; /* check point and contour counts */ - if ( n_points <= 0 || n_contours <= 0 ) + if ( n_points == 0 || n_contours == 0 ) goto Bad; - end0 = end = -1; + end0 = -1; for ( n = 0; n < n_contours; n++ ) { end = outline->contours[n]; @@ -369,7 +381,7 @@ end0 = end; } - if ( end != n_points - 1 ) + if ( end0 != n_points - 1 ) goto Bad; /* XXX: check the tags array */ @@ -377,7 +389,7 @@ } Bad: - return FT_THROW( Invalid_Argument ); + return FT_THROW( Invalid_Outline ); } @@ -539,10 +551,12 @@ if ( !outline ) return; - first = 0; - + last = -1; for ( n = 0; n < outline->n_contours; n++ ) { + /* keep the first contour point as is and swap points around it */ + /* to guarantee that the cubic arches stay valid after reverse */ + first = last + 2; last = outline->contours[n]; /* reverse point table */ @@ -564,13 +578,13 @@ /* reverse tags table */ { - char* p = outline->tags + first; - char* q = outline->tags + last; + FT_Byte* p = outline->tags + first; + FT_Byte* q = outline->tags + last; while ( p < q ) { - char swap; + FT_Byte swap; swap = *p; @@ -580,8 +594,6 @@ q--; } } - - first = last + 1; } outline->flags ^= FT_OUTLINE_REVERSE_FILL; @@ -711,7 +723,7 @@ FT_Vector* limit; - if ( !outline || !matrix ) + if ( !outline || !matrix || !outline->points ) return; vec = outline->points; @@ -930,7 +942,7 @@ points = outline->points; - first = 0; + last = -1; for ( c = 0; c < outline->n_contours; c++ ) { FT_Vector in, out, anchor, shift; @@ -938,8 +950,9 @@ FT_Int i, j, k; - l_in = 0; - last = outline->contours[c]; + first = last + 1; + last = outline->contours[c]; + l_in = 0; /* pacify compiler */ in.x = in.y = anchor.x = anchor.y = 0; @@ -1026,8 +1039,6 @@ in = out; l_in = l_out; } - - first = last + 1; } return FT_Err_Ok; @@ -1043,7 +1054,7 @@ FT_Int xshift, yshift; FT_Vector* points; FT_Vector v_prev, v_cur; - FT_Int c, n, first; + FT_Int c, n, first, last; FT_Pos area = 0; @@ -1061,6 +1072,11 @@ if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) return FT_ORIENTATION_NONE; + /* Reject values large outlines. */ + if ( cbox.xMin < -0x1000000L || cbox.yMin < -0x1000000L || + cbox.xMax > 0x1000000L || cbox.yMax > 0x1000000L ) + return FT_ORIENTATION_NONE; + xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | FT_ABS( cbox.xMin ) ) ) - 14; xshift = FT_MAX( xshift, 0 ); @@ -1070,11 +1086,11 @@ points = outline->points; - first = 0; + last = -1; for ( c = 0; c < outline->n_contours; c++ ) { - FT_Int last = outline->contours[c]; - + first = last + 1; + last = outline->contours[c]; v_prev.x = points[last].x >> xshift; v_prev.y = points[last].y >> yshift; @@ -1090,8 +1106,6 @@ v_prev = v_cur; } - - first = last + 1; } if ( area > 0 ) diff --git a/src/thirdparty/freetype2/src/base/ftpatent.c b/src/thirdparty/freetype2/src/base/ftpatent.c index 020f4646e..664bc34de 100644 --- a/src/thirdparty/freetype2/src/base/ftpatent.c +++ b/src/thirdparty/freetype2/src/base/ftpatent.c @@ -5,7 +5,7 @@ * FreeType API for checking patented TrueType bytecode instructions * (body). Obsolete, retained for backward compatibility. * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ * */ -#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 +#include +#include +#include +#include +#include +#include /* documentation is in freetype.h */ diff --git a/src/thirdparty/freetype2/src/base/ftpfr.c b/src/thirdparty/freetype2/src/base/ftpfr.c index aeff1db8b..f2af1fecc 100644 --- a/src/thirdparty/freetype2/src/base/ftpfr.c +++ b/src/thirdparty/freetype2/src/base/ftpfr.c @@ -4,7 +4,7 @@ * * FreeType API for accessing PFR-specific data (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -15,11 +15,10 @@ * */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_PFR_H +#include +#include /* check the format */ diff --git a/src/thirdparty/freetype2/src/base/ftpsprop.c b/src/thirdparty/freetype2/src/base/ftpsprop.c index 52b9d453a..0631cd63f 100644 --- a/src/thirdparty/freetype2/src/base/ftpsprop.c +++ b/src/thirdparty/freetype2/src/base/ftpsprop.c @@ -5,7 +5,7 @@ * Get and set properties of PostScript drivers (body). * See `ftdriver.h' for available properties. * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,12 +17,11 @@ */ -#include -#include FT_DRIVER_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_POSTSCRIPT_PROPS_H +#include +#include +#include +#include +#include /************************************************************************** @@ -165,9 +164,9 @@ driver->hinting_engine = *hinting_engine; else error = FT_ERR( Unimplemented_Feature ); - - return error; } + + return error; } else if ( !ft_strcmp( property_name, "no-stem-darkening" ) ) @@ -221,7 +220,7 @@ return error; } - FT_TRACE0(( "ps_property_set: missing property `%s'\n", + FT_TRACE2(( "ps_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -276,7 +275,7 @@ return error; } - FT_TRACE0(( "ps_property_get: missing property `%s'\n", + FT_TRACE2(( "ps_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } diff --git a/src/thirdparty/freetype2/src/base/ftrfork.c b/src/thirdparty/freetype2/src/base/ftrfork.c index 73b7eb0de..1e241f4f9 100644 --- a/src/thirdparty/freetype2/src/base/ftrfork.c +++ b/src/thirdparty/freetype2/src/base/ftrfork.c @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Masatake YAMATO and Redhat K.K. * * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are @@ -24,10 +24,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_RFORK_H +#include +#include +#include #include "ftbase.h" @@ -168,16 +167,11 @@ } - static int - ft_raccess_sort_ref_by_id( FT_RFork_Ref* a, - FT_RFork_Ref* b ) + FT_COMPARE_DEF( int ) + ft_raccess_sort_ref_by_id( const void* a, + const void* b ) { - if ( a->res_id < b->res_id ) - return -1; - else if ( a->res_id > b->res_id ) - return 1; - else - return 0; + return ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id; } @@ -240,7 +234,7 @@ (char)( 0xFF & ( tag_internal >> 16 ) ), (char)( 0xFF & ( tag_internal >> 8 ) ), (char)( 0xFF & ( tag_internal >> 0 ) ) )); - FT_TRACE3(( " : subcount=%d, suboffset=0x%04x\n", + FT_TRACE3(( " : subcount=%d, suboffset=0x%04lx\n", subcnt, rpos )); if ( tag_internal == tag ) @@ -257,7 +251,7 @@ if ( error ) return error; - if ( FT_NEW_ARRAY( ref, *count ) ) + if ( FT_QNEW_ARRAY( ref, *count ) ) return error; for ( j = 0; j < *count; j++ ) @@ -275,18 +269,12 @@ * According to Inside Macintosh: More Macintosh Toolbox, * "Resource IDs" (1-46), there are some reserved IDs. * However, FreeType2 is not a font synthesizer, no need - * to check the acceptable resource ID. + * to check the acceptable resource ID or its attributes. */ - if ( temp < 0 ) - { - error = FT_THROW( Invalid_Table ); - goto Exit; - } - ref[j].offset = temp & 0xFFFFFFL; FT_TRACE3(( " [%d]:" - " resource_id=0x%04x, offset=0x%08x\n", + " resource_id=0x%04x, offset=0x%08lx\n", j, (FT_UShort)ref[j].res_id, ref[j].offset )); } @@ -295,18 +283,17 @@ ft_qsort( ref, (size_t)*count, sizeof ( FT_RFork_Ref ), - ( int(*)(const void*, - const void*) )ft_raccess_sort_ref_by_id ); + ft_raccess_sort_ref_by_id ); FT_TRACE3(( " -- sort resources by their ids --\n" )); for ( j = 0; j < *count; j++ ) FT_TRACE3(( " [%d]:" - " resource_id=0x%04x, offset=0x%08x\n", + " resource_id=0x%04x, offset=0x%08lx\n", j, ref[j].res_id, ref[j].offset )); } - if ( FT_NEW_ARRAY( offsets_internal, *count ) ) + if ( FT_QNEW_ARRAY( offsets_internal, *count ) ) goto Exit; /* XXX: duplicated reference ID, @@ -409,17 +396,17 @@ FT_Long *result_offset ); - CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table, - ft_raccess_guess_rec) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double, apple_double) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single, apple_single) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs, darwin_newvfs) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus, darwin_hfsplus) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat, vfat) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap, linux_cap) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double, linux_double) - CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk, linux_netatalk) + CONST_FT_RFORK_RULE_ARRAY_BEGIN( ft_raccess_guess_table, + ft_raccess_guess_rec ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_double, apple_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( apple_single, apple_single ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_ufs_export, darwin_ufs_export ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_newvfs, darwin_newvfs ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( darwin_hfsplus, darwin_hfsplus ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( vfat, vfat ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_cap, linux_cap ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_double, linux_double ) + CONST_FT_RFORK_RULE_ARRAY_ENTRY( linux_netatalk, linux_netatalk ) CONST_FT_RFORK_RULE_ARRAY_END @@ -609,7 +596,7 @@ if ( base_file_len + 6 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( newpath, base_file_len + 6 ) ) + if ( FT_QALLOC( newpath, base_file_len + 6 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); @@ -645,7 +632,7 @@ if ( base_file_len + 18 > FT_INT_MAX ) return FT_THROW( Array_Too_Large ); - if ( FT_ALLOC( newpath, base_file_len + 18 ) ) + if ( FT_QALLOC( newpath, base_file_len + 18 ) ) return error; FT_MEM_COPY( newpath, base_file_name, base_file_len ); @@ -875,13 +862,11 @@ const char* tmp; const char* slash; size_t new_length; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; new_length = ft_strlen( original_name ) + ft_strlen( insertion ); - if ( FT_ALLOC( new_name, new_length + 1 ) ) + if ( FT_QALLOC( new_name, new_length + 1 ) ) return NULL; tmp = ft_strrchr( original_name, '/' ); diff --git a/src/thirdparty/freetype2/src/base/ftsnames.c b/src/thirdparty/freetype2/src/base/ftsnames.c index 7ab3fe3cf..34a67a148 100644 --- a/src/thirdparty/freetype2/src/base/ftsnames.c +++ b/src/thirdparty/freetype2/src/base/ftsnames.c @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,12 +19,11 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include FT_SFNT_NAMES_H -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_INTERNAL_STREAM_H +#include +#include +#include #ifdef TT_CONFIG_OPTION_SFNT_NAMES @@ -66,7 +65,7 @@ FT_Stream stream = face->stream; - if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || FT_STREAM_SEEK( entry->stringOffset ) || FT_STREAM_READ( entry->string, entry->stringLength ) ) { @@ -122,7 +121,7 @@ FT_Stream stream = face->stream; - if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) || + if ( FT_QNEW_ARRAY ( entry->string, entry->stringLength ) || FT_STREAM_SEEK( entry->stringOffset ) || FT_STREAM_READ( entry->string, entry->stringLength ) ) { diff --git a/src/thirdparty/freetype2/src/base/ftstream.c b/src/thirdparty/freetype2/src/base/ftstream.c index 4b0890d7f..c04a0506d 100644 --- a/src/thirdparty/freetype2/src/base/ftstream.c +++ b/src/thirdparty/freetype2/src/base/ftstream.c @@ -4,7 +4,7 @@ * * I/O stream support (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,9 +16,8 @@ */ -#include -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H +#include +#include /************************************************************************** @@ -62,7 +61,7 @@ if ( stream->read ) { - if ( stream->read( stream, pos, 0, 0 ) ) + if ( stream->read( stream, pos, NULL, 0 ) ) { FT_ERROR(( "FT_Stream_Seek:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", @@ -142,7 +141,9 @@ if ( read_bytes > count ) read_bytes = count; - FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + pos, read_bytes ); } stream->pos = pos + read_bytes; @@ -179,7 +180,9 @@ if ( read_bytes > count ) read_bytes = count; - FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); + /* Allow "reading" zero bytes without UB even if buffer is NULL */ + if ( count ) + FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes ); } stream->pos += read_bytes; @@ -239,7 +242,7 @@ FT_ULong read_bytes; - FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count )); + FT_TRACE7(( "FT_Stream_EnterFrame: %lu bytes\n", count )); /* check for nested frame access */ FT_ASSERT( stream && stream->cursor == 0 ); @@ -262,7 +265,7 @@ } #ifdef FT_DEBUG_MEMORY - /* assume _ft_debug_file and _ft_debug_lineno are already set */ + /* assume `ft_debug_file_` and `ft_debug_lineno_` are already set */ stream->base = (unsigned char*)ft_mem_qalloc( memory, (FT_Long)count, &error ); @@ -286,7 +289,7 @@ } stream->cursor = stream->base; - stream->limit = stream->cursor + count; + stream->limit = FT_OFFSET( stream->cursor, count ); stream->pos += read_bytes; } else @@ -348,27 +351,27 @@ } - FT_BASE_DEF( FT_Char ) - FT_Stream_GetChar( FT_Stream stream ) + FT_BASE_DEF( FT_Byte ) + FT_Stream_GetByte( FT_Stream stream ) { - FT_Char result; + FT_Byte result; FT_ASSERT( stream && stream->cursor ); result = 0; if ( stream->cursor < stream->limit ) - result = (FT_Char)*stream->cursor++; + result = *stream->cursor++; return result; } - FT_BASE_DEF( FT_UShort ) + FT_BASE_DEF( FT_UInt16 ) FT_Stream_GetUShort( FT_Stream stream ) { FT_Byte* p; - FT_UShort result; + FT_UInt16 result; FT_ASSERT( stream && stream->cursor ); @@ -383,11 +386,11 @@ } - FT_BASE_DEF( FT_UShort ) + FT_BASE_DEF( FT_UInt16 ) FT_Stream_GetUShortLE( FT_Stream stream ) { FT_Byte* p; - FT_UShort result; + FT_UInt16 result; FT_ASSERT( stream && stream->cursor ); @@ -402,11 +405,11 @@ } - FT_BASE_DEF( FT_ULong ) + FT_BASE_DEF( FT_UInt32 ) FT_Stream_GetUOffset( FT_Stream stream ) { FT_Byte* p; - FT_ULong result; + FT_UInt32 result; FT_ASSERT( stream && stream->cursor ); @@ -420,11 +423,11 @@ } - FT_BASE_DEF( FT_ULong ) + FT_BASE_DEF( FT_UInt32 ) FT_Stream_GetULong( FT_Stream stream ) { FT_Byte* p; - FT_ULong result; + FT_UInt32 result; FT_ASSERT( stream && stream->cursor ); @@ -438,11 +441,11 @@ } - FT_BASE_DEF( FT_ULong ) + FT_BASE_DEF( FT_UInt32 ) FT_Stream_GetULongLE( FT_Stream stream ) { FT_Byte* p; - FT_ULong result; + FT_UInt32 result; FT_ASSERT( stream && stream->cursor ); @@ -456,8 +459,8 @@ } - FT_BASE_DEF( FT_Char ) - FT_Stream_ReadChar( FT_Stream stream, + FT_BASE_DEF( FT_Byte ) + FT_Stream_ReadByte( FT_Stream stream, FT_Error* error ) { FT_Byte result = 0; @@ -465,47 +468,46 @@ FT_ASSERT( stream ); - *error = FT_Err_Ok; - - if ( stream->read ) + if ( stream->pos < stream->size ) { - if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) - goto Fail; + if ( stream->read ) + { + if ( stream->read( stream, stream->pos, &result, 1L ) != 1L ) + goto Fail; + } + else + result = stream->base[stream->pos]; } else - { - if ( stream->pos < stream->size ) - result = stream->base[stream->pos]; - else - goto Fail; - } + goto Fail; + stream->pos++; - return (FT_Char)result; + *error = FT_Err_Ok; + + return result; Fail: *error = FT_THROW( Invalid_Stream_Operation ); - FT_ERROR(( "FT_Stream_ReadChar:" + FT_ERROR(( "FT_Stream_ReadByte:" " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } - FT_BASE_DEF( FT_UShort ) + FT_BASE_DEF( FT_UInt16 ) FT_Stream_ReadUShort( FT_Stream stream, FT_Error* error ) { FT_Byte reads[2]; - FT_Byte* p = 0; - FT_UShort result = 0; + FT_Byte* p; + FT_UInt16 result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 1 < stream->size ) { if ( stream->read ) @@ -526,6 +528,8 @@ stream->pos += 2; + *error = FT_Err_Ok; + return result; Fail: @@ -534,23 +538,21 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } - FT_BASE_DEF( FT_UShort ) + FT_BASE_DEF( FT_UInt16 ) FT_Stream_ReadUShortLE( FT_Stream stream, FT_Error* error ) { FT_Byte reads[2]; - FT_Byte* p = 0; - FT_UShort result = 0; + FT_Byte* p; + FT_UInt16 result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 1 < stream->size ) { if ( stream->read ) @@ -571,6 +573,8 @@ stream->pos += 2; + *error = FT_Err_Ok; + return result; Fail: @@ -579,7 +583,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -588,14 +592,12 @@ FT_Error* error ) { FT_Byte reads[3]; - FT_Byte* p = 0; + FT_Byte* p; FT_ULong result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 2 < stream->size ) { if ( stream->read ) @@ -616,6 +618,8 @@ stream->pos += 3; + *error = FT_Err_Ok; + return result; Fail: @@ -624,23 +628,21 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } - FT_BASE_DEF( FT_ULong ) + FT_BASE_DEF( FT_UInt32 ) FT_Stream_ReadULong( FT_Stream stream, FT_Error* error ) { FT_Byte reads[4]; - FT_Byte* p = 0; - FT_ULong result = 0; + FT_Byte* p; + FT_UInt32 result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 3 < stream->size ) { if ( stream->read ) @@ -661,6 +663,8 @@ stream->pos += 4; + *error = FT_Err_Ok; + return result; Fail: @@ -669,23 +673,21 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } - FT_BASE_DEF( FT_ULong ) + FT_BASE_DEF( FT_UInt32 ) FT_Stream_ReadULongLE( FT_Stream stream, FT_Error* error ) { FT_Byte reads[4]; - FT_Byte* p = 0; - FT_ULong result = 0; + FT_Byte* p; + FT_UInt32 result = 0; FT_ASSERT( stream ); - *error = FT_Err_Ok; - if ( stream->pos + 3 < stream->size ) { if ( stream->read ) @@ -706,6 +708,8 @@ stream->pos += 4; + *error = FT_Err_Ok; + return result; Fail: @@ -714,7 +718,7 @@ " invalid i/o; pos = 0x%lx, size = 0x%lx\n", stream->pos, stream->size )); - return 0; + return result; } @@ -759,10 +763,10 @@ case ft_frame_bytes: /* read a byte sequence */ case ft_frame_skip: /* skip some bytes */ { - FT_UInt len = fields->size; + FT_Offset len = fields->size; - if ( cursor + len > stream->limit ) + if ( len > (FT_Offset)( stream->limit - cursor ) ) { error = FT_THROW( Invalid_Stream_Operation ); goto Exit; @@ -826,7 +830,7 @@ goto Exit; } - /* now, compute the signed value is necessary */ + /* now, compute the signed value if necessary */ if ( fields->value & FT_FRAME_OP_SIGNED ) value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift ); diff --git a/src/thirdparty/freetype2/src/base/ftstroke.c b/src/thirdparty/freetype2/src/base/ftstroke.c index 1b2c0f657..591f18eaa 100644 --- a/src/thirdparty/freetype2/src/base/ftstroke.c +++ b/src/thirdparty/freetype2/src/base/ftstroke.c @@ -4,7 +4,7 @@ * * FreeType path stroker (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ */ -#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 +#include +#include +#include +#include +#include +#include /* declare an extern to access `ft_outline_glyph_class' globally */ @@ -540,63 +539,52 @@ 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_Fixed coef; + FT_Vector a0, a1, a2, a3; + FT_Int i, arcs = 1; FT_Error error = FT_Err_Ok; - /* compute start point */ - FT_Vector_From_Polar( &a, radius, angle_start ); - a.x += center->x; - a.y += center->y; + /* number of cubic arcs to draw */ + while ( angle_diff > FT_ARC_CUBIC_ANGLE * arcs || + -angle_diff > FT_ARC_CUBIC_ANGLE * arcs ) + arcs++; - total = angle_diff; - angle = angle_start; - rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2; + /* control tangents */ + coef = FT_Tan( angle_diff / ( 4 * arcs ) ); + coef += coef / 3; - while ( total != 0 ) + /* compute start and first control point */ + FT_Vector_From_Polar( &a0, radius, angle_start ); + a1.x = FT_MulFix( -a0.y, coef ); + a1.y = FT_MulFix( a0.x, coef ); + + a0.x += center->x; + a0.y += center->y; + a1.x += a0.x; + a1.y += a0.y; + + for ( i = 1; i <= arcs; i++ ) { - step = total; - if ( step > FT_ARC_CUBIC_ANGLE ) - step = FT_ARC_CUBIC_ANGLE; + /* compute end and second control point */ + FT_Vector_From_Polar( &a3, radius, + angle_start + i * angle_diff / arcs ); + a2.x = FT_MulFix( a3.y, coef ); + a2.y = FT_MulFix( -a3.x, coef ); - 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; + a3.x += center->x; + a3.y += center->y; + a2.x += a3.x; + a2.y += a3.y; /* add cubic arc */ - error = ft_stroke_border_cubicto( border, &a2, &b2, &b ); + error = ft_stroke_border_cubicto( border, &a1, &a2, &a3 ); if ( error ) break; - /* process the rest of the arc ?? */ - a = b; - total -= step; - angle = next; + /* a0 = a3; */ + a1.x = a3.x - a2.x + a3.x; + a1.y = a3.y - a2.y + a3.y; } return error; @@ -723,7 +711,7 @@ { FT_UInt count = border->num_points; FT_Byte* read = border->tags; - FT_Byte* write = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* write = outline->tags + outline->n_points; for ( ; count > 0; count--, read++, write++ ) @@ -739,10 +727,10 @@ /* 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; + FT_UInt count = border->num_points; + FT_Byte* tags = border->tags; + FT_UShort* write = outline->contours + outline->n_contours; + FT_UShort idx = outline->n_points; for ( ; count > 0; count--, tags++, idx++ ) @@ -755,7 +743,7 @@ } } - outline->n_points += (short)border->num_points; + outline->n_points += (FT_UShort)border->num_points; FT_ASSERT( FT_Outline_Check( outline ) == 0 ); } @@ -934,55 +922,40 @@ error = ft_stroker_arcto( stroker, side ); } - else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + else { - /* add a square cap */ - FT_Vector delta, delta2; - FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); + /* add a square or butt cap */ + FT_Vector middle, delta; 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 ); + /* compute middle point and first angle point */ + FT_Vector_From_Polar( &middle, radius, angle ); + delta.x = side ? middle.y : -middle.y; + delta.y = side ? -middle.x : middle.x; - delta.x += stroker->center.x + delta2.x; - delta.y += stroker->center.y + delta2.y; + if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE ) + { + middle.x += stroker->center.x; + middle.y += stroker->center.y; + } + else /* FT_STROKER_LINECAP_BUTT */ + { + middle.x = stroker->center.x; + middle.y = stroker->center.y; + } + + delta.x += middle.x; + delta.y += middle.y; error = ft_stroke_border_lineto( border, &delta, FALSE ); 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, FALSE ); - } - else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT ) - { - /* add a butt ending */ - FT_Vector delta; - FT_Angle rotate = FT_SIDE_TO_ROTATE( side ); - FT_Fixed radius = stroker->radius; - FT_StrokeBorder border = stroker->borders + side; - - - FT_Vector_From_Polar( &delta, radius, angle + rotate ); - - delta.x += stroker->center.x; - delta.y += stroker->center.y; - - error = ft_stroke_border_lineto( border, &delta, FALSE ); - if ( error ) - goto Exit; - - FT_Vector_From_Polar( &delta, radius, angle - rotate ); - - delta.x += stroker->center.x; - delta.y += stroker->center.y; + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; error = ft_stroke_border_lineto( border, &delta, FALSE ); } @@ -1000,7 +973,8 @@ { FT_StrokeBorder border = stroker->borders + side; FT_Angle phi, theta, rotate; - FT_Fixed length, thcos; + FT_Fixed length; + FT_Vector sigma = { 0, 0 }; FT_Vector delta; FT_Error error = FT_Err_Ok; FT_Bool intersect; /* use intersection of lines? */ @@ -1019,10 +993,13 @@ else { /* compute minimum required length of lines */ - FT_Fixed min_length = ft_pos_abs( FT_MulFix( stroker->radius, - FT_Tan( theta ) ) ); + FT_Fixed min_length; + FT_Vector_Unit( &sigma, theta ); + min_length = + ft_pos_abs( FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); + intersect = FT_BOOL( min_length && stroker->line_length >= min_length && line_length >= min_length ); @@ -1040,13 +1017,11 @@ else { /* compute median angle */ - phi = stroker->angle_in + theta; + phi = stroker->angle_in + theta + rotate; - thcos = FT_Cos( theta ); + length = FT_DivFix( stroker->radius, sigma.x ); - length = FT_DivFix( stroker->radius, thcos ); - - FT_Vector_From_Polar( &delta, length, phi + rotate ); + FT_Vector_From_Polar( &delta, length, phi ); delta.x += stroker->center.x; delta.y += stroker->center.y; } @@ -1073,10 +1048,10 @@ else { /* this is a mitered (pointed) or beveled (truncated) corner */ - FT_Fixed sigma = 0, radius = stroker->radius; - FT_Angle theta = 0, phi = 0; - FT_Fixed thcos = 0; - FT_Bool bevel, fixed_bevel; + FT_Fixed radius = stroker->radius; + FT_Vector sigma = { 0, 0 }; + FT_Angle theta = 0, phi = 0; + FT_Bool bevel, fixed_bevel; rotate = FT_SIDE_TO_ROTATE( side ); @@ -1087,26 +1062,20 @@ fixed_bevel = FT_BOOL( stroker->line_join != FT_STROKER_LINEJOIN_MITER_VARIABLE ); + /* check miter limit first */ if ( !bevel ) { - theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ); + theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; - if ( theta == FT_ANGLE_PI ) - { - theta = rotate; - phi = stroker->angle_in; - } - else - { - theta /= 2; - phi = stroker->angle_in + theta + rotate; - } + if ( theta == FT_ANGLE_PI2 ) + theta = -rotate; - thcos = FT_Cos( theta ); - sigma = FT_MulFix( stroker->miter_limit, thcos ); + phi = stroker->angle_in + theta + rotate; + + FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); /* is miter limit exceeded? */ - if ( sigma < 0x10000L ) + if ( sigma.x < 0x10000L ) { /* don't create variable bevels for very small deviations; */ /* FT_Sin(x) = 0 for x <= 57 */ @@ -1133,36 +1102,34 @@ border->movable = FALSE; error = ft_stroke_border_lineto( border, &delta, FALSE ); } - else /* variable bevel */ + else /* variable bevel or clipped miter */ { /* the miter is truncated */ FT_Vector middle, delta; - FT_Fixed length; + FT_Fixed coef; - /* compute middle point */ + /* compute middle point and first angle point */ FT_Vector_From_Polar( &middle, FT_MulFix( radius, stroker->miter_limit ), phi ); + + coef = FT_DivFix( 0x10000L - sigma.x, sigma.y ); + delta.x = FT_MulFix( middle.y, coef ); + delta.y = FT_MulFix( -middle.x, coef ); + middle.x += stroker->center.x; middle.y += stroker->center.y; - - /* compute first angle point */ - length = FT_MulDiv( radius, 0x10000L - sigma, - ft_pos_abs( FT_Sin( theta ) ) ); - - FT_Vector_From_Polar( &delta, length, phi + rotate ); - delta.x += middle.x; - delta.y += middle.y; + delta.x += middle.x; + delta.y += middle.y; error = ft_stroke_border_lineto( border, &delta, FALSE ); if ( error ) goto Exit; /* compute second angle point */ - FT_Vector_From_Polar( &delta, length, phi - rotate ); - delta.x += middle.x; - delta.y += middle.y; + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; error = ft_stroke_border_lineto( border, &delta, FALSE ); if ( error ) @@ -1189,7 +1156,7 @@ FT_Vector delta; - length = FT_DivFix( stroker->radius, thcos ); + length = FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); FT_Vector_From_Polar( &delta, length, phi ); delta.x += stroker->center.x; @@ -1404,7 +1371,7 @@ arc[1] = *control; arc[2] = stroker->center; - while ( arc >= bez_stack ) + do { FT_Angle angle_in, angle_out; @@ -1557,12 +1524,15 @@ } } - arc -= 2; - stroker->angle_in = angle_out; - } - stroker->center = *to; + if ( arc == bez_stack ) + break; + arc -= 2; + } while ( 1 ); + + stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1609,7 +1579,7 @@ arc[2] = *control1; arc[3] = stroker->center; - while ( arc >= bez_stack ) + do { FT_Angle angle_in, angle_mid, angle_out; @@ -1773,12 +1743,15 @@ } } - arc -= 3; - stroker->angle_in = angle_out; - } - stroker->center = *to; + if ( arc == bez_stack ) + break; + arc -= 3; + } while ( 1 ); + + stroker->center = *to; + stroker->line_length = 0; Exit: return error; @@ -1931,13 +1904,9 @@ } 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 ) + if ( !FT_IS_SMALL( stroker->center.x - stroker->subpath_start.x ) || + !FT_IS_SMALL( stroker->center.y - stroker->subpath_start.y ) ) { error = FT_Stroker_LineTo( stroker, &stroker->subpath_start ); if ( error ) @@ -1946,29 +1915,11 @@ /* 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 */ - /* otherwise, the inside side is 1 */ - inside_side = ( turn < 0 ); - - error = ft_stroker_inside( stroker, - inside_side, - stroker->subpath_line_length ); - if ( error ) - goto Exit; - - /* process the outside side */ - error = ft_stroker_outside( stroker, - !inside_side, - stroker->subpath_line_length ); - if ( error ) - goto Exit; - } + error = ft_stroker_process_corner( stroker, + stroker->subpath_line_length ); + if ( error ) + goto Exit; /* then end our two subpaths */ ft_stroke_border_close( stroker->borders + 0, FALSE ); @@ -2103,12 +2054,14 @@ FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; FT_Error error; FT_Int n; /* index of contour in outline */ - FT_UInt first; /* index of first point in contour */ + FT_Int first; /* index of first point in contour */ + FT_Int last; /* index of last point in contour */ + FT_Int tag; /* current point's state */ @@ -2120,22 +2073,17 @@ FT_Stroker_Rewind( stroker ); - first = 0; - + last = -1; for ( n = 0; n < outline->n_contours; n++ ) { - FT_UInt last; /* index of last point in contour */ - - - last = (FT_UInt)outline->contours[n]; - limit = outline->points + last; + first = last + 1; + last = outline->contours[n]; /* skip empty points; we don't stroke these */ if ( last <= first ) - { - first = last + 1; continue; - } + + limit = outline->points + last; v_start = outline->points[first]; v_last = outline->points[last]; @@ -2284,8 +2232,6 @@ if ( error ) goto Exit; } - - first = last + 1; } return FT_Err_Ok; diff --git a/src/thirdparty/freetype2/src/base/ftsynth.c b/src/thirdparty/freetype2/src/base/ftsynth.c index f87ed65e7..08bc17422 100644 --- a/src/thirdparty/freetype2/src/base/ftsynth.c +++ b/src/thirdparty/freetype2/src/base/ftsynth.c @@ -4,7 +4,7 @@ * * FreeType synthesizing code for emboldening and slanting (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_SYNTHESIS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_OUTLINE_H -#include FT_BITMAP_H +#include +#include +#include +#include +#include /************************************************************************** @@ -46,6 +45,18 @@ FT_EXPORT_DEF( void ) FT_GlyphSlot_Oblique( FT_GlyphSlot slot ) + { + /* Value '0x0366A' corresponds to a shear angle of about 12 degrees. */ + FT_GlyphSlot_Slant( slot, 0x0366A, 0 ); + } + + + /* documentation is in ftsynth.h */ + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_Slant( FT_GlyphSlot slot, + FT_Fixed xslant, + FT_Fixed yslant ) { FT_Matrix transform; FT_Outline* outline; @@ -62,13 +73,11 @@ /* we don't touch the advance width */ - /* For italic, simply apply a shear transform, with an angle */ - /* of about 12 degrees. */ - + /* For italic, simply apply a shear transform */ transform.xx = 0x10000L; - transform.yx = 0x00000L; + transform.yx = -yslant; - transform.xy = 0x0366AL; + transform.xy = xslant; transform.yy = 0x10000L; FT_Outline_Transform( outline, &transform ); @@ -88,9 +97,18 @@ FT_EXPORT_DEF( void ) FT_GlyphSlot_Embolden( FT_GlyphSlot slot ) + { + FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA ); + } + + + FT_EXPORT_DEF( void ) + FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot, + FT_Fixed xdelta, + FT_Fixed ydelta ) { FT_Library library; - FT_Face face; + FT_Size size; FT_Error error; FT_Pos xstr, ystr; @@ -99,16 +117,15 @@ return; library = slot->library; - face = slot->face; + size = slot->face->size; 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; + /* express deltas in pixels in 26.6 format */ + xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024; + ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024; if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); @@ -124,13 +141,13 @@ /* * XXX: overflow check for 16-bit system, for compatibility * with FT_GlyphSlot_Embolden() since FreeType 2.1.10. - * unfortunately, this function return no informations + * unfortunately, this function returns no information * about the cause of error. */ if ( ( ystr >> 6 ) > FT_INT_MAX || ( ystr >> 6 ) < FT_INT_MIN ) { FT_TRACE1(( "FT_GlyphSlot_Embolden:" )); - FT_TRACE1(( "too strong emboldening parameter ystr=%d\n", ystr )); + FT_TRACE1(( "too strong emboldening parameter ystr=%ld\n", ystr )); return; } error = FT_GlyphSlot_Own_Bitmap( slot ); diff --git a/src/thirdparty/freetype2/src/base/ftsystem.c b/src/thirdparty/freetype2/src/base/ftsystem.c index f92b3a03d..186119d55 100644 --- a/src/thirdparty/freetype2/src/base/ftsystem.c +++ b/src/thirdparty/freetype2/src/base/ftsystem.c @@ -4,7 +4,7 @@ * * ANSI-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,11 +27,11 @@ #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 +#include +#include +#include +#include +#include /************************************************************************** @@ -206,7 +206,7 @@ * The number of bytes to read from the stream. * * @Return: - * The number of bytes actually read. If `count' is zero (this is, + * The number of bytes actually read. If `count' is zero (that is, * the function is used for seeking), a non-zero return value * indicates an error. */ @@ -219,7 +219,7 @@ FT_FILE* file; - if ( !count && offset > stream->size ) + if ( offset > stream->size && !count ) return 1; file = STREAM_FILE( stream ); @@ -227,6 +227,11 @@ if ( stream->pos != offset ) ft_fseek( file, (long)offset, SEEK_SET ); + /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */ + /* which is undefined behaviour. */ + if ( !count ) + return 0; + return (unsigned long)ft_fread( buffer, 1, count, file ); } @@ -275,7 +280,7 @@ stream->close = ft_ansi_stream_close; FT_TRACE1(( "FT_Stream_Open:" )); - FT_TRACE1(( " opened `%s' (%d bytes) successfully\n", + FT_TRACE1(( " opened `%s' (%lu bytes) successfully\n", filepathname, stream->size )); return FT_Err_Ok; diff --git a/src/thirdparty/freetype2/src/base/fttrigon.c b/src/thirdparty/freetype2/src/base/fttrigon.c index 38721977c..29eff639c 100644 --- a/src/thirdparty/freetype2/src/base/fttrigon.c +++ b/src/thirdparty/freetype2/src/base/fttrigon.c @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (body). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -29,10 +29,9 @@ * */ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_CALC_H -#include FT_TRIGONOMETRY_H +#include +#include +#include /* the Cordic shrink factor 0.858785336480436 * 2^32 */ @@ -54,7 +53,7 @@ }; -#ifdef FT_LONG64 +#ifdef FT_INT64 /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed @@ -77,7 +76,7 @@ return s < 0 ? -val : val; } -#else /* !FT_LONG64 */ +#else /* !FT_INT64 */ /* multiply a given value by the CORDIC shrink factor */ static FT_Fixed @@ -126,7 +125,7 @@ return s < 0 ? -val : val; } -#endif /* !FT_LONG64 */ +#endif /* !FT_INT64 */ /* undefined and never called for zero vector */ diff --git a/src/thirdparty/freetype2/src/base/fttype1.c b/src/thirdparty/freetype2/src/base/fttype1.c index 26d4f1c3a..77978df67 100644 --- a/src/thirdparty/freetype2/src/base/fttype1.c +++ b/src/thirdparty/freetype2/src/base/fttype1.c @@ -4,7 +4,7 @@ * * FreeType utility file for PS names support (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_SERVICE_H -#include FT_SERVICE_POSTSCRIPT_INFO_H +#include +#include +#include +#include /* documentation is in t1tables.h */ diff --git a/src/thirdparty/freetype2/src/base/ftutil.c b/src/thirdparty/freetype2/src/base/ftutil.c index 92bd857e9..0b7382627 100644 --- a/src/thirdparty/freetype2/src/base/ftutil.c +++ b/src/thirdparty/freetype2/src/base/ftutil.c @@ -4,7 +4,7 @@ * * FreeType utility file for memory and list management (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_OBJECTS_H -#include FT_LIST_H +#include +#include +#include +#include /************************************************************************** diff --git a/src/thirdparty/freetype2/src/base/ftver.rc b/src/thirdparty/freetype2/src/base/ftver.rc index 135449742..25bbeaf3c 100644 --- a/src/thirdparty/freetype2/src/base/ftver.rc +++ b/src/thirdparty/freetype2/src/base/ftver.rc @@ -4,7 +4,7 @@ /* */ /* FreeType VERSIONINFO resource for Windows DLLs. */ /* */ -/* Copyright (C) 2018-2019 by */ +/* Copyright (C) 2018-2025 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -18,8 +18,8 @@ #include -#define FT_VERSION 2,10,1,0 -#define FT_VERSION_STR "2.10.1" +#define FT_VERSION 2,14,1,0 +#define FT_VERSION_STR "2.14.1" VS_VERSION_INFO VERSIONINFO FILEVERSION FT_VERSION @@ -38,14 +38,14 @@ FILETYPE VFT_STATIC_LIB BEGIN BLOCK "StringFileInfo" BEGIN - BLOCK "040904E4" + BLOCK "040904B0" BEGIN VALUE "CompanyName", "The FreeType Project" VALUE "FileDescription", "Font Rendering Library" VALUE "FileVersion", FT_VERSION_STR VALUE "ProductName", "FreeType" VALUE "ProductVersion", FT_VERSION_STR - VALUE "LegalCopyright", "\251 2018-2019 The FreeType Project www.freetype.org. All rights reserved." + VALUE "LegalCopyright", L"\x00A9 2000-2025 The FreeType Project freetype.org. All rights reserved." VALUE "InternalName", "freetype" VALUE "OriginalFilename", FT_FILENAME END @@ -56,6 +56,6 @@ BEGIN /* The following line should only be modified for localized versions. */ /* It consists of any number of WORD,WORD pairs, with each pair */ /* describing a "language,codepage" combination supported by the file. */ - VALUE "Translation", 0x409, 1252 + VALUE "Translation", 0x409, 1200 END END diff --git a/src/thirdparty/freetype2/src/base/ftwinfnt.c b/src/thirdparty/freetype2/src/base/ftwinfnt.c index 59daa7703..256b58005 100644 --- a/src/thirdparty/freetype2/src/base/ftwinfnt.c +++ b/src/thirdparty/freetype2/src/base/ftwinfnt.c @@ -4,7 +4,7 @@ * * FreeType API for accessing Windows FNT specific info (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_WINFONTS_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_WINFNT_H +#include +#include +#include +#include /* documentation is in ftwinfnt.h */ diff --git a/src/thirdparty/freetype2/src/bdf/README b/src/thirdparty/freetype2/src/bdf/README index 996ac2d2a..d7cb8c14e 100644 --- a/src/thirdparty/freetype2/src/bdf/README +++ b/src/thirdparty/freetype2/src/bdf/README @@ -13,7 +13,7 @@ This code implements a BDF driver for the FreeType library, following the Adobe Specification V 2.2. The specification of the BDF font format is available from Adobe's web site: - https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5005.BDF_Spec.pdf + https://adobe-type-tools.github.io/font-tech-notes/pdfs/5005.BDF_Spec.pdf Many good bitmap fonts in bdf format come with XFree86 (www.XFree86.org). They do not define vertical metrics, because the X Consortium BDF @@ -23,6 +23,10 @@ specification has removed them. Encodings ********* +[This section is out of date, retained for historical reasons. BDF + properties can be retrieved with `FT_Get_BDF_Property`, character set ID + values with `FT_Get_BDF_Charset_ID`.] + The variety of encodings that accompanies bdf fonts appears to encompass the small set defined in freetype.h. On the other hand, two properties that specify encoding and registry are usually defined in bdf fonts. diff --git a/src/thirdparty/freetype2/src/bdf/bdf.h b/src/thirdparty/freetype2/src/bdf/bdf.h index d9abd2378..85a9e4f2e 100644 --- a/src/thirdparty/freetype2/src/bdf/bdf.h +++ b/src/thirdparty/freetype2/src/bdf/bdf.h @@ -30,10 +30,9 @@ * 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 -#include FT_INTERNAL_HASH_H +#include +#include +#include FT_BEGIN_HEADER @@ -58,39 +57,13 @@ FT_BEGIN_HEADER */ -#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_CORRECT_METRICS 0x1000 /* Correct metrics when loading. */ +#define BDF_KEEP_COMMENTS 0x2000 /* Preserve the font comments. */ +#define BDF_KEEP_UNENCODED 0x4000 /* Keep the unencoded glyphs. */ -#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 ); +#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */ +#define BDF_MONOWIDTH 0x10 /* Font has mono width. */ +#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */ /************************************************************************** @@ -168,9 +141,6 @@ FT_BEGIN_HEADER unsigned long resolution_y; /* Font vertical resolution. */ int spacing; /* Font spacing value. */ - - unsigned short monowidth; /* Logical width for monowidth font. */ - unsigned long default_char; /* Encoding of the default glyph. */ long font_ascent; /* Font ascent. */ @@ -191,7 +161,7 @@ FT_BEGIN_HEADER char* comments; /* Font comments. */ unsigned long comments_len; /* Length of comment string. */ - void* internal; /* Internal data for the font. */ + FT_Hash internal; /* Internal data for the font. */ unsigned short bpp; /* Bits per pixel. */ @@ -234,16 +204,12 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) bdf_load_font( FT_Stream stream, FT_Memory memory, - bdf_options_t* opts, + unsigned long flags, 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 ); diff --git a/src/thirdparty/freetype2/src/bdf/bdfdrivr.c b/src/thirdparty/freetype2/src/bdf/bdfdrivr.c index 60eb93305..f57bb0007 100644 --- a/src/thirdparty/freetype2/src/bdf/bdfdrivr.c +++ b/src/thirdparty/freetype2/src/bdf/bdfdrivr.c @@ -24,16 +24,15 @@ 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_TRUETYPE_IDS_H +#include +#include +#include +#include +#include -#include FT_SERVICE_BDF_H -#include FT_SERVICE_FONT_FORMAT_H +#include +#include #include "bdf.h" #include "bdfdrivr.h" @@ -93,24 +92,18 @@ THE SOFTWARE. { BDF_CMap cmap = (BDF_CMap)bdfcmap; BDF_encoding_el* encodings = cmap->encodings; - FT_ULong min, max, mid; /* num_encodings */ FT_UShort result = 0; /* encodings->glyph */ + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; - min = 0; - max = cmap->num_encodings; - mid = ( min + max ) >> 1; while ( min < max ) { - FT_ULong code; + FT_ULong code = encodings[mid].enc; - if ( mid >= max || mid < min ) - mid = ( min + max ) >> 1; - - code = encodings[mid].enc; - if ( charcode == code ) { /* increase glyph index by 1 -- */ @@ -124,8 +117,10 @@ THE SOFTWARE. else min = mid + 1; - /* prediction in a continuous block */ + /* reasonable prediction in a continuous block */ mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; } return result; @@ -138,25 +133,19 @@ THE SOFTWARE. { BDF_CMap cmap = (BDF_CMap)bdfcmap; BDF_encoding_el* encodings = cmap->encodings; - FT_ULong min, max, mid; /* num_encodings */ FT_UShort result = 0; /* encodings->glyph */ FT_ULong charcode = *acharcode + 1; + FT_ULong min = 0; + FT_ULong max = cmap->num_encodings; + FT_ULong mid = ( min + max ) >> 1; - min = 0; - max = cmap->num_encodings; - mid = ( min + max ) >> 1; while ( min < max ) { - FT_ULong code; /* same as BDF_encoding_el.enc */ + FT_ULong code = encodings[mid].enc; - if ( mid >= max || mid < min ) - mid = ( min + max ) >> 1; - - code = encodings[mid].enc; - if ( charcode == code ) { /* increase glyph index by 1 -- */ @@ -172,6 +161,8 @@ THE SOFTWARE. /* prediction in a continuous block */ mid += charcode - code; + if ( mid >= max || mid < min ) + mid = ( min + max ) >> 1; } charcode = 0; @@ -184,7 +175,8 @@ THE SOFTWARE. Exit: if ( charcode > 0xFFFFFFFFUL ) { - FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%x > 32bit API" )); + FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API", + charcode )); *acharcode = 0; /* XXX: result should be changed to indicate an overflow error */ } @@ -276,7 +268,7 @@ THE SOFTWARE. char* s; - if ( FT_ALLOC( face->style_name, len ) ) + if ( FT_QALLOC( face->style_name, len ) ) return error; s = face->style_name; @@ -319,9 +311,9 @@ THE SOFTWARE. FT_CALLBACK_DEF( void ) - BDF_Face_Done( FT_Face bdfface ) /* BDF_Face */ + BDF_Face_Done( FT_Face face ) /* BDF_Face */ { - BDF_Face face = (BDF_Face)bdfface; + BDF_Face bdfface = (BDF_Face)face; FT_Memory memory; @@ -330,34 +322,33 @@ THE SOFTWARE. memory = FT_FACE_MEMORY( face ); - bdf_free_font( face->bdffont ); + bdf_free_font( bdfface->bdffont ); - FT_FREE( face->en_table ); + FT_FREE( bdfface->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->charset_encoding ); + FT_FREE( bdfface->charset_registry ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); - FT_FREE( bdfface->available_sizes ); + FT_FREE( face->available_sizes ); - FT_FREE( face->bdffont ); + FT_FREE( bdfface->bdffont ); } FT_CALLBACK_DEF( FT_Error ) BDF_Face_Init( FT_Stream stream, - FT_Face bdfface, /* BDF_Face */ + FT_Face face, /* BDF_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { - FT_Error error = FT_Err_Ok; - BDF_Face face = (BDF_Face)bdfface; - FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + BDF_Face bdfface = (BDF_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); bdf_font_t* font = NULL; - bdf_options_t options; FT_UNUSED( num_params ); FT_UNUSED( params ); @@ -368,12 +359,8 @@ THE SOFTWARE. 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 ); + error = bdf_load_font( stream, memory, + BDF_CORRECT_METRICS | BDF_KEEP_UNENCODED, &font ); if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) { FT_TRACE2(( " not a BDF file\n" )); @@ -383,7 +370,7 @@ THE SOFTWARE. goto Exit; /* we have a bdf font: let's construct the face object */ - face->bdffont = font; + bdfface->bdffont = font; /* BDF cannot have multiple faces in a single font file. * XXX: non-zero face_index is already invalid argument, but @@ -394,7 +381,7 @@ THE SOFTWARE. if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) { FT_ERROR(( "BDF_Face_Init: invalid face index\n" )); - BDF_Face_Done( bdfface ); + BDF_Face_Done( face ); return FT_THROW( Invalid_Argument ); } @@ -402,25 +389,33 @@ THE SOFTWARE. bdf_property_t* prop = NULL; - FT_TRACE4(( " number of glyphs: allocated %d (used %d)\n", + FT_TRACE4(( " number of glyphs: allocated %lu (used %lu)\n", font->glyphs_size, font->glyphs_used )); - FT_TRACE4(( " number of unencoded glyphs: allocated %d (used %d)\n", + FT_TRACE4(( " number of unencoded glyphs: allocated %lu (used %lu)\n", font->unencoded_size, font->unencoded_used )); - bdfface->num_faces = 1; - bdfface->face_index = 0; + face->num_faces = 1; + face->face_index = 0; - bdfface->face_flags |= FT_FACE_FLAG_FIXED_SIZES | - FT_FACE_FLAG_HORIZONTAL; + face->face_flags |= FT_FACE_FLAG_FIXED_SIZES | + FT_FACE_FLAG_HORIZONTAL; 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; + if ( prop && prop->value.atom ) + { + if ( prop->value.atom[0] == 'p' || prop->value.atom[0] == 'P' ) + font->spacing = BDF_PROPORTIONAL; + else if ( prop->value.atom[0] == 'm' || prop->value.atom[0] == 'M' ) + font->spacing = BDF_MONOWIDTH; + else if ( prop->value.atom[0] == 'c' || prop->value.atom[0] == 'C' ) + font->spacing = BDF_CHARCELL; + } + + if ( font->spacing == BDF_MONOWIDTH || + font->spacing == BDF_CHARCELL ) + face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ /* FZ XXX: I need a font to implement this */ @@ -428,44 +423,49 @@ THE SOFTWARE. prop = bdf_get_font_property( font, "FAMILY_NAME" ); if ( prop && prop->value.atom ) { - if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) ) + if ( FT_STRDUP( face->family_name, prop->value.atom ) ) goto Exit; } else - bdfface->family_name = NULL; + face->family_name = NULL; - if ( FT_SET_ERROR( bdf_interpret_style( face ) ) ) + if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) ) goto Exit; /* the number of glyphs (with one slot for the undefined glyph */ /* at position 0 and all unencoded glyphs) */ - bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); + face->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); - bdfface->num_fixed_sizes = 1; - if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) ) + face->num_fixed_sizes = 1; + if ( FT_NEW( face->available_sizes ) ) goto Exit; { - FT_Bitmap_Size* bsize = bdfface->available_sizes; - FT_Short resolution_x = 0, resolution_y = 0; + FT_Bitmap_Size* bsize = face->available_sizes; + FT_Short resolution_x = 0; + FT_Short resolution_y = 0; long value; - FT_ZERO( bsize ); + prop = bdf_get_font_property( font, "FONT_ASCENT" ); + if ( prop ) + font->font_ascent = prop->value.l; + else + font->font_ascent = font->bbx.ascent; + if ( font->font_ascent > 0x7FFF ) + font->font_ascent = 0x7FFF; + else if ( font->font_ascent < 0 ) + font->font_ascent = 0; - /* sanity checks */ - if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) - { - font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; - FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %d\n", - font->font_ascent )); - } - if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) - { - font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; - FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %d\n", - font->font_descent )); - } + prop = bdf_get_font_property( font, "FONT_DESCENT" ); + if ( prop ) + font->font_descent = prop->value.l; + else + font->font_descent = font->bbx.descent; + if ( font->font_descent > 0x7FFF ) + font->font_descent = 0x7FFF; + else if ( font->font_descent < 0 ) + font->font_descent = 0; bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); @@ -489,7 +489,7 @@ THE SOFTWARE. else { /* this is a heuristical value */ - bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); + bsize->width = ( bsize->height * 2 + 1 ) / 3; } prop = bdf_get_font_property( font, "POINT_SIZE" ); @@ -504,7 +504,7 @@ THE SOFTWARE. prop->value.l < -0x504C2L ) { bsize->size = 0x7FFF; - FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n", + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", bsize->size )); } else @@ -517,7 +517,7 @@ THE SOFTWARE. if ( font->point_size > 0x7FFF ) { bsize->size = 0x7FFF; - FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n", + FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", bsize->size )); } else @@ -539,7 +539,7 @@ THE SOFTWARE. if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) { bsize->y_ppem = 0x7FFF << 6; - FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %d\n", + FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n", bsize->y_ppem )); } else @@ -600,6 +600,12 @@ THE SOFTWARE. resolution_y ); else bsize->x_ppem = bsize->y_ppem; + + prop = bdf_get_font_property( font, "DEFAULT_CHAR" ); + if ( prop ) + font->default_char = prop->value.ul; + else + font->default_char = ~0UL; } /* encoding table */ @@ -608,23 +614,23 @@ THE SOFTWARE. unsigned long n; - if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) ) + if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) ) goto Exit; - face->default_glyph = 0; + bdfface->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_UShort)n; + (bdfface->en_table[n]).enc = cur[n].encoding; + FT_TRACE4(( " idx %lu, val 0x%lX\n", n, cur[n].encoding )); + (bdfface->en_table[n]).glyph = (FT_UShort)n; if ( cur[n].encoding == font->default_char ) { if ( n < FT_UINT_MAX ) - face->default_glyph = (FT_UInt)n; + bdfface->default_glyph = (FT_UInt)n; else FT_TRACE1(( "BDF_Face_Init:" - " idx %d is too large for this system\n", n )); + " idx %lu is too large for this system\n", n )); } } } @@ -649,27 +655,27 @@ THE SOFTWARE. const char* s; - if ( FT_STRDUP( face->charset_encoding, + if ( FT_STRDUP( bdfface->charset_encoding, charset_encoding->value.atom ) || - FT_STRDUP( face->charset_registry, + FT_STRDUP( bdfface->charset_registry, charset_registry->value.atom ) ) goto Exit; /* Uh, oh, compare first letters manually to avoid dependency */ /* on locales. */ - s = face->charset_registry; + s = bdfface->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" ) ) ) + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( bdfface->charset_encoding, "1" ) ) ) unicode_charmap = 1; /* another name for ASCII */ - else if ( !ft_strcmp( s, "646.1991" ) && - !ft_strcmp( face->charset_encoding, "IRV" ) ) + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( bdfface->charset_encoding, "IRV" ) ) unicode_charmap = 1; } @@ -677,7 +683,7 @@ THE SOFTWARE. FT_CharMapRec charmap; - charmap.face = FT_FACE( face ); + charmap.face = face; charmap.encoding = FT_ENCODING_NONE; /* initial platform/encoding should indicate unset status? */ charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; @@ -703,7 +709,7 @@ THE SOFTWARE. FT_CharMapRec charmap; - charmap.face = FT_FACE( face ); + charmap.face = face; charmap.encoding = FT_ENCODING_ADOBE_STANDARD; charmap.platform_id = TT_PLATFORM_ADOBE; charmap.encoding_id = TT_ADOBE_ID_STANDARD; @@ -711,8 +717,8 @@ THE SOFTWARE. error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); /* Select default charmap */ - if ( bdfface->num_charmaps ) - bdfface->charmap = bdfface->charmaps[0]; + if ( face->num_charmaps ) + face->charmap = face->charmaps[0]; } } } @@ -721,7 +727,7 @@ THE SOFTWARE. return error; Fail: - BDF_Face_Done( bdfface ); + BDF_Face_Done( face ); return FT_THROW( Unknown_File_Format ); } @@ -789,8 +795,8 @@ THE SOFTWARE. FT_UInt glyph_index, FT_Int32 load_flags ) { - BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); - FT_Face face = FT_FACE( bdf ); + FT_Face face = size->face; + BDF_Face bdf = (BDF_Face)face; FT_Error error = FT_Err_Ok; FT_Bitmap* bitmap = &slot->bitmap; bdf_glyph_t glyph; @@ -811,7 +817,7 @@ THE SOFTWARE. goto Exit; } - FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); + FT_TRACE1(( "BDF_Glyph_Load: glyph index %u\n", glyph_index )); /* index 0 is the undefined glyph */ if ( glyph_index == 0 ) @@ -825,7 +831,7 @@ THE SOFTWARE. bitmap->rows = glyph.bbx.height; bitmap->width = glyph.bbx.width; if ( glyph.bpr > FT_INT_MAX ) - FT_TRACE1(( "BDF_Glyph_Load: too large pitch %d is truncated\n", + FT_TRACE1(( "BDF_Glyph_Load: too large pitch %lu is truncated\n", glyph.bpr )); bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ @@ -878,17 +884,18 @@ THE SOFTWARE. * */ - static FT_Error - bdf_get_bdf_property( BDF_Face face, + FT_CALLBACK_DEF( FT_Error ) + bdf_get_bdf_property( FT_Face face, /* BDF_Face */ const char* prop_name, BDF_PropertyRec *aproperty ) { + BDF_Face bdfface = (BDF_Face)face; bdf_property_t* prop; - FT_ASSERT( face && face->bdffont ); + FT_ASSERT( bdfface && bdfface->bdffont ); - prop = bdf_get_font_property( face->bdffont, prop_name ); + prop = bdf_get_font_property( bdfface->bdffont, prop_name ); if ( prop ) { switch ( prop->format ) @@ -902,7 +909,8 @@ THE SOFTWARE. if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) { FT_TRACE1(( "bdf_get_bdf_property:" - " too large integer 0x%x is truncated\n" )); + " too large integer 0x%lx is truncated\n", + prop->value.l )); } aproperty->type = BDF_PROPERTY_TYPE_INTEGER; aproperty->u.integer = (FT_Int32)prop->value.l; @@ -912,7 +920,8 @@ THE SOFTWARE. if ( prop->value.ul > 0xFFFFFFFFUL ) { FT_TRACE1(( "bdf_get_bdf_property:" - " too large cardinal 0x%x is truncated\n" )); + " too large cardinal 0x%lx is truncated\n", + prop->value.ul )); } aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; aproperty->u.cardinal = (FT_UInt32)prop->value.ul; @@ -929,13 +938,16 @@ THE SOFTWARE. } - static FT_Error - bdf_get_charset_id( BDF_Face face, + FT_CALLBACK_DEF( FT_Error ) + bdf_get_charset_id( FT_Face face, /* BDF_Face */ const char* *acharset_encoding, const char* *acharset_registry ) { - *acharset_encoding = face->charset_encoding; - *acharset_registry = face->charset_registry; + BDF_Face bdfface = (BDF_Face)face; + + + *acharset_encoding = bdfface->charset_encoding; + *acharset_registry = bdfface->charset_registry; return 0; } @@ -972,7 +984,6 @@ THE SOFTWARE. } - FT_CALLBACK_TABLE_DEF const FT_Driver_ClassRec bdf_driver_class = { diff --git a/src/thirdparty/freetype2/src/bdf/bdfdrivr.h b/src/thirdparty/freetype2/src/bdf/bdfdrivr.h index b37b84ea3..54aaa3353 100644 --- a/src/thirdparty/freetype2/src/bdf/bdfdrivr.h +++ b/src/thirdparty/freetype2/src/bdf/bdfdrivr.h @@ -28,8 +28,7 @@ THE SOFTWARE. #ifndef BDFDRIVR_H_ #define BDFDRIVR_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include #include "bdf.h" diff --git a/src/thirdparty/freetype2/src/bdf/bdferror.h b/src/thirdparty/freetype2/src/bdf/bdferror.h index dbe41c02a..c1b544487 100644 --- a/src/thirdparty/freetype2/src/bdf/bdferror.h +++ b/src/thirdparty/freetype2/src/bdf/bdferror.h @@ -29,7 +29,7 @@ #ifndef BDFERROR_H_ #define BDFERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -37,7 +37,7 @@ #define FT_ERR_PREFIX BDF_Err_ #define FT_ERR_BASE FT_Mod_Err_BDF -#include FT_ERRORS_H +#include #endif /* BDFERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/bdf/bdflib.c b/src/thirdparty/freetype2/src/bdf/bdflib.c index 63813f7ed..ab6f6a9bf 100644 --- a/src/thirdparty/freetype2/src/bdf/bdflib.c +++ b/src/thirdparty/freetype2/src/bdf/bdflib.c @@ -31,12 +31,11 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include +#include #include "bdf.h" #include "bdferror.h" @@ -52,22 +51,6 @@ #define FT_COMPONENT 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. @@ -77,7 +60,7 @@ /* 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[] = + static const bdf_property_t bdf_properties_[] = { { "ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, { "AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, @@ -87,7 +70,6 @@ { "CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, { "CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, { "CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, - { "COMMENT", BDF_ATOM, 1, { 0 } }, { "COPYRIGHT", BDF_ATOM, 1, { 0 } }, { "DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, { "DESTINATION", BDF_CARDINAL, 1, { 0 } }, @@ -165,56 +147,43 @@ }; static const unsigned long - _num_bdf_properties = sizeof ( _bdf_properties ) / - sizeof ( _bdf_properties[0] ); - - - /* An auxiliary macro to parse properties, to be used in conditionals. */ - /* It behaves like `strncmp' but also tests the following character */ - /* whether it is a whitespace or NULL. */ - /* `property' is a constant string of length `n' to compare with. */ -#define _bdf_strncmp( name, property, n ) \ - ( ft_strncmp( name, property, n ) || \ - !( name[n] == ' ' || \ - name[n] == '\0' || \ - name[n] == '\n' || \ - name[n] == '\r' || \ - name[n] == '\t' ) ) + num_bdf_properties_ = sizeof ( bdf_properties_ ) / + sizeof ( bdf_properties_[0] ); /* 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 ACMSG3 "Font width != actual width. Old: %d New: %d.\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 ACMSG6 "Font descent != actual descent. Old: %d New: %d.\n" +#define ACMSG7 "Font height != actual height. Old: %d New: %d.\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 ACMSG9 "SWIDTH field missing at line %lu. Set automatically.\n" +#define ACMSG10 "DWIDTH field missing at line %lu. Set to glyph width.\n" #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" #define ACMSG13 "Glyph %lu extra rows removed.\n" #define ACMSG14 "Glyph %lu extra columns removed.\n" -#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" +#define ACMSG15 "Incorrect glyph count: %lu indicated but %lu found.\n" #define ACMSG16 "Glyph %lu missing columns padded with zero bits.\n" -#define ACMSG17 "Adjusting number of glyphs to %ld.\n" +#define ACMSG17 "Adjusting number of glyphs to %lu.\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" -#define ERRMSG5 "[line %ld] `%s' value too big.\n" -#define ERRMSG6 "[line %ld] Input line too long.\n" -#define ERRMSG7 "[line %ld] Font name too long.\n" -#define ERRMSG8 "[line %ld] Invalid `%s' value.\n" -#define ERRMSG9 "[line %ld] Invalid keyword.\n" +#define ERRMSG1 "[line %lu] Missing `%s' line.\n" +#define ERRMSG2 "[line %lu] Font header corrupted or missing fields.\n" +#define ERRMSG3 "[line %lu] Font glyphs corrupted or missing fields.\n" +#define ERRMSG4 "[line %lu] BBX too big.\n" +#define ERRMSG5 "[line %lu] `%s' value too big.\n" +#define ERRMSG6 "[line %lu] Input line too long.\n" +#define ERRMSG7 "[line %lu] Font name too long.\n" +#define ERRMSG8 "[line %lu] Invalid `%s' value.\n" +#define ERRMSG9 "[line %lu] Invalid keyword.\n" /* Debug messages. */ -#define DBGMSG1 " [%6ld] %s" /* no \n */ +#define DBGMSG1 " [%6lu] %s" /* no \n */ #define DBGMSG2 " (0x%lX)\n" @@ -225,31 +194,9 @@ */ - /* 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_ + typedef struct bdf_parse_t__ { unsigned long flags; unsigned long cnt; @@ -266,15 +213,23 @@ char* glyph_name; long glyph_enc; + bdf_glyph_t* glyph; bdf_font_t* font; - bdf_options_t* opts; - - _bdf_list_t list; FT_Memory memory; unsigned long size; /* the stream size */ - } _bdf_parse_t; + } bdf_parse_t_; + + + /* Function type for parsing lines of a BDF font. */ + + typedef FT_Error + (*bdf_line_func_t_)( char* line, + unsigned long linelen, + unsigned long lineno, + bdf_parse_t_* p, + void* next ); #define setsbit( m, cc ) \ @@ -283,377 +238,20 @@ ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) - static void - _bdf_list_init( _bdf_list_t* list, - FT_Memory memory ) + static char* + bdf_strtok_( char* line, + int delim ) { - FT_ZERO( list ); - list->memory = memory; - } + while ( *line && *line != delim ) + line++; + if ( *line ) + *line++ = '\0'; - static void - _bdf_list_done( _bdf_list_t* list ) - { - FT_Memory memory = list->memory; + while ( *line && *line == delim ) + line++; - - if ( memory ) - { - FT_FREE( list->field ); - FT_ZERO( list ); - } - } - - - static FT_Error - _bdf_list_ensure( _bdf_list_t* list, - unsigned long num_items ) /* same as _bdf_list_t.used */ - { - FT_Error error = FT_Err_Ok; - - - if ( num_items > list->size ) - { - unsigned long oldsize = list->size; /* same as _bdf_list_t.size */ - unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5; - unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); - FT_Memory memory = list->memory; - - - if ( oldsize == bigsize ) - { - error = FT_THROW( 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; - } - - - /* An empty string for empty fields. */ - - static const char empty[] = ""; /* XXX eliminate this */ - - - static char * - _bdf_list_join( _bdf_list_t* list, - int c, - unsigned long *alen ) - { - unsigned long i, j; - char* dp; - - - *alen = 0; - - if ( list == 0 || list->used == 0 ) - return 0; - - dp = list->field[0]; - for ( i = j = 0; i < list->used; i++ ) - { - char* fp = list->field[i]; - - - while ( *fp ) - dp[j++] = *fp++; - - if ( i + 1 < list->used ) - dp[j++] = (char)c; - } - if ( dp != empty ) - dp[j] = 0; - - *alen = j; - return dp; - } - - - /* The code below ensures that we have at least 4 + 1 `field' */ - /* elements in `list' (which are possibly NULL) so that we */ - /* don't have to check the number of fields in most cases. */ - - static FT_Error - _bdf_list_split( _bdf_list_t* list, - const char* separators, - char* line, - unsigned long linelen ) - { - unsigned long final_empty; - int mult; - const char *sp, *end; - char *ep; - char seps[32]; - FT_Error error = FT_Err_Ok; - - - /* Initialize the list. */ - list->used = 0; - if ( list->size ) - { - list->field[0] = (char*)empty; - list->field[1] = (char*)empty; - list->field[2] = (char*)empty; - list->field[3] = (char*)empty; - list->field[4] = (char*)empty; - } - - /* 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 = FT_THROW( 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 ) ? (char*)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, hold, to_skip; - ptrdiff_t bytes, start, end, cursor, avail; - char* buf = NULL; - FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; - - - if ( callback == 0 ) - { - error = FT_THROW( 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; - avail = 0; - cursor = 0; - refill = 1; - to_skip = NO_SKIP; - bytes = 0; /* make compiler happy */ - - for (;;) - { - if ( refill ) - { - bytes = (ptrdiff_t)FT_Stream_TryRead( - stream, (FT_Byte*)buf + cursor, - buf_size - (unsigned long)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 */ - { - FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno )); - error = FT_THROW( Invalid_Argument ); - goto Exit; - } - - new_size = buf_size * 2; - if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) - goto Exit; - - cursor = (ptrdiff_t)buf_size; - buf_size = new_size; - } - else - { - bytes = avail - start; - - FT_MEM_MOVE( 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, (unsigned long)( end - start ), lineno, - (void*)&cb, client_data ); - /* Redo if we have encountered CHARS without properties. */ - if ( error == -1 ) - error = (*cb)( buf + start, (unsigned long)( 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; + return line; } @@ -661,17 +259,22 @@ 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 + 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, 0x00 }; static const unsigned char ddigits[32] = @@ -682,25 +285,14 @@ 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, - }; - /* Routine to convert a decimal ASCII string to an unsigned long integer. */ static unsigned long - _bdf_atoul( const char* s ) + bdf_atoul_( const char* s ) { unsigned long v; - if ( s == 0 || *s == 0 ) - return 0; - for ( v = 0; sbitset( ddigits, *s ); s++ ) { if ( v < ( FT_ULONG_MAX - 9 ) / 10 ) @@ -718,21 +310,19 @@ /* Routine to convert a decimal ASCII string to a signed long integer. */ static long - _bdf_atol( const char* s ) + bdf_atol_( const char* s ) { long v, neg; - if ( s == 0 || *s == 0 ) - return 0; - /* Check for a minus sign. */ - neg = 0; if ( *s == '-' ) { s++; - neg = 1; + neg = -1; } + else + neg = 1; for ( v = 0; sbitset( ddigits, *s ); s++ ) { @@ -745,20 +335,17 @@ } } - return ( !neg ) ? v : -v; + return neg * v; } /* Routine to convert a decimal ASCII string to an unsigned short integer. */ static unsigned short - _bdf_atous( const char* s ) + bdf_atous_( const char* s ) { unsigned short v; - if ( s == 0 || *s == 0 ) - return 0; - for ( v = 0; sbitset( ddigits, *s ); s++ ) { if ( v < ( FT_USHORT_MAX - 9 ) / 10 ) @@ -776,21 +363,19 @@ /* Routine to convert a decimal ASCII string to a signed short integer. */ static short - _bdf_atos( const char* s ) + bdf_atos_( const char* s ) { short v, neg; - if ( s == 0 || *s == 0 ) - return 0; - /* Check for a minus. */ - neg = 0; if ( *s == '-' ) { s++; - neg = 1; + neg = -1; } + else + neg = 1; for ( v = 0; sbitset( ddigits, *s ); s++ ) { @@ -803,12 +388,12 @@ } } - return (short)( ( !neg ) ? v : -v ); + return neg * v; } /* Routine to compare two glyphs by encoding so they can be sorted. */ - static int + FT_COMPARE_DEF( int ) by_encoding( const void* a, const void* b ) { @@ -845,27 +430,21 @@ if ( ft_hash_str_lookup( name, &(font->proptbl) ) ) goto Exit; - if ( FT_RENEW_ARRAY( font->user_props, - font->nuser_props, - font->nuser_props + 1 ) ) + if ( FT_QRENEW_ARRAY( font->user_props, + font->nuser_props, + font->nuser_props + 1 ) ) goto Exit; p = font->user_props + font->nuser_props; - FT_ZERO( p ); - n = ft_strlen( name ) + 1; - if ( n > FT_ULONG_MAX ) - return FT_THROW( Invalid_Argument ); - - if ( FT_NEW_ARRAY( p->name, n ) ) + if ( FT_STRDUP( p->name, name ) ) goto Exit; - FT_MEM_COPY( (char *)p->name, name, n ); + p->format = format; + p->builtin = 0; + p->value.atom = NULL; /* nothing is ever stored here */ - p->format = format; - p->builtin = 0; - - n = _num_bdf_properties + font->nuser_props; + n = num_bdf_properties_ + font->nuser_props; error = ft_hash_str_insert( p->name, n, &(font->proptbl), memory ); if ( error ) @@ -878,23 +457,23 @@ } - FT_LOCAL_DEF( bdf_property_t* ) - bdf_get_property( char* name, + static bdf_property_t* + bdf_get_property( const char* name, bdf_font_t* font ) { size_t* propid; - if ( name == 0 || *name == 0 ) - return 0; + if ( name == NULL || *name == 0 ) + return NULL; if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL ) - return 0; + return NULL; - if ( *propid >= _num_bdf_properties ) - return font->user_props + ( *propid - _num_bdf_properties ); + if ( *propid >= num_bdf_properties_ ) + return font->user_props + ( *propid - num_bdf_properties_ ); - return (bdf_property_t*)_bdf_properties + *propid; + return (bdf_property_t*)bdf_properties_ + *propid; } @@ -920,8 +499,6 @@ #define BDF_BBX_ 0x0400U #define BDF_BITMAP_ 0x0800U -#define BDF_SWIDTH_ADJ_ 0x1000U - #define BDF_GLYPH_BITS_ ( BDF_GLYPH_ | \ BDF_ENCODING_ | \ BDF_SWIDTH_ | \ @@ -929,13 +506,10 @@ BDF_BBX_ | \ BDF_BITMAP_ ) -#define BDF_GLYPH_WIDTH_CHECK_ 0x40000000UL -#define BDF_GLYPH_HEIGHT_CHECK_ 0x80000000UL - static FT_Error - _bdf_add_comment( bdf_font_t* font, - char* comment, + bdf_add_comment_( bdf_font_t* font, + const char* comment, unsigned long len ) { char* cp; @@ -943,15 +517,22 @@ FT_Error error = FT_Err_Ok; - if ( FT_RENEW_ARRAY( font->comments, - font->comments_len, - font->comments_len + len + 1 ) ) + /* Skip keyword COMMENT. */ + comment += 7; + len -= 7; + + if ( len == 0 ) + goto Exit; + + if ( FT_QRENEW_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'; + cp[len] = '\0'; font->comments_len += len + 1; @@ -960,80 +541,10 @@ } - /* 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 lineno ) - { - size_t len; - char name[256]; - _bdf_list_t list; - FT_Memory memory; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( lineno ); /* only used in debug mode */ - - - if ( font == 0 || font->name == 0 || font->name[0] == 0 ) - { - error = FT_THROW( Invalid_Argument ); - goto Exit; - } - - memory = font->memory; - - _bdf_list_init( &list, memory ); - - font->spacing = opts->font_spacing; - - len = ft_strlen( font->name ) + 1; - /* Limit ourselves to 256 characters in the font name. */ - if ( len >= 256 ) - { - FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno )); - error = FT_THROW( Invalid_Argument ); - goto Exit; - } - - FT_MEM_COPY( name, font->name, len ); - - error = _bdf_list_split( &list, "-", name, (unsigned long)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, + bdf_is_atom_( char* line, unsigned long linelen, char** name, char** value, @@ -1044,27 +555,24 @@ bdf_property_t* p; - *name = sp = ep = line; + sp = ep = line; - while ( *ep && *ep != ' ' && *ep != '\t' ) + while ( *ep && *ep != ' ' ) ep++; - hold = -1; - if ( *ep ) - { - hold = *ep; - *ep = 0; - } + 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 ) + { + *ep = (char)hold; /* Undo NUL-termination. */ return 0; + } + + *name = sp; /* The property is an atom. Trim all leading and trailing whitespace */ /* and double quotes for the atom value. */ @@ -1072,32 +580,33 @@ ep = line + linelen; /* Trim the leading whitespace if it exists. */ - if ( *sp ) - *sp++ = 0; - while ( *sp && - ( *sp == ' ' || *sp == '\t' ) ) - sp++; + if ( sp < ep ) + do + sp++; + while ( *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; + if ( sp < ep ) + do + *ep-- = '\0'; + while ( *ep == ' ' ); /* Trim the trailing double quote if it exists. */ - if ( ep > sp && *( ep - 1 ) == '"' ) - *--ep = 0; + if ( *ep == '"' ) + *ep = '\0'; return 1; } static FT_Error - _bdf_add_property( bdf_font_t* font, + bdf_add_property_( bdf_font_t* font, const char* name, char* value, unsigned long lineno ) @@ -1111,8 +620,7 @@ /* First, check whether the property already exists in the font. */ - if ( ( propid = ft_hash_str_lookup( name, - (FT_Hash)font->internal ) ) != NULL ) + if ( ( propid = ft_hash_str_lookup( name, font->internal ) ) != NULL ) { /* The property already exists in the font, so simply replace */ /* the value of the property with the current value. */ @@ -1132,11 +640,11 @@ break; case BDF_INTEGER: - fp->value.l = _bdf_atol( value ); + fp->value.l = bdf_atol_( value ); break; case BDF_CARDINAL: - fp->value.ul = _bdf_atoul( value ); + fp->value.ul = bdf_atoul_( value ); break; default: @@ -1160,28 +668,18 @@ /* Allocate another property if this is overflowing. */ 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; - } + if ( FT_QRENEW_ARRAY( font->props, + font->props_size, + font->props_size + 1 ) ) + goto Exit; - fp = font->props + font->props_size; - FT_ZERO( fp ); font->props_size++; } - if ( *propid >= _num_bdf_properties ) - prop = font->user_props + ( *propid - _num_bdf_properties ); + if ( *propid >= num_bdf_properties_ ) + prop = font->user_props + ( *propid - num_bdf_properties_ ); else - prop = (bdf_property_t*)_bdf_properties + *propid; + prop = (bdf_property_t*)bdf_properties_ + *propid; fp = font->props + font->props_used; @@ -1192,8 +690,8 @@ switch ( prop->format ) { case BDF_ATOM: - fp->value.atom = 0; - if ( value != 0 && value[0] ) + fp->value.atom = NULL; + if ( value && value[0] ) { if ( FT_STRDUP( fp->value.atom, value ) ) goto Exit; @@ -1201,182 +699,145 @@ break; case BDF_INTEGER: - fp->value.l = _bdf_atol( value ); + fp->value.l = bdf_atol_( value ); break; case BDF_CARDINAL: - fp->value.ul = _bdf_atoul( value ); + fp->value.ul = bdf_atoul_( value ); break; } - /* If the property happens to be a comment, then it doesn't need */ - /* to be added to the internal hash table. */ - if ( _bdf_strncmp( name, "COMMENT", 7 ) != 0 ) - { - /* Add the property to the font property table. */ - error = ft_hash_str_insert( fp->name, - font->props_used, - (FT_Hash)font->internal, - memory ); - if ( error ) - goto Exit; - } + /* Add the property to the font property table. */ + error = ft_hash_str_insert( fp->name, + font->props_used, + 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 ( _bdf_strncmp( name, "DEFAULT_CHAR", 12 ) == 0 ) - font->default_char = fp->value.ul; - else if ( _bdf_strncmp( name, "FONT_ASCENT", 11 ) == 0 ) - font->font_ascent = fp->value.l; - else if ( _bdf_strncmp( name, "FONT_DESCENT", 12 ) == 0 ) - font->font_descent = fp->value.l; - else if ( _bdf_strncmp( name, "SPACING", 7 ) == 0 ) - { - if ( !fp->value.atom ) - { - FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - - 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 - }; - - static FT_Error - _bdf_parse_end( char* line, + bdf_parse_end_( char* line, unsigned long linelen, unsigned long lineno, - void* call_data, - void* client_data ) + bdf_parse_t_* p, + void* next ) { /* a no-op; we ignore everything after `ENDFONT' */ FT_UNUSED( line ); FT_UNUSED( linelen ); FT_UNUSED( lineno ); - FT_UNUSED( call_data ); - FT_UNUSED( client_data ); + FT_UNUSED( p ); + FT_UNUSED( next ); return FT_Err_Ok; } - /* Actually parse the glyph info and bitmaps. */ + /* Line function prototypes. */ static FT_Error - _bdf_parse_glyphs( char* line, + bdf_parse_start_( char* line, + unsigned long linelen, + unsigned long lineno, + bdf_parse_t_* p, + void* next ); + + + static FT_Error + bdf_parse_glyphs_( char* line, unsigned long linelen, unsigned long lineno, - void* call_data, - void* client_data ) + bdf_parse_t_* p, + void* next ); + + + /* Aggressively parse the glyph bitmaps. */ + static FT_Error + bdf_parse_bitmap_( char* line, + unsigned long linelen, + unsigned long lineno, + bdf_parse_t_* p, + void* next ) { - int c, mask_index; - char* s; - unsigned char* bp; - unsigned long i, slen, nibbles; - - _bdf_line_func_t* next; - _bdf_parse_t* p; - bdf_glyph_t* glyph; - bdf_font_t* font; - - FT_Memory memory; - FT_Error error = FT_Err_Ok; + bdf_glyph_t* glyph = p->glyph; + unsigned char* bp; + unsigned long i, nibbles; + int x; FT_UNUSED( lineno ); /* only used in debug mode */ - next = (_bdf_line_func_t *)call_data; - p = (_bdf_parse_t *) client_data; + nibbles = glyph->bpr << 1; + bp = glyph->bitmap + p->row * glyph->bpr; - font = p->font; - memory = font->memory; - - /* Check for a comment. */ - if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + if ( nibbles > linelen ) { - linelen -= 7; - - s = line + 7; - if ( *s != 0 ) - { - s++; - linelen--; - } - error = _bdf_add_comment( p->font, s, linelen ); - goto Exit; + FT_TRACE2(( "bdf_parse_bitmap_: " ACMSG16, glyph->encoding )); + nibbles = linelen; } - /* The very first thing expected is the number of glyphs. */ - if ( !( p->flags & BDF_GLYPHS_ ) ) + for ( i = 0; i < nibbles; i++ ) { - if ( _bdf_strncmp( line, "CHARS", 5 ) != 0 ) - { - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); - error = FT_THROW( Missing_Chars_Field ); - goto Exit; - } + /* char to hex without checks */ + x = line[i]; + x += 9 * ( x & 0x40 ) >> 6; /* for [A-Fa-f] */ + x &= 0x0F; - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; - p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1] ); + if ( i & 1 ) + *bp++ |= x; + else + *bp = (unsigned char)( x << 4 ); + } - /* We need at least 20 bytes per glyph. */ - if ( p->cnt > p->size / 20 ) - { - p->cnt = font->glyphs_size = p->size / 20; - FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG17, p->cnt )); - } + p->row++; - /* Make sure the number of glyphs is non-zero. */ - if ( p->cnt == 0 ) - font->glyphs_size = 64; + /* When done, go back to parsing glyphs */ + if ( p->row >= (unsigned long)glyph->bbx.height ) + *(bdf_line_func_t_*)next = bdf_parse_glyphs_; - /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ - /* number of code points available in Unicode). */ - if ( p->cnt >= 0x110000UL ) - { - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" )); - error = FT_THROW( Invalid_Argument ); - goto Exit; - } + return FT_Err_Ok; + } - if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) - goto Exit; - p->flags |= BDF_GLYPHS_; + /* Actually parse the glyph info. */ + static FT_Error + bdf_parse_glyphs_( char* line, + unsigned long linelen, + unsigned long lineno, + bdf_parse_t_* p, + void* next ) + { + bdf_font_t* font = p->font; + bdf_glyph_t* glyph; + FT_Memory memory = font->memory; + FT_Error error = FT_Err_Ok; + + FT_UNUSED( lineno ); /* only used in debug mode */ + + + /* Check for a comment. */ + if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->flags & BDF_KEEP_COMMENTS ) + error = bdf_add_comment_( font, line, linelen ); goto Exit; } /* Check for the ENDFONT field. */ - if ( _bdf_strncmp( line, "ENDFONT", 7 ) == 0 ) + if ( ft_strncmp( line, "ENDFONT", 7 ) == 0 ) { if ( p->flags & BDF_GLYPH_BITS_ ) { /* Missing ENDCHAR field. */ - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); error = FT_THROW( Corrupted_Font_Glyphs ); goto Exit; } @@ -1388,14 +849,18 @@ by_encoding ); p->flags &= ~BDF_START_; - *next = _bdf_parse_end; + + *(bdf_line_func_t_*)next = bdf_parse_end_; goto Exit; } /* Check for the ENDCHAR field. */ - if ( _bdf_strncmp( line, "ENDCHAR", 7 ) == 0 ) + if ( ft_strncmp( line, "ENDCHAR", 7 ) == 0 ) { + /* Free unused glyph_name */ + FT_FREE( p->glyph_name ); + p->glyph_enc = 0; p->flags &= ~BDF_GLYPH_BITS_; @@ -1404,69 +869,48 @@ /* Check 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 ) + if ( p->flags & BDF_GLYPH_ && + p->glyph_enc == -1 && + !( p->flags & BDF_KEEP_UNENCODED ) ) goto Exit; /* Check for the STARTCHAR field. */ - if ( _bdf_strncmp( line, "STARTCHAR", 9 ) == 0 ) + if ( ft_strncmp( line, "STARTCHAR ", 10 ) == 0 ) { if ( p->flags & BDF_GLYPH_BITS_ ) { /* Missing ENDCHAR field. */ - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENDCHAR" )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENDCHAR" )); error = FT_THROW( Missing_Startchar_Field ); goto Exit; } - /* Set the character name in the parse info first until the */ - /* encoding can be checked for an unencoded character. */ - FT_FREE( p->glyph_name ); + line = bdf_strtok_( line, ' ' ); - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) + if ( FT_STRDUP( p->glyph_name, line ) ) goto Exit; - _bdf_list_shift( &p->list, 1 ); - - s = _bdf_list_join( &p->list, ' ', &slen ); - - if ( !s ) - { - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" )); - error = FT_THROW( 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_; - FT_TRACE4(( DBGMSG1, lineno, s )); + FT_TRACE4(( DBGMSG1, lineno, line )); goto Exit; } /* Check for the ENCODING field. */ - if ( _bdf_strncmp( line, "ENCODING", 8 ) == 0 ) + if ( ft_strncmp( line, "ENCODING ", 9 ) == 0 ) { if ( !( p->flags & BDF_GLYPH_ ) ) { /* Missing STARTCHAR field. */ - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "STARTCHAR" )); error = FT_THROW( Missing_Startchar_Field ); goto Exit; } - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; + line = bdf_strtok_( line, ' ' ); - p->glyph_enc = _bdf_atol( p->list.field[1] ); + p->glyph_enc = bdf_atol_( line ); /* Normalize negative encoding values. The specification only */ /* allows -1, but we can be more generous here. */ @@ -1474,8 +918,10 @@ p->glyph_enc = -1; /* Check for alternative encoding format. */ - if ( p->glyph_enc == -1 && p->list.used > 2 ) - p->glyph_enc = _bdf_atol( p->list.field[2] ); + line = bdf_strtok_( line, ' ' ); + + if ( p->glyph_enc == -1 && *line ) + p->glyph_enc = bdf_atol_( line ); if ( p->glyph_enc < -1 || p->glyph_enc >= 0x110000L ) p->glyph_enc = -1; @@ -1499,49 +945,35 @@ glyph = font->glyphs + font->glyphs_used++; glyph->name = p->glyph_name; glyph->encoding = (unsigned long)p->glyph_enc; + } + else if ( p->flags & BDF_KEEP_UNENCODED ) + { + /* 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; - /* Reset the initial glyph info. */ - p->glyph_name = NULL; + font->unencoded_size += 4; + } + + glyph = font->unencoded + font->unencoded_used; + glyph->name = p->glyph_name; + glyph->encoding = font->unencoded_used++; } else { - /* Unencoded glyph. Check 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++; - - /* Reset the initial glyph info. */ - p->glyph_name = NULL; - } - else - { - /* Free up the glyph name if the unencoded shouldn't be */ - /* kept. */ - FT_FREE( p->glyph_name ); - } - - p->glyph_name = NULL; + /* Free up the glyph name if the unencoded shouldn't be */ + /* kept. */ + FT_FREE( p->glyph_name ); + glyph = NULL; } - /* 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_; + p->glyph_name = NULL; + p->glyph = glyph; + p->flags |= BDF_ENCODING_; goto Exit; } @@ -1550,96 +982,29 @@ goto Missing_Encoding; /* 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 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_; - } - - 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]; - if ( !sbitset( hdigits, c ) ) - break; - *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); - if ( i + 1 < nibbles && ( i & 1 ) ) - *++bp = 0; - } - - /* If any line has not enough columns, */ - /* indicate they have been padded with zero bits. */ - if ( i < nibbles && - !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) - { - FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding )); - p->flags |= BDF_GLYPH_WIDTH_CHECK_; - } - - /* 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 ( i == nibbles && - sbitset( hdigits, line[nibbles] ) && - !( p->flags & BDF_GLYPH_WIDTH_CHECK_ ) ) - { - FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); - p->flags |= BDF_GLYPH_WIDTH_CHECK_; - } - - p->row++; - goto Exit; - } + glyph = p->glyph; /* Expect the SWIDTH (scalable width) field next. */ - if ( _bdf_strncmp( line, "SWIDTH", 6 ) == 0 ) + if ( ft_strncmp( line, "SWIDTH ", 7 ) == 0 ) { - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; + line = bdf_strtok_( line, ' ' ); + glyph->swidth = bdf_atous_( line ); - glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1] ); p->flags |= BDF_SWIDTH_; - goto Exit; } - /* Expect the DWIDTH (scalable width) field next. */ - if ( _bdf_strncmp( line, "DWIDTH", 6 ) == 0 ) + /* Expect the DWIDTH (device width) field next. */ + if ( ft_strncmp( line, "DWIDTH ", 7 ) == 0 ) { - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; - - glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1] ); + line = bdf_strtok_( line, ' ' ); + glyph->dwidth = bdf_atous_( line ); 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 )); + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG9, lineno )); glyph->swidth = (unsigned short)FT_MulDiv( glyph->dwidth, 72000L, @@ -1651,17 +1016,21 @@ goto Exit; } - /* Expect the BBX field next. */ - if ( _bdf_strncmp( line, "BBX", 3 ) == 0 ) - { - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; + /* Do not leak the bitmap or reset its size */ + if ( p->flags & BDF_BITMAP_ ) + goto Exit; - glyph->bbx.width = _bdf_atous( p->list.field[1] ); - glyph->bbx.height = _bdf_atous( p->list.field[2] ); - glyph->bbx.x_offset = _bdf_atos( p->list.field[3] ); - glyph->bbx.y_offset = _bdf_atos( p->list.field[4] ); + /* Expect the BBX field next. */ + if ( ft_strncmp( line, "BBX ", 4 ) == 0 ) + { + line = bdf_strtok_( line, ' ' ); + glyph->bbx.width = bdf_atous_( line ); + line = bdf_strtok_( line, ' ' ); + glyph->bbx.height = bdf_atous_( line ); + line = bdf_strtok_( line, ' ' ); + glyph->bbx.x_offset = bdf_atos_( line ); + line = bdf_strtok_( line, ' ' ); + glyph->bbx.y_offset = bdf_atos_( line ); /* Generate the ascent and descent of the character. */ glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); @@ -1682,13 +1051,13 @@ { /* Missing DWIDTH field. Emit an auto correction message and set */ /* the device width to the glyph width. */ - FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); + 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 ) + if ( p->flags & BDF_CORRECT_METRICS ) { /* Determine the point size of the glyph. */ unsigned short sw = (unsigned short)FT_MulDiv( @@ -1701,7 +1070,7 @@ { glyph->swidth = sw; - p->flags |= BDF_SWIDTH_ADJ_; + FT_TRACE2(( "bdf_parse_glyphs_: " ACMSG8 )); } } @@ -1710,7 +1079,7 @@ } /* And finally, gather up the bitmap. */ - if ( _bdf_strncmp( line, "BITMAP", 6 ) == 0 ) + if ( ft_strncmp( line, "BITMAP", 6 ) == 0 ) { unsigned long bitmap_size; @@ -1718,7 +1087,7 @@ if ( !( p->flags & BDF_BBX_ ) ) { /* Missing BBX field. */ - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "BBX" )); error = FT_THROW( Missing_Bbx_Field ); goto Exit; } @@ -1729,29 +1098,30 @@ bitmap_size = glyph->bpr * glyph->bbx.height; if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU ) { - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG4, lineno )); error = FT_THROW( Bbx_Too_Big ); goto Exit; } else glyph->bytes = (unsigned short)bitmap_size; - if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) + if ( !bitmap_size || FT_ALLOC( glyph->bitmap, glyph->bytes ) ) goto Exit; p->row = 0; p->flags |= BDF_BITMAP_; + *(bdf_line_func_t_*)next = bdf_parse_bitmap_; goto Exit; } - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG9, lineno )); error = FT_THROW( Invalid_File_Format ); goto Exit; Missing_Encoding: /* Missing ENCODING field. */ - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); + FT_ERROR(( "bdf_parse_glyphs_: " ERRMSG1, lineno, "ENCODING" )); error = FT_THROW( Missing_Encoding_Field ); Exit: @@ -1764,98 +1134,52 @@ /* Load the font properties. */ static FT_Error - _bdf_parse_properties( char* line, + bdf_parse_properties_( char* line, unsigned long linelen, unsigned long lineno, - void* call_data, - void* client_data ) + bdf_parse_t_* p, + void* next ) { - unsigned long vlen; - _bdf_line_func_t* next; - _bdf_parse_t* p; - char* name; - char* value; - char nbuf[128]; - FT_Error error = FT_Err_Ok; + bdf_font_t* font = p->font; + FT_Error error = FT_Err_Ok; + char* name; + char* value; FT_UNUSED( lineno ); - next = (_bdf_line_func_t *)call_data; - p = (_bdf_parse_t *) client_data; + /* Check for a comment. */ + if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->flags & BDF_KEEP_COMMENTS ) + error = bdf_add_comment_( font, line, linelen ); + + goto Exit; + } /* Check for the end of the properties. */ - if ( _bdf_strncmp( line, "ENDPROPERTIES", 13 ) == 0 ) + if ( ft_strncmp( 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, "FONT_ASCENT", - nbuf, lineno ); - if ( error ) - goto Exit; - - FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); - } - - 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, "FONT_DESCENT", - nbuf, lineno ); - if ( error ) - goto Exit; - - FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); - } - - p->flags &= ~BDF_PROPS_; - *next = _bdf_parse_glyphs; + *(bdf_line_func_t_*)next = bdf_parse_start_; goto Exit; } /* Ignore the _XFREE86_GLYPH_RANGES properties. */ - if ( _bdf_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) + if ( ft_strncmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) goto Exit; - /* Handle COMMENT fields and properties in a special way to preserve */ - /* the spacing. */ - if ( _bdf_strncmp( line, "COMMENT", 7 ) == 0 ) + if ( bdf_is_atom_( line, linelen, &name, &value, p->font ) ) { - name = value = line; - value += 7; - if ( *value ) - *value++ = 0; - error = _bdf_add_property( p->font, name, value, lineno ); - if ( error ) - goto Exit; - } - else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) - { - error = _bdf_add_property( p->font, name, value, lineno ); + error = bdf_add_property_( font, name, value, lineno ); if ( error ) goto Exit; } else { - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; - name = p->list.field[0]; + value = bdf_strtok_( line, ' ' ); - _bdf_list_shift( &p->list, 1 ); - value = _bdf_list_join( &p->list, ' ', &vlen ); - - error = _bdf_add_property( p->font, name, value, lineno ); + error = bdf_add_property_( font, line, value, lineno ); if ( error ) goto Exit; } @@ -1867,169 +1191,124 @@ /* Load the font header. */ static FT_Error - _bdf_parse_start( char* line, + bdf_parse_start_( char* line, unsigned long linelen, unsigned long lineno, - void* call_data, - void* client_data ) + bdf_parse_t_* p, + void* next ) { - 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 = FT_Err_Ok; + bdf_font_t* font; + FT_Memory memory = p->memory; + FT_Error error = FT_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 ( _bdf_strncmp( 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; - } - + /* The first line must be STARTFONT. */ + /* Otherwise, reject the font immediately. */ if ( !( p->flags & BDF_START_ ) ) { - memory = p->memory; - - if ( _bdf_strncmp( line, "STARTFONT", 9 ) != 0 ) + if ( ft_strncmp( line, "STARTFONT", 9 ) != 0 ) { - /* we don't emit an error message since this code gets */ - /* explicitly caught one level higher */ error = FT_THROW( Missing_Startfont_Field ); goto Exit; } - p->flags = BDF_START_; - font = p->font = 0; + p->flags |= BDF_START_; - if ( FT_NEW( font ) ) + if ( FT_NEW( p->font ) ) goto Exit; - p->font = font; - font->memory = p->memory; - p->memory = 0; + p->font->memory = memory; - { /* setup */ - size_t i; - bdf_property_t* prop; + goto Exit; + } + /* Point at the font being constructed. */ + font = p->font; - error = ft_hash_str_init( &(font->proptbl), memory ); - if ( error ) - goto Exit; - for ( i = 0, prop = (bdf_property_t*)_bdf_properties; - i < _num_bdf_properties; i++, prop++ ) - { - error = ft_hash_str_insert( prop->name, i, - &(font->proptbl), memory ); - if ( error ) - goto Exit; - } - } - - if ( FT_ALLOC( p->font->internal, sizeof ( FT_HashRec ) ) ) - goto Exit; - error = ft_hash_str_init( (FT_Hash)p->font->internal, memory ); - if ( error ) - goto Exit; - p->font->spacing = p->opts->font_spacing; - p->font->default_char = ~0UL; + /* Check for a comment. */ + if ( ft_strncmp( line, "COMMENT", 7 ) == 0 ) + { + if ( p->flags & BDF_KEEP_COMMENTS ) + error = bdf_add_comment_( font, line, linelen ); goto Exit; } /* Check for the start of the properties. */ - if ( _bdf_strncmp( line, "STARTPROPERTIES", 15 ) == 0 ) + if ( !( p->flags & BDF_PROPS_ ) && + ft_strncmp( line, "STARTPROPERTIES ", 16 ) == 0 ) { - if ( !( p->flags & BDF_FONT_BBX_ ) ) - { - /* Missing the FONTBOUNDINGBOX field. */ - FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); - error = FT_THROW( Missing_Fontboundingbox_Field ); - goto Exit; - } + line = bdf_strtok_( line, ' ' ); + font->props_size = bdf_atoul_( line ); - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; + if ( font->props_size < 2 ) + font->props_size = 2; - /* at this point, `p->font' can't be NULL */ - p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1] ); /* We need at least 4 bytes per property. */ - if ( p->cnt > p->size / 4 ) + if ( font->props_size > p->size / 4 ) { - p->font->props_size = 0; + font->props_size = 0; - FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "STARTPROPERTIES" )); + FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "STARTPROPERTIES" )); error = FT_THROW( Invalid_Argument ); goto Exit; } - if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) + if ( FT_NEW_ARRAY( font->props, font->props_size ) ) { - p->font->props_size = 0; + font->props_size = 0; goto Exit; } + if ( FT_QNEW( font->internal ) ) + goto Exit; + error = ft_hash_str_init( font->internal, memory ); + if ( error ) + goto Exit; + + /* preset common properties */ + { + bdf_property_t* prop = (bdf_property_t*)bdf_properties_; + FT_Hash proptbl = &font->proptbl; + size_t i; + + + error = ft_hash_str_init( proptbl, memory ); + if ( error ) + goto Exit; + for ( i = 0; i < num_bdf_properties_; i++, prop++ ) + { + error = ft_hash_str_insert( prop->name, i, proptbl, memory ); + if ( error ) + goto Exit; + } + } + p->flags |= BDF_PROPS_; - *next = _bdf_parse_properties; + + *(bdf_line_func_t_*)next = bdf_parse_properties_; goto Exit; } /* Check for the FONTBOUNDINGBOX field. */ - if ( _bdf_strncmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) + if ( ft_strncmp( line, "FONTBOUNDINGBOX ", 16 ) == 0 ) { - if ( !( p->flags & BDF_SIZE_ ) ) - { - /* Missing the SIZE field. */ - FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); - error = FT_THROW( Missing_Size_Field ); - goto Exit; - } + line = bdf_strtok_( line, ' ' ); + font->bbx.width = bdf_atous_( line ); + line = bdf_strtok_( line, ' ' ); + font->bbx.height = bdf_atous_( line ); + line = bdf_strtok_( line, ' ' ); + font->bbx.x_offset = bdf_atos_( line ); + line = bdf_strtok_( line, ' ' ); + font->bbx.y_offset = bdf_atos_( line ); - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; + font->bbx.ascent = (short)( font->bbx.height + + font->bbx.y_offset ); - p->font->bbx.width = _bdf_atous( p->list.field[1] ); - p->font->bbx.height = _bdf_atous( p->list.field[2] ); - - p->font->bbx.x_offset = _bdf_atos( p->list.field[3] ); - p->font->bbx.y_offset = _bdf_atos( p->list.field[4] ); - - p->font->bbx.ascent = (short)( p->font->bbx.height + - p->font->bbx.y_offset ); - - p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); + font->bbx.descent = (short)( -font->bbx.y_offset ); p->flags |= BDF_FONT_BBX_; @@ -2037,34 +1316,45 @@ } /* The next thing to check for is the FONT field. */ - if ( _bdf_strncmp( line, "FONT", 4 ) == 0 ) + if ( ft_strncmp( line, "FONT ", 5 ) == 0 ) { - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; - _bdf_list_shift( &p->list, 1 ); + int i; - s = _bdf_list_join( &p->list, ' ', &slen ); - if ( !s ) - { - FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } + line = bdf_strtok_( line, ' ' ); /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ - FT_FREE( p->font->name ); + FT_FREE( font->name ); - if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) + if ( FT_STRDUP( font->name, line ) ) 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, lineno ); - if ( error ) - goto Exit; + /* If the font name is an XLFD name, set the spacing to the one in */ + /* the font name after the 11th dash. */ + for ( i = 0; i < 11; i++ ) + { + while ( *line && *line != '-' ) + line++; + if ( *line ) + line++; + } + + switch ( *line ) + { + case 'C': + case 'c': + font->spacing = BDF_CHARCELL; + break; + case 'M': + case 'm': + font->spacing = BDF_MONOWIDTH; + break; + case 'P': + case 'p': + default: + font->spacing = BDF_PROPORTIONAL; + break; + } p->flags |= BDF_FONT_NAME_; @@ -2072,93 +1362,105 @@ } /* Check for the SIZE field. */ - if ( _bdf_strncmp( line, "SIZE", 4 ) == 0 ) + if ( ft_strncmp( line, "SIZE ", 5 ) == 0 ) { - if ( !( p->flags & BDF_FONT_NAME_ ) ) - { - /* Missing the FONT field. */ - FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); - error = FT_THROW( Missing_Font_Field ); - goto Exit; - } - - error = _bdf_list_split( &p->list, " +", line, linelen ); - if ( error ) - goto Exit; - - p->font->point_size = _bdf_atoul( p->list.field[1] ); - p->font->resolution_x = _bdf_atoul( p->list.field[2] ); - p->font->resolution_y = _bdf_atoul( p->list.field[3] ); + line = bdf_strtok_( line, ' ' ); + font->point_size = bdf_atoul_( line ); + line = bdf_strtok_( line, ' ' ); + font->resolution_x = bdf_atoul_( line ); + line = bdf_strtok_( line, ' ' ); + font->resolution_y = bdf_atoul_( line ); /* Check for the bits per pixel field. */ - if ( p->list.used == 5 ) + line = bdf_strtok_( line, ' ' ); + if ( *line ) { unsigned short bpp; - bpp = (unsigned short)_bdf_atos( p->list.field[4] ); + bpp = bdf_atous_( line ); /* Only values 1, 2, 4, 8 are allowed for greymap fonts. */ if ( bpp > 4 ) - p->font->bpp = 8; + font->bpp = 8; else if ( bpp > 2 ) - p->font->bpp = 4; + font->bpp = 4; else if ( bpp > 1 ) - p->font->bpp = 2; + font->bpp = 2; else - p->font->bpp = 1; + font->bpp = 1; - if ( p->font->bpp != bpp ) - FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); + if ( font->bpp != bpp ) + FT_TRACE2(( "bdf_parse_start_: " ACMSG11, font->bpp )); } else - p->font->bpp = 1; + font->bpp = 1; p->flags |= BDF_SIZE_; goto Exit; } - /* Check for the CHARS field -- font properties are optional */ - if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 ) + /* Check for the CHARS field */ + if ( ft_strncmp( line, "CHARS ", 6 ) == 0 ) { - char nbuf[128]; - - + /* Check the header for completeness before parsing glyphs. */ + if ( !( p->flags & BDF_FONT_NAME_ ) ) + { + /* Missing the FONT field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONT" )); + error = FT_THROW( Missing_Font_Field ); + goto Exit; + } + if ( !( p->flags & BDF_SIZE_ ) ) + { + /* Missing the SIZE field. */ + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "SIZE" )); + error = FT_THROW( Missing_Size_Field ); + goto Exit; + } if ( !( p->flags & BDF_FONT_BBX_ ) ) { /* Missing the FONTBOUNDINGBOX field. */ - FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); + FT_ERROR(( "bdf_parse_start_: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); error = FT_THROW( Missing_Fontboundingbox_Field ); goto Exit; } - /* Add the two standard X11 properties which are required */ - /* for compiling fonts. */ - p->font->font_ascent = p->font->bbx.ascent; - ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); - error = _bdf_add_property( p->font, "FONT_ASCENT", - nbuf, lineno ); - if ( error ) + line = bdf_strtok_( line, ' ' ); + p->cnt = font->glyphs_size = bdf_atoul_( line ); + + /* We need at least 20 bytes per glyph. */ + if ( p->cnt > p->size / 20 ) + { + p->cnt = font->glyphs_size = p->size / 20; + FT_TRACE2(( "bdf_parse_start_: " ACMSG17, p->cnt )); + } + + /* 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 >= 0x110000UL ) + { + FT_ERROR(( "bdf_parse_start_: " ERRMSG5, lineno, "CHARS" )); + error = FT_THROW( Invalid_Argument ); goto Exit; - FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); + } - p->font->font_descent = p->font->bbx.descent; - ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); - error = _bdf_add_property( p->font, "FONT_DESCENT", - nbuf, lineno ); - if ( error ) + if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) goto Exit; - FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); - *next = _bdf_parse_glyphs; + p->flags |= BDF_GLYPHS_; + + *(bdf_line_func_t_*)next = bdf_parse_glyphs_; - /* A special return value. */ - error = -1; goto Exit; } - FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno )); + FT_ERROR(( "bdf_parse_start_: " ERRMSG9, lineno )); error = FT_THROW( Invalid_File_Format ); Exit: @@ -2166,6 +1468,104 @@ } + static FT_Error + bdf_readstream_( FT_Stream stream, + bdf_parse_t_* p, + unsigned long* lno ) + { + bdf_line_func_t_ cb = bdf_parse_start_; + unsigned long lineno, buf_size; + unsigned long bytes, start, end, cursor, avail; + char* buf = NULL; + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + + + /* initial size and allocation of the input buffer */ + buf_size = 1024; + + if ( FT_QALLOC( buf, buf_size ) ) + goto Exit; + + lineno = 1; + start = 0; + cursor = 0; + + Refill: + bytes = FT_Stream_TryRead( stream, + (FT_Byte*)buf + cursor, buf_size - cursor ); + avail = cursor + bytes; + + while ( bytes ) + { + /* try to find the start of the line */ + while ( start < avail && buf[start] < ' ' ) + start++; + + /* try to find the end of the line */ + end = start + 1; + while ( end < avail && buf[end] >= ' ' ) + end++; + + /* if we hit the end of the buffer, try shifting its content */ + /* or even resizing it */ + if ( end >= avail ) + { + 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 */ + { + FT_ERROR(( "bdf_readstream_: " ERRMSG6, lineno )); + error = FT_THROW( Invalid_File_Format ); + + goto Exit; + } + + new_size = buf_size * 4; + if ( FT_QREALLOC( buf, buf_size, new_size ) ) + goto Exit; + + cursor = avail; + buf_size = new_size; + } + else + { + cursor = avail - start; + + FT_MEM_MOVE( buf, buf + start, cursor ); + + start = 0; + } + goto Refill; + } + + /* NUL-terminate the line. */ + buf[end] = 0; + + if ( buf[start] != '#' ) + { + error = (*cb)( buf + start, end - start, lineno, p, (void*)&cb ); + if ( error ) + break; + } + + lineno += 1; + start = end + 1; + } + + *lno = lineno; + + Exit: + FT_FREE( buf ); + return error; + } + + /************************************************************************** * * API. @@ -2175,41 +1575,30 @@ FT_LOCAL_DEF( FT_Error ) bdf_load_font( FT_Stream stream, - FT_Memory extmemory, - bdf_options_t* opts, + FT_Memory memory, + unsigned long flags, bdf_font_t* *font ) { unsigned long lineno = 0; /* make compiler happy */ - _bdf_parse_t *p = NULL; + bdf_parse_t_ *p = NULL; - FT_Memory memory = extmemory; /* needed for FT_NEW */ - FT_Error error = FT_Err_Ok; + FT_Error error = FT_Err_Ok; if ( FT_NEW( p ) ) goto Exit; - memory = NULL; - p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); + p->flags = flags; /* comments, metrics, unencoded */ p->minlb = 32767; p->size = stream->size; - p->memory = extmemory; /* only during font creation */ + p->memory = memory; /* only during font creation */ - _bdf_list_init( &p->list, extmemory ); - - error = _bdf_readstream( stream, _bdf_parse_start, - (void *)p, &lineno ); + error = bdf_readstream_( stream, p, &lineno ); if ( error ) goto Fail; - if ( p->font != 0 ) + if ( p->font ) { - /* If the font is not proportional, set the font's monowidth */ - /* field to the width of the font bounding box. */ - - 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 ) @@ -2220,7 +1609,7 @@ /* Once the font has been loaded, adjust the overall font metrics if */ /* necessary. */ - if ( p->opts->correct_metrics != 0 && + if ( p->flags & BDF_CORRECT_METRICS && ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) { if ( p->maxrb - p->minlb != p->font->bbx.width ) @@ -2258,9 +1647,6 @@ 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 )); } } @@ -2283,22 +1669,7 @@ } } - 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 ) + if ( !p->font && !error ) error = FT_THROW( Invalid_File_Format ); *font = p->font; @@ -2306,10 +1677,6 @@ Exit: if ( p ) { - _bdf_list_done( &p->list ); - - memory = extmemory; - FT_FREE( p->glyph_name ); FT_FREE( p ); } @@ -2319,8 +1686,6 @@ Fail: bdf_free_font( p->font ); - memory = extmemory; - FT_FREE( p->font ); goto Exit; @@ -2336,7 +1701,7 @@ FT_Memory memory; - if ( font == 0 ) + if ( font == NULL ) return; memory = font->memory; @@ -2346,7 +1711,7 @@ /* Free up the internal hash table of property names. */ if ( font->internal ) { - ft_hash_str_free( (FT_Hash)font->internal, memory ); + ft_hash_str_free( font->internal, memory ); FT_FREE( font->internal ); } @@ -2386,11 +1751,7 @@ /* 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 ); @@ -2405,12 +1766,12 @@ size_t* propid; - if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) + if ( font == NULL || font->props_size == 0 || name == NULL || *name == 0 ) return 0; - propid = ft_hash_str_lookup( name, (FT_Hash)font->internal ); + propid = ft_hash_str_lookup( name, font->internal ); - return propid ? ( font->props + *propid ) : 0; + return propid ? ( font->props + *propid ) : NULL; } diff --git a/src/thirdparty/freetype2/src/bzip2/ftbzip2.c b/src/thirdparty/freetype2/src/bzip2/ftbzip2.c index 1fda59b60..16d158d72 100644 --- a/src/thirdparty/freetype2/src/bzip2/ftbzip2.c +++ b/src/thirdparty/freetype2/src/bzip2/ftbzip2.c @@ -8,7 +8,7 @@ * parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2010-2019 by + * Copyright (C) 2010-2025 by * Joel Klinghed. * * based on `src/gzip/ftgzip.c' @@ -22,15 +22,14 @@ */ -#include -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H -#include FT_BZIP2_H +#include +#include +#include +#include #include FT_CONFIG_STANDARD_LIBRARY_H -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -38,7 +37,7 @@ #define FT_ERR_PREFIX Bzip2_Err_ #define FT_ERR_BASE FT_Mod_Err_Bzip2 -#include FT_ERRORS_H +#include #ifdef FT_CONFIG_OPTION_USE_BZIP2 @@ -58,28 +57,34 @@ /* it is better to use FreeType memory routines instead of raw 'malloc/free' */ - typedef void *(* alloc_func)(void*, int, int); - typedef void (* free_func)(void*, void*); + typedef void* (*alloc_func)( void*, int, int ); + typedef void (*free_func) ( void*, void* ); + static void* - ft_bzip2_alloc( FT_Memory memory, - int items, - int size ) + ft_bzip2_alloc( void* memory_, /* FT_Memory */ + int items, + int size ) { + FT_Memory memory = (FT_Memory)memory_; + FT_ULong sz = (FT_ULong)size * (FT_ULong)items; FT_Error error; FT_Pointer p = NULL; - (void)FT_ALLOC( p, sz ); + FT_MEM_QALLOC( p, sz ); return p; } static void - ft_bzip2_free( FT_Memory memory, - void* address ) + ft_bzip2_free( void* memory_, /* FT_Memory */ + void* address ) { + FT_Memory memory = (FT_Memory)memory_; + + FT_MEM_FREE( address ); } @@ -103,10 +108,11 @@ FT_Byte input[FT_BZIP2_BUFFER_SIZE]; /* input read buffer */ - FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ - FT_ULong pos; /* position in output */ + FT_Byte buffer[FT_BZIP2_BUFFER_SIZE]; /* output buffer */ + FT_ULong pos; /* position in output */ FT_Byte* cursor; FT_Byte* limit; + FT_Bool reset; /* reset before next read */ } FT_BZip2FileRec, *FT_BZip2File; @@ -154,6 +160,7 @@ zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; zip->cursor = zip->limit; zip->pos = 0; + zip->reset = 0; /* check .bz2 header */ { @@ -168,8 +175,8 @@ } /* initialize bzlib */ - bzstream->bzalloc = (alloc_func)ft_bzip2_alloc; - bzstream->bzfree = (free_func) ft_bzip2_free; + bzstream->bzalloc = ft_bzip2_alloc; + bzstream->bzfree = ft_bzip2_free; bzstream->opaque = zip->memory; bzstream->avail_in = 0; @@ -229,6 +236,7 @@ zip->limit = zip->buffer + FT_BZIP2_BUFFER_SIZE; zip->cursor = zip->limit; zip->pos = 0; + zip->reset = 0; BZ2_bzDecompressInit( bzstream, 0, 0 ); } @@ -303,18 +311,23 @@ err = BZ2_bzDecompress( bzstream ); - if ( err == BZ_STREAM_END ) + if ( err != BZ_OK ) { - zip->limit = (FT_Byte*)bzstream->next_out; - if ( zip->limit == zip->cursor ) - error = FT_THROW( Invalid_Stream_Operation ); - break; - } - else if ( err != BZ_OK ) - { - zip->limit = zip->cursor; - error = FT_THROW( Invalid_Stream_Operation ); - break; + zip->reset = 1; + + if ( err == BZ_STREAM_END ) + { + zip->limit = (FT_Byte*)bzstream->next_out; + if ( zip->limit == zip->cursor ) + error = FT_THROW( Invalid_Stream_Operation ); + break; + } + else + { + zip->limit = zip->cursor; + error = FT_THROW( Invalid_Stream_Operation ); + break; + } } } @@ -328,12 +341,13 @@ FT_ULong count ) { FT_Error error = FT_Err_Ok; - FT_ULong delta; for (;;) { - delta = (FT_ULong)( zip->limit - zip->cursor ); + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + if ( delta >= count ) delta = count; @@ -363,9 +377,9 @@ 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 ) + /* Reset inflate stream if seeking backwards or bzip reported an error. */ + /* Yes, that is not too efficient, but it saves memory :-) */ + if ( pos < zip->pos || zip->reset ) { error = ft_bzip2_file_reset( zip ); if ( error ) @@ -495,7 +509,7 @@ stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; - stream->base = 0; + stream->base = NULL; stream->read = ft_bzip2_stream_io; stream->close = ft_bzip2_stream_close; diff --git a/src/thirdparty/freetype2/src/cache/ftcbasic.c b/src/thirdparty/freetype2/src/cache/ftcbasic.c index a473585eb..e7cf2605f 100644 --- a/src/thirdparty/freetype2/src/cache/ftcbasic.c +++ b/src/thirdparty/freetype2/src/cache/ftcbasic.c @@ -4,7 +4,7 @@ * * The FreeType basic cache interface (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_CACHE_H +#include +#include +#include #include "ftcglyph.h" #include "ftcimage.h" #include "ftcsbits.h" @@ -27,6 +26,7 @@ #include "ftccback.h" #include "ftcerror.h" +#undef FT_COMPONENT #define FT_COMPONENT cache @@ -37,7 +37,7 @@ typedef struct FTC_BasicAttrRec_ { FTC_ScalerRec scaler; - FT_UInt load_flags; + FT_Int32 load_flags; } FTC_BasicAttrRec, *FTC_BasicAttrs; @@ -45,8 +45,9 @@ 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 ) +#define FTC_BASIC_ATTR_HASH( a ) \ + ( FTC_SCALER_HASH( &(a)->scaler ) + \ + (FT_Offset)( 31 * (a)->load_flags ) ) typedef struct FTC_BasicQueryRec_ @@ -109,13 +110,18 @@ if ( error || !face ) return result; +#ifdef FT_DEBUG_LEVEL_TRACE if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs ) + { FT_TRACE1(( "ftc_basic_family_get_count:" - " too large number of glyphs in this face, truncated\n", + " the number of glyphs in this face is %ld,\n", face->num_glyphs )); + FT_TRACE1(( " " + " which is too much and thus truncated\n" )); + } +#endif - if ( !error ) - result = (FT_UInt)face->num_glyphs; + result = (FT_UInt)face->num_glyphs; return result; } @@ -138,10 +144,9 @@ FT_Face face = size->face; - error = FT_Load_Glyph( - face, - gindex, - (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER ); + error = FT_Load_Glyph( face, + gindex, + family->attrs.load_flags | FT_LOAD_RENDER ); if ( !error ) *aface = face; } @@ -171,13 +176,12 @@ { face = size->face; - error = FT_Load_Glyph( face, - gindex, - (FT_Int)family->attrs.load_flags ); + 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 ) + face->glyph->format == FT_GLYPH_FORMAT_OUTLINE || + face->glyph->format == FT_GLYPH_FORMAT_SVG ) { /* ok, copy it */ FT_Glyph glyph; @@ -240,7 +244,6 @@ ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ - NULL, /* FTC_MruNode_ResetFunc node_reset */ NULL /* FTC_MruNode_DoneFunc node_done */ }, @@ -287,40 +290,24 @@ FT_Glyph *aglyph, FTC_Node *anode ) { - FTC_BasicQueryRec query; - FTC_Node node = 0; /* make compiler happy */ FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ FT_Offset hash; - /* some argument checks are delayed to `FTC_Cache_Lookup' */ + /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !aglyph ) - { - error = FT_THROW( Invalid_Argument ); - goto Exit; - } + return FT_THROW( Invalid_Argument ); *aglyph = NULL; if ( anode ) - *anode = NULL; - - /* - * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', - * but public `FT_ImageType->flags' is of type `FT_Int32'. - * - * On 16bit systems, higher bits of type->flags cannot be handled. - */ -#if 0xFFFFFFFFUL > FT_UINT_MAX - if ( (type->flags & (FT_ULong)FT_UINT_MAX) ) - FT_TRACE1(( "FTC_ImageCache_Lookup:" - " higher bits in load_flags 0x%x are dropped\n", - (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); -#endif + *anode = NULL; query.attrs.scaler.face_id = type->face_id; query.attrs.scaler.width = type->width; query.attrs.scaler.height = type->height; - query.attrs.load_flags = (FT_UInt)type->flags; + query.attrs.load_flags = type->flags; query.attrs.scaler.pixel = 1; query.attrs.scaler.x_res = 0; /* make compilers happy */ @@ -328,10 +315,10 @@ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; -#if 1 /* inlining is about 50% faster! */ +#ifdef FTC_INLINE /* inlining is about 50% faster! */ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, - FTC_GNode_Compare, + ftc_gnode_compare, hash, gindex, &query, node, @@ -353,7 +340,6 @@ } } - Exit: return error; } @@ -368,44 +354,41 @@ FT_Glyph *aglyph, FTC_Node *anode ) { - FTC_BasicQueryRec query; - FTC_Node node = 0; /* make compiler happy */ FT_Error error; + FTC_BasicQueryRec query; + FTC_Node node = NULL; /* make compiler happy */ FT_Offset hash; - /* some argument checks are delayed to `FTC_Cache_Lookup' */ + /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !aglyph || !scaler ) - { - error = FT_THROW( Invalid_Argument ); - goto Exit; - } + return FT_THROW( Invalid_Argument ); *aglyph = NULL; if ( anode ) - *anode = NULL; + *anode = NULL; /* - * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', * but public `FT_Face->face_flags' is of type `FT_Long'. * * On long > int systems, higher bits of load_flags cannot be handled. */ -#if FT_ULONG_MAX > FT_UINT_MAX - if ( load_flags > FT_UINT_MAX ) +#if FT_ULONG_MAX > 0xFFFFFFFFUL + if ( load_flags > 0xFFFFFFFFUL ) FT_TRACE1(( "FTC_ImageCache_LookupScaler:" - " higher bits in load_flags 0x%x are dropped\n", - load_flags & ~((FT_ULong)FT_UINT_MAX) )); + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~0xFFFFFFFFUL )); #endif query.attrs.scaler = scaler[0]; - query.attrs.load_flags = (FT_UInt)load_flags; + query.attrs.load_flags = (FT_Int32)load_flags; hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex; FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, - FTC_GNode_Compare, + ftc_gnode_compare, hash, gindex, &query, node, @@ -421,7 +404,6 @@ } } - Exit: return error; } @@ -439,7 +421,6 @@ sizeof ( FTC_BasicFamilyRec ), ftc_basic_family_compare, /* FTC_MruNode_CompareFunc node_compare */ ftc_basic_family_init, /* FTC_MruNode_InitFunc node_init */ - NULL, /* FTC_MruNode_ResetFunc node_reset */ NULL /* FTC_MruNode_DoneFunc node_done */ }, @@ -489,36 +470,22 @@ { FT_Error error; FTC_BasicQueryRec query; - FTC_Node node = 0; /* make compiler happy */ + FTC_Node node = NULL; /* make compiler happy */ FT_Offset hash; - if ( anode ) - *anode = NULL; - /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !ansbit ) return FT_THROW( Invalid_Argument ); *ansbit = NULL; - - /* - * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', - * but public `FT_ImageType->flags' is of type `FT_Int32'. - * - * On 16bit systems, higher bits of type->flags cannot be handled. - */ -#if 0xFFFFFFFFUL > FT_UINT_MAX - if ( (type->flags & (FT_ULong)FT_UINT_MAX) ) - FT_TRACE1(( "FTC_ImageCache_Lookup:" - " higher bits in load_flags 0x%x are dropped\n", - (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); -#endif + if ( anode ) + *anode = NULL; query.attrs.scaler.face_id = type->face_id; query.attrs.scaler.width = type->width; query.attrs.scaler.height = type->height; - query.attrs.load_flags = (FT_UInt)type->flags; + query.attrs.load_flags = type->flags; query.attrs.scaler.pixel = 1; query.attrs.scaler.x_res = 0; /* make compilers happy */ @@ -528,10 +495,10 @@ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex / FTC_SBIT_ITEMS_PER_NODE; -#if 1 /* inlining is about 50% faster! */ +#ifdef FTC_INLINE /* inlining is about 50% faster! */ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, - FTC_SNode_Compare, + ftc_snode_compare, hash, gindex, &query, node, @@ -572,34 +539,33 @@ { FT_Error error; FTC_BasicQueryRec query; - FTC_Node node = 0; /* make compiler happy */ + FTC_Node node = NULL; /* make compiler happy */ FT_Offset hash; - if ( anode ) - *anode = NULL; - /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !ansbit || !scaler ) - return FT_THROW( Invalid_Argument ); + return FT_THROW( Invalid_Argument ); *ansbit = NULL; + if ( anode ) + *anode = NULL; /* - * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', + * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32', * but public `FT_Face->face_flags' is of type `FT_Long'. * * On long > int systems, higher bits of load_flags cannot be handled. */ -#if FT_ULONG_MAX > FT_UINT_MAX - if ( load_flags > FT_UINT_MAX ) +#if FT_ULONG_MAX > 0xFFFFFFFFUL + if ( load_flags > 0xFFFFFFFFUL ) FT_TRACE1(( "FTC_ImageCache_LookupScaler:" - " higher bits in load_flags 0x%x are dropped\n", - load_flags & ~((FT_ULong)FT_UINT_MAX) )); + " higher bits in load_flags 0x%lx are dropped\n", + load_flags & ~0xFFFFFFFFUL )); #endif query.attrs.scaler = scaler[0]; - query.attrs.load_flags = (FT_UInt)load_flags; + query.attrs.load_flags = (FT_Int32)load_flags; /* beware, the hash must be the same for all glyph ranges! */ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + @@ -607,7 +573,7 @@ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, - FTC_SNode_Compare, + ftc_snode_compare, hash, gindex, &query, node, diff --git a/src/thirdparty/freetype2/src/cache/ftccache.c b/src/thirdparty/freetype2/src/cache/ftccache.c index f38ca44dd..91227147a 100644 --- a/src/thirdparty/freetype2/src/cache/ftccache.c +++ b/src/thirdparty/freetype2/src/cache/ftccache.c @@ -4,7 +4,7 @@ * * The FreeType internal cache interface (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include #include "ftcmanag.h" -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H +#include +#include #include "ftccback.h" #include "ftcerror.h" @@ -91,15 +90,14 @@ ftc_get_top_node_for_hash( FTC_Cache cache, FT_Offset hash ) { - FTC_Node* pnode; FT_Offset idx; idx = hash & cache->mask; - if ( idx < cache->p ) - idx = hash & ( 2 * cache->mask + 1 ); - pnode = cache->buckets + idx; - return pnode; + if ( idx >= cache->p ) + idx = hash & ( cache->mask >> 1 ); + + return cache->buckets + idx; } #endif /* !FTC_INLINE */ @@ -115,12 +113,12 @@ for (;;) { FTC_Node node, *pnode; - FT_UFast p = cache->p; - FT_UFast mask = cache->mask; - FT_UFast count = mask + p + 1; /* number of buckets */ + FT_UFast p = cache->p; + FT_UFast size = cache->mask + 1; /* available size */ + FT_UFast half = size >> 1; - /* do we need to shrink the buckets array? */ + /* do we need to expand the buckets array? */ if ( cache->slack < 0 ) { FTC_Node new_list = NULL; @@ -129,20 +127,22 @@ /* try to expand the buckets array _before_ splitting * the bucket lists */ - if ( p >= mask ) + if ( p == size ) { 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 ) ) + if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) ) break; + + cache->mask = 2 * size - 1; + half = size; } - /* split a single bucket */ - pnode = cache->buckets + p; + /* the bucket to split */ + pnode = cache->buckets + p - half; for (;;) { @@ -150,7 +150,7 @@ if ( !node ) break; - if ( node->hash & ( mask + 1 ) ) + if ( node->hash & half ) { *pnode = node->link; node->link = new_list; @@ -160,56 +160,50 @@ pnode = &node->link; } - cache->buckets[p + mask + 1] = new_list; + cache->buckets[p] = new_list; cache->slack += FTC_HASH_MAX_LOAD; + cache->p = p + 1; - if ( p >= mask ) - { - cache->mask = 2 * mask + 1; - cache->p = 0; - } - else - cache->p = p + 1; + FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n", + cache->index, cache->p )); } - /* do we need to expand the buckets array? */ - else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD ) + /* do we need to shrink the buckets array? */ + else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD ) { - FT_UFast old_index = p + mask; - FTC_Node* pold; + FTC_Node old_list = cache->buckets[--p]; - if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE ) + if ( p < FTC_HASH_INITIAL_SIZE ) break; - if ( p == 0 ) + if ( p == half ) { 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 ) ) + if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) ) break; - cache->mask >>= 1; - p = cache->mask; + cache->mask = half - 1; } - else - p--; - pnode = cache->buckets + p; + /* the bucket to merge */ + pnode = cache->buckets + p - half; + while ( *pnode ) pnode = &(*pnode)->link; - pold = cache->buckets + old_index; - *pnode = *pold; - *pold = NULL; + *pnode = old_list; cache->slack -= FTC_HASH_MAX_LOAD; cache->p = p; + + FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n", + cache->index, cache->p )); } /* otherwise, the hash table is balanced */ @@ -241,7 +235,7 @@ if ( node == node0 ) break; - pnode = &(*pnode)->link; + pnode = &node->link; } *pnode = node0->link; @@ -309,7 +303,7 @@ #if 0 /* check, just in case of general corruption :-) */ if ( manager->num_nodes == 0 ) - FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%d)\n", + FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%u)\n", manager->num_nodes )); #endif } @@ -324,13 +318,6 @@ /*************************************************************************/ - 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 ) { @@ -338,30 +325,38 @@ FT_Error error; - cache->p = 0; + cache->p = FTC_HASH_INITIAL_SIZE; 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 ); + FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE ); return error; } - static void - FTC_Cache_Clear( FTC_Cache cache ) + FT_LOCAL_DEF( FT_Error ) + FTC_Cache_Init( FTC_Cache cache ) { - if ( cache && cache->buckets ) + return ftc_cache_init( cache ); + } + + + FT_LOCAL_DEF( void ) + ftc_cache_done( FTC_Cache cache ) + { + FT_Memory memory = cache->memory; + + + if ( cache->buckets ) { FTC_Manager manager = cache->manager; + FT_UFast count = cache->p; FT_UFast i; - FT_UFast count; - count = cache->p + cache->mask + 1; - for ( i = 0; i < count; i++ ) { - FTC_Node *pnode = cache->buckets + i, next, node = *pnode; + FTC_Node node = cache->buckets[i], next; while ( node ) @@ -378,30 +373,14 @@ cache->clazz.node_free( node, cache ); node = next; } - cache->buckets[i] = NULL; } - ftc_cache_resize( cache ); } - } + FT_FREE( cache->buckets ); - 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; - } + cache->p = 0; + cache->mask = 0; + cache->slack = 0; } @@ -418,7 +397,7 @@ FTC_Node node ) { node->hash = hash; - node->cache_index = (FT_UInt16)cache->index; + node->cache_index = (FT_UShort)cache->index; node->ref_count = 0; ftc_node_hash_link( node, cache ); @@ -460,7 +439,7 @@ { error = cache->clazz.node_new( &node, query, cache ); } - FTC_CACHE_TRYLOOP_END( NULL ); + FTC_CACHE_TRYLOOP_END( NULL ) if ( error ) node = NULL; @@ -529,7 +508,7 @@ goto NewNode; } else - pnode = &((*pnode)->link); + pnode = &(*pnode)->link; } } @@ -564,56 +543,40 @@ FTC_Cache_RemoveFaceID( FTC_Cache cache, FTC_FaceID face_id ) { - FT_UFast i, count; FTC_Manager manager = cache->manager; - FTC_Node frees = NULL; + FT_UFast count = cache->p; + FT_UFast i; - count = cache->p + cache->mask + 1; for ( i = 0; i < count; i++ ) { - FTC_Node* bucket = cache->buckets + i; - FTC_Node* pnode = bucket; + FTC_Node* pnode = cache->buckets + i; for (;;) { FTC_Node node = *pnode; - FT_Bool list_changed = FALSE; if ( !node ) break; - if ( cache->clazz.node_remove_faceid( node, face_id, - cache, &list_changed ) ) + if ( cache->clazz.node_remove_faceid( node, face_id, cache, NULL ) ) { - *pnode = node->link; - node->link = frees; - frees = node; + *pnode = 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++; } 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 ); } diff --git a/src/thirdparty/freetype2/src/cache/ftccache.h b/src/thirdparty/freetype2/src/cache/ftccache.h index 140ceadb1..20c2638e7 100644 --- a/src/thirdparty/freetype2/src/cache/ftccache.h +++ b/src/thirdparty/freetype2/src/cache/ftccache.h @@ -4,7 +4,7 @@ * * FreeType internal cache interface (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef FTCCACHE_H_ #define FTCCACHE_H_ - +#include #include "ftcmru.h" FT_BEGIN_HEADER @@ -72,11 +72,12 @@ FT_BEGIN_HEADER #define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next ) #define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev ) + /* address the hash table entries */ #ifdef FTC_INLINE -#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ - ( ( cache )->buckets + \ - ( ( ( ( hash ) & ( cache )->mask ) < ( cache )->p ) \ - ? ( ( hash ) & ( ( cache )->mask * 2 + 1 ) ) \ +#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \ + ( ( cache )->buckets + \ + ( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \ + ? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \ : ( ( hash ) & ( cache )->mask ) ) ) #else FT_LOCAL( FTC_Node* ) @@ -86,6 +87,10 @@ FT_BEGIN_HEADER ftc_get_top_node_for_hash( ( cache ), ( hash ) ) #endif + FT_LOCAL( void ) + ftc_node_destroy( FTC_Node node, + FTC_Manager manager ); + /*************************************************************************/ /*************************************************************************/ @@ -139,11 +144,13 @@ FT_BEGIN_HEADER } FTC_CacheClassRec; - /* each cache really implements a dynamic hash table to manage its nodes */ + /* each cache really implements a hash table to manage its nodes */ + /* the number of the table entries (buckets) can change dynamically */ + /* each bucket contains a linked lists of nodes for a given hash */ typedef struct FTC_CacheRec_ { - FT_UFast p; - FT_UFast mask; + FT_UFast p; /* hash table counter */ + FT_UFast mask; /* hash table index range */ FT_Long slack; FTC_Node* buckets; @@ -210,7 +217,7 @@ FT_BEGIN_HEADER #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); \ + FTC_Cache _cache = FTC_CACHE( cache ); \ FT_Offset _hash = (FT_Offset)(hash); \ FTC_Node_CompareFunc _nodcomp = (FTC_Node_CompareFunc)(nodecmp); \ FT_Bool _list_changed = FALSE; \ @@ -251,7 +258,7 @@ FT_BEGIN_HEADER goto NewNode_; \ } \ else \ - _pnode = &((*_pnode)->link); \ + _pnode = &(*_pnode)->link; \ } \ } \ \ diff --git a/src/thirdparty/freetype2/src/cache/ftccback.h b/src/thirdparty/freetype2/src/cache/ftccback.h index 9321bc3d4..1af2f17f9 100644 --- a/src/thirdparty/freetype2/src/cache/ftccback.h +++ b/src/thirdparty/freetype2/src/cache/ftccback.h @@ -4,7 +4,7 @@ * * Callback functions of the caching sub-system (specification only). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,14 +18,10 @@ #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" +#include +#include "ftccache.h" +FT_BEGIN_HEADER FT_LOCAL( void ) ftc_inode_free( FTC_Node inode, @@ -81,10 +77,7 @@ FT_LOCAL( void ) ftc_cache_done( FTC_Cache cache ); - FT_LOCAL( void ) - ftc_node_destroy( FTC_Node node, - FTC_Manager manager ); - +FT_END_HEADER #endif /* FTCCBACK_H_ */ diff --git a/src/thirdparty/freetype2/src/cache/ftccmap.c b/src/thirdparty/freetype2/src/cache/ftccmap.c index 76ba10e3e..e3a4ec242 100644 --- a/src/thirdparty/freetype2/src/cache/ftccmap.c +++ b/src/thirdparty/freetype2/src/cache/ftccmap.c @@ -4,7 +4,7 @@ * * FreeType CharMap cache (body) * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ */ -#include -#include FT_FREETYPE_H -#include FT_CACHE_H +#include +#include #include "ftcmanag.h" -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H +#include +#include +#include #include "ftccback.h" #include "ftcerror.h" @@ -117,7 +116,7 @@ FT_UInt nn; - if ( !FT_NEW( node ) ) + if ( !FT_QNEW( node ) ) { node->face_id = query->face_id; node->cmap_index = query->cmap_index; @@ -265,7 +264,7 @@ hash = FTC_CMAP_HASH( face_id, (FT_UInt)cmap_index, char_code ); -#if 1 +#ifdef FTC_INLINE FTC_CACHE_LOOKUP_CMP( cache, ftc_cmap_node_compare, hash, &query, node, error ); #else @@ -274,12 +273,11 @@ if ( error ) goto Exit; - FT_ASSERT( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first ) < - FTC_CMAP_INDICES_MAX ); + FT_ASSERT( char_code - FTC_CMAP_NODE( node )->first < + FTC_CMAP_INDICES_MAX ); /* something rotten can happen with rogue clients */ - if ( (FT_UInt)( char_code - FTC_CMAP_NODE( node )->first >= - FTC_CMAP_INDICES_MAX ) ) + if ( char_code - FTC_CMAP_NODE( node )->first >= FTC_CMAP_INDICES_MAX ) return 0; /* XXX: should return appropriate error */ gindex = FTC_CMAP_NODE( node )->indices[char_code - @@ -297,21 +295,19 @@ if ( error ) goto Exit; - if ( (FT_UInt)cmap_index < (FT_UInt)face->num_charmaps ) + if ( cmap_index < face->num_charmaps ) { - FT_CharMap old, cmap = NULL; + FT_CharMap old = face->charmap; + FT_CharMap cmap = face->charmaps[cmap_index]; - old = face->charmap; - cmap = face->charmaps[cmap_index]; - - if ( old != cmap && !no_cmap_change ) - FT_Set_Charmap( face, cmap ); + if ( !no_cmap_change ) + face->charmap = cmap; gindex = FT_Get_Char_Index( face, char_code ); - if ( old != cmap && !no_cmap_change ) - FT_Set_Charmap( face, old ); + if ( !no_cmap_change ) + face->charmap = old; } FTC_CMAP_NODE( node )->indices[char_code - diff --git a/src/thirdparty/freetype2/src/cache/ftcerror.h b/src/thirdparty/freetype2/src/cache/ftcerror.h index e2d641718..f714491c7 100644 --- a/src/thirdparty/freetype2/src/cache/ftcerror.h +++ b/src/thirdparty/freetype2/src/cache/ftcerror.h @@ -4,7 +4,7 @@ * * Caching sub-system error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef FTCERROR_H_ #define FTCERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX FTC_Err_ #define FT_ERR_BASE FT_Mod_Err_Cache -#include FT_ERRORS_H +#include #endif /* FTCERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/cache/ftcglyph.c b/src/thirdparty/freetype2/src/cache/ftcglyph.c index 2a0e97d4a..703c69d91 100644 --- a/src/thirdparty/freetype2/src/cache/ftcglyph.c +++ b/src/thirdparty/freetype2/src/cache/ftcglyph.c @@ -4,7 +4,7 @@ * * FreeType Glyph Image (FT_Glyph) cache (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_CACHE_H +#include +#include #include "ftcglyph.h" -#include FT_ERRORS_H +#include #include "ftccback.h" #include "ftcerror.h" @@ -80,20 +79,6 @@ } -#ifdef FTC_INLINE - - FT_LOCAL_DEF( FT_Bool ) - FTC_GNode_Compare( FTC_GNode gnode, - FTC_GQuery gquery, - FTC_Cache cache, - FT_Bool* list_changed ) - { - return ftc_gnode_compare( FTC_NODE( gnode ), gquery, - cache, list_changed ); - } - -#endif - /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -116,22 +101,22 @@ FT_LOCAL_DEF( FT_Error ) - ftc_gcache_init( FTC_Cache ftccache ) + ftc_gcache_init( FTC_Cache cache ) { - FTC_GCache cache = (FTC_GCache)ftccache; + FTC_GCache gcache = (FTC_GCache)cache; FT_Error error; - error = FTC_Cache_Init( FTC_CACHE( cache ) ); + error = FTC_Cache_Init( cache ); if ( !error ) { - FTC_GCacheClass clazz = (FTC_GCacheClass)FTC_CACHE( cache )->org_class; + FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class; - FTC_MruList_Init( &cache->families, + FTC_MruList_Init( &gcache->families, clazz->family_class, 0, /* no maximum here! */ cache, - FTC_CACHE( cache )->memory ); + cache->memory ); } return error; @@ -141,31 +126,31 @@ #if 0 FT_LOCAL_DEF( FT_Error ) - FTC_GCache_Init( FTC_GCache cache ) + FTC_GCache_Init( FTC_GCache gcache ) { - return ftc_gcache_init( FTC_CACHE( cache ) ); + return ftc_gcache_init( FTC_CACHE( gcache ) ); } #endif /* 0 */ FT_LOCAL_DEF( void ) - ftc_gcache_done( FTC_Cache ftccache ) + ftc_gcache_done( FTC_Cache cache ) { - FTC_GCache cache = (FTC_GCache)ftccache; + FTC_GCache gcache = (FTC_GCache)cache; - FTC_Cache_Done( (FTC_Cache)cache ); - FTC_MruList_Done( &cache->families ); + FTC_Cache_Done( cache ); + FTC_MruList_Done( &gcache->families ); } #if 0 FT_LOCAL_DEF( void ) - FTC_GCache_Done( FTC_GCache cache ) + FTC_GCache_Done( FTC_GCache gcache ) { - ftc_gcache_done( FTC_CACHE( cache ) ); + ftc_gcache_done( FTC_CACHE( gcache ) ); } #endif /* 0 */ @@ -184,7 +169,7 @@ #ifndef FTC_INLINE FT_LOCAL_DEF( FT_Error ) - FTC_GCache_Lookup( FTC_GCache cache, + FTC_GCache_Lookup( FTC_GCache gcache, FT_Offset hash, FT_UInt gindex, FTC_GQuery query, @@ -195,7 +180,7 @@ query->gindex = gindex; - FTC_MRULIST_LOOKUP( &cache->families, query, query->family, error ); + FTC_MRULIST_LOOKUP( &gcache->families, query, query->family, error ); if ( !error ) { FTC_Family family = query->family; @@ -205,10 +190,10 @@ /* out-of-memory condition occurs during glyph node initialization. */ family->num_nodes++; - error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, anode ); + error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode ); if ( --family->num_nodes == 0 ) - FTC_FAMILY_FREE( family, cache ); + FTC_FAMILY_FREE( family, FTC_CACHE( gcache ) ); } return error; } diff --git a/src/thirdparty/freetype2/src/cache/ftcglyph.h b/src/thirdparty/freetype2/src/cache/ftcglyph.h index 5a1f0e2a7..b728b636e 100644 --- a/src/thirdparty/freetype2/src/cache/ftcglyph.h +++ b/src/thirdparty/freetype2/src/cache/ftcglyph.h @@ -4,7 +4,7 @@ * * FreeType abstract glyph cache (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -58,14 +58,13 @@ * - 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_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 @@ -117,7 +116,6 @@ #define FTCGLYPH_H_ -#include #include "ftcmanag.h" @@ -141,8 +139,8 @@ FT_BEGIN_HEADER } FTC_FamilyRec, *FTC_Family; -#define FTC_FAMILY(x) ( (FTC_Family)(x) ) -#define FTC_FAMILY_P(x) ( (FTC_Family*)(x) ) +#define FTC_FAMILY( x ) ( (FTC_Family)(x) ) +#define FTC_FAMILY_P( x ) ( (FTC_Family*)(x) ) typedef struct FTC_GNodeRec_ @@ -180,19 +178,6 @@ FT_BEGIN_HEADER FT_UInt gindex, /* glyph index for node */ FTC_Family family ); -#ifdef FTC_INLINE - - /* 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, - FTC_Cache cache, - FT_Bool* list_changed ); - -#endif - /* call this function to clear a node's family -- this is necessary */ /* to implement the `node_remove_faceid' cache method correctly */ FT_LOCAL( void ) @@ -246,7 +231,7 @@ FT_BEGIN_HEADER #define FTC_GCACHE_CLASS( x ) ((FTC_GCacheClass)(x)) #define FTC_CACHE_GCACHE_CLASS( x ) \ - FTC_GCACHE_CLASS( FTC_CACHE(x)->org_class ) + FTC_GCACHE_CLASS( FTC_CACHE( x )->org_class ) #define FTC_CACHE_FAMILY_CLASS( x ) \ ( (FTC_MruListClass)FTC_CACHE_GCACHE_CLASS( x )->family_class ) diff --git a/src/thirdparty/freetype2/src/cache/ftcimage.c b/src/thirdparty/freetype2/src/cache/ftcimage.c index 9e64d51a2..05d393dcd 100644 --- a/src/thirdparty/freetype2/src/cache/ftcimage.c +++ b/src/thirdparty/freetype2/src/cache/ftcimage.c @@ -4,7 +4,7 @@ * * FreeType Image cache (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_CACHE_H +#include #include "ftcimage.h" -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_OBJECTS_H +#include +#include #include "ftccback.h" #include "ftcerror.h" @@ -35,11 +34,7 @@ FT_Memory memory = cache->memory; - if ( inode->glyph ) - { - FT_Done_Glyph( inode->glyph ); - inode->glyph = NULL; - } + FT_Done_Glyph( inode->glyph ); FTC_GNode_Done( FTC_GNODE( inode ), cache ); FT_FREE( inode ); @@ -65,7 +60,7 @@ FTC_INode inode = NULL; - if ( !FT_NEW( inode ) ) + if ( !FT_QNEW( inode ) ) { FTC_GNode gnode = FTC_GNODE( inode ); FTC_Family family = gquery->family; @@ -75,6 +70,7 @@ /* initialize its inner fields */ FTC_GNode_Init( gnode, gindex, family ); + inode->glyph = NULL; /* we will now load the glyph image */ error = clazz->family_load_glyph( family, gindex, cache, @@ -119,10 +115,9 @@ { case FT_GLYPH_FORMAT_BITMAP: { - FT_BitmapGlyph bitg; + FT_BitmapGlyph bitg = (FT_BitmapGlyph)glyph; - bitg = (FT_BitmapGlyph)glyph; size = bitg->bitmap.rows * (FT_Offset)FT_ABS( bitg->bitmap.pitch ) + sizeof ( *bitg ); } @@ -130,10 +125,9 @@ case FT_GLYPH_FORMAT_OUTLINE: { - FT_OutlineGlyph outg; + FT_OutlineGlyph outg = (FT_OutlineGlyph)glyph; - outg = (FT_OutlineGlyph)glyph; size = (FT_Offset)outg->outline.n_points * ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) + (FT_Offset)outg->outline.n_contours * sizeof ( FT_Short ) + diff --git a/src/thirdparty/freetype2/src/cache/ftcimage.h b/src/thirdparty/freetype2/src/cache/ftcimage.h index dcb101fab..8eb148262 100644 --- a/src/thirdparty/freetype2/src/cache/ftcimage.h +++ b/src/thirdparty/freetype2/src/cache/ftcimage.h @@ -4,7 +4,7 @@ * * FreeType Generic Image cache (specification) * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -36,8 +36,7 @@ #define FTCIMAGE_H_ -#include -#include FT_CACHE_H +#include #include "ftcglyph.h" FT_BEGIN_HEADER @@ -52,8 +51,8 @@ FT_BEGIN_HEADER } 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 +#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, @@ -73,7 +72,7 @@ FT_BEGIN_HEADER #define FTC_IFAMILY_CLASS( x ) ((FTC_IFamilyClass)(x)) #define FTC_CACHE_IFAMILY_CLASS( x ) \ - FTC_IFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS(x)->family_class ) + FTC_IFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) /* can be used as a @FTC_Node_FreeFunc */ diff --git a/src/thirdparty/freetype2/src/cache/ftcmanag.c b/src/thirdparty/freetype2/src/cache/ftcmanag.c index bd585968e..4bfb389bb 100644 --- a/src/thirdparty/freetype2/src/cache/ftcmanag.c +++ b/src/thirdparty/freetype2/src/cache/ftcmanag.c @@ -4,7 +4,7 @@ * * FreeType Cache Manager (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,14 +16,12 @@ */ -#include -#include FT_CACHE_H +#include #include "ftcmanag.h" -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_SIZES_H +#include +#include +#include -#include "ftccback.h" #include "ftcerror.h" @@ -87,12 +85,10 @@ FT_Pointer data ) { FTC_SizeNode node = (FTC_SizeNode)ftcnode; - FT_Size size = node->size; FT_UNUSED( data ); - if ( size ) - FT_Done_Size( size ); + FT_Done_Size( node->size ); } @@ -119,32 +115,21 @@ FT_Pointer ftcscaler, FT_Pointer ftcmanager ) { + FT_Error error; + FT_Size size; FTC_SizeNode node = (FTC_SizeNode)ftcnode; FTC_Scaler scaler = (FTC_Scaler)ftcscaler; FTC_Manager manager = (FTC_Manager)ftcmanager; - node->scaler = scaler[0]; + error = ftc_scaler_lookup_size( manager, scaler, &size ); + if ( !error ) + { + node->size = size; + 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 ); + return error; } @@ -155,7 +140,6 @@ ftc_size_node_compare, /* FTC_MruNode_CompareFunc node_compare */ ftc_size_node_init, /* FTC_MruNode_InitFunc node_init */ - ftc_size_node_reset, /* FTC_MruNode_ResetFunc node_reset */ ftc_size_node_done /* FTC_MruNode_DoneFunc node_done */ }; @@ -232,23 +216,25 @@ FT_Pointer ftcface_id, FT_Pointer ftcmanager ) { + FT_Error error; + FT_Face face; 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 ); + &face ); if ( !error ) { /* destroy initial size object; it will be re-created later */ - if ( node->face->size ) - FT_Done_Size( node->face->size ); + if ( face->size ) + FT_Done_Size( face->size ); + + node->face = face; + node->face_id = face_id; } return error; @@ -295,7 +281,6 @@ ftc_face_node_compare, /* FTC_MruNode_CompareFunc node_compare */ ftc_face_node_init, /* FTC_MruNode_InitFunc node_init */ - NULL, /* FTC_MruNode_ResetFunc node_reset */ ftc_face_node_done /* FTC_MruNode_DoneFunc node_done */ }; @@ -358,7 +343,7 @@ { FT_Error error; FT_Memory memory; - FTC_Manager manager = 0; + FTC_Manager manager = NULL; if ( !library ) @@ -369,7 +354,7 @@ memory = library->memory; - if ( FT_NEW( manager ) ) + if ( FT_QNEW( manager ) ) goto Exit; if ( max_faces == 0 ) @@ -384,6 +369,7 @@ manager->library = library; manager->memory = memory; manager->max_weight = max_bytes; + manager->cur_weight = 0; manager->request_face = requester; manager->request_data = req_data; @@ -400,6 +386,10 @@ manager, memory ); + manager->nodes_list = NULL; + manager->num_nodes = 0; + manager->num_caches = 0; + *amanager = manager; Exit: @@ -422,7 +412,7 @@ memory = manager->memory; /* now discard all caches */ - for (idx = manager->num_caches; idx-- > 0; ) + for ( idx = manager->num_caches; idx-- > 0; ) { FTC_Cache cache = manager->caches[idx]; @@ -431,18 +421,13 @@ { 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 ); } @@ -485,8 +470,8 @@ FTC_Cache cache = manager->caches[node->cache_index]; - if ( (FT_UInt)node->cache_index >= manager->num_caches ) - FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %ld\n", + if ( node->cache_index >= manager->num_caches ) + FT_TRACE0(( "FTC_Manager_Check: invalid node (cache index = %hu\n", node->cache_index )); else weight += cache->clazz.node_weight( node, cache ); @@ -516,7 +501,7 @@ if ( count != manager->num_nodes ) FT_TRACE0(( "FTC_Manager_Check:" - " invalid cache node count %d instead of %d\n", + " invalid cache node count %u instead of %u\n", manager->num_nodes, count )); } } @@ -533,7 +518,7 @@ FT_LOCAL_DEF( void ) FTC_Manager_Compress( FTC_Manager manager ) { - FTC_Node node, first; + FTC_Node node, prev, first; if ( !manager ) @@ -544,7 +529,7 @@ #ifdef FT_DEBUG_ERROR FTC_Manager_Check( manager ); - FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %d\n", + FT_TRACE0(( "compressing, weight = %ld, max = %ld, nodes = %u\n", manager->cur_weight, manager->max_weight, manager->num_nodes )); #endif @@ -553,20 +538,16 @@ return; /* go to last node -- it's a circular list */ - node = FTC_NODE_PREV( first ); + prev = FTC_NODE_PREV( first ); do { - FTC_Node prev; - - - prev = ( node == first ) ? NULL : FTC_NODE_PREV( node ); + node = prev; + prev = FTC_NODE_PREV( node ); if ( node->ref_count <= 0 ) ftc_node_destroy( node, manager ); - node = prev; - - } while ( node && manager->cur_weight > manager->max_weight ); + } while ( node != first && manager->cur_weight > manager->max_weight ); } @@ -594,7 +575,7 @@ goto Exit; } - if ( !FT_ALLOC( cache, clazz->cache_size ) ) + if ( !FT_QALLOC( cache, clazz->cache_size ) ) { cache->manager = manager; cache->memory = memory; @@ -629,20 +610,20 @@ FT_UInt count ) { FTC_Node first = manager->nodes_list; - FTC_Node node; - FT_UInt result; + FTC_Node prev, node; + FT_UInt result = 0; /* try to remove `count' nodes from the list */ - if ( !first ) /* empty list! */ - return 0; + if ( !first || !count ) + return result; - /* go to last node - it's a circular list */ - node = FTC_NODE_PREV(first); - for ( result = 0; result < count; ) + /* go to last node -- it's a circular list */ + prev = FTC_NODE_PREV( first ); + do { - FTC_Node prev = FTC_NODE_PREV( node ); - + node = prev; + prev = FTC_NODE_PREV( node ); /* don't touch locked nodes */ if ( node->ref_count <= 0 ) @@ -650,13 +631,9 @@ ftc_node_destroy( node, manager ); result++; } + } while ( node != first && result < count ); - if ( node == first ) - break; - - node = prev; - } - return result; + return result; } @@ -690,9 +667,9 @@ FTC_Node_Unref( FTC_Node node, FTC_Manager manager ) { - if ( node && - manager && - (FT_UInt)node->cache_index < manager->num_caches ) + if ( node && + manager && + node->cache_index < manager->num_caches ) node->ref_count--; } diff --git a/src/thirdparty/freetype2/src/cache/ftcmanag.h b/src/thirdparty/freetype2/src/cache/ftcmanag.h index 60c66c8fc..c691aebb3 100644 --- a/src/thirdparty/freetype2/src/cache/ftcmanag.h +++ b/src/thirdparty/freetype2/src/cache/ftcmanag.h @@ -4,7 +4,7 @@ * * FreeType Cache Manager (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -63,8 +63,7 @@ #define FTCMANAG_H_ -#include -#include FT_CACHE_H +#include #include "ftcmru.h" #include "ftccache.h" diff --git a/src/thirdparty/freetype2/src/cache/ftcmru.c b/src/thirdparty/freetype2/src/cache/ftcmru.c index 18a7b8005..2a5f2f3aa 100644 --- a/src/thirdparty/freetype2/src/cache/ftcmru.c +++ b/src/thirdparty/freetype2/src/cache/ftcmru.c @@ -4,7 +4,7 @@ * * FreeType MRU support (body). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_CACHE_H +#include #include "ftcmru.h" -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H +#include +#include #include "ftcerror.h" @@ -239,50 +238,43 @@ { FT_Error error; FTC_MruNode node = NULL; + FTC_MruNode prev = NULL; 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 ) ) + /* zero new node in case of node_init failure */ + if ( FT_ALLOC( node, list->clazz.node_size ) ) goto Exit; error = list->clazz.node_init( node, key, list->data ); if ( error ) - goto Fail; + { + prev = node; + node = NULL; + + goto Clean; + } + else if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) + prev = list->nodes->prev; FTC_MruNode_Prepend( &list->nodes, node ); list->num_nodes++; + if ( !prev ) + goto Exit; + + FTC_MruNode_Remove( &list->nodes, prev ); + list->num_nodes--; + + Clean: + if ( list->clazz.node_done ) + list->clazz.node_done( prev, list->data ); + + FT_FREE( prev ); + Exit: *anode = node; return error; - - Fail: - if ( list->clazz.node_done ) - list->clazz.node_done( node, list->data ); - - FT_FREE( node ); - goto Exit; } @@ -308,18 +300,16 @@ FTC_MruList_Remove( FTC_MruList list, FTC_MruNode node ) { + FT_Memory memory = list->memory; + + 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 ); - - if ( list->clazz.node_done ) - list->clazz.node_done( node, list->data ); - - FT_FREE( node ); - } + FT_FREE( node ); } @@ -328,29 +318,23 @@ FTC_MruNode_CompareFunc selection, FT_Pointer key ) { - FTC_MruNode first, node, next; + FTC_MruNode first = list->nodes; + FTC_MruNode prev, node; - first = list->nodes; - while ( first && ( !selection || selection( first, key ) ) ) + if ( !first || !selection ) + return; + + prev = first->prev; + do { - FTC_MruList_Remove( list, first ); - first = list->nodes; - } + node = prev; + prev = node->prev; - if ( first ) - { - node = first->next; - while ( node != first ) - { - next = node->next; + if ( selection( node, key ) ) + FTC_MruList_Remove( list, node ); - if ( selection( node, key ) ) - FTC_MruList_Remove( list, node ); - - node = next; - } - } + } while ( node != first ); } diff --git a/src/thirdparty/freetype2/src/cache/ftcmru.h b/src/thirdparty/freetype2/src/cache/ftcmru.h index 58721ed34..18e7a840e 100644 --- a/src/thirdparty/freetype2/src/cache/ftcmru.h +++ b/src/thirdparty/freetype2/src/cache/ftcmru.h @@ -4,7 +4,7 @@ * * Simple MRU list-cache (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -44,8 +44,8 @@ #define FTCMRU_H_ -#include -#include FT_FREETYPE_H +#include +#include #ifdef FREETYPE_H #error "freetype.h of FreeType 1 has been loaded!" @@ -95,11 +95,6 @@ FT_BEGIN_HEADER 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 ); @@ -111,7 +106,6 @@ FT_BEGIN_HEADER FTC_MruNode_CompareFunc node_compare; FTC_MruNode_InitFunc node_init; - FTC_MruNode_ResetFunc node_reset; FTC_MruNode_DoneFunc node_done; } FTC_MruListClassRec; diff --git a/src/thirdparty/freetype2/src/cache/ftcsbits.c b/src/thirdparty/freetype2/src/cache/ftcsbits.c index 06b46c896..6857f82b4 100644 --- a/src/thirdparty/freetype2/src/cache/ftcsbits.c +++ b/src/thirdparty/freetype2/src/cache/ftcsbits.c @@ -4,7 +4,7 @@ * * FreeType sbits manager (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_CACHE_H +#include #include "ftcsbits.h" -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_ERRORS_H +#include +#include +#include #include "ftccback.h" #include "ftcerror.h" @@ -53,11 +52,8 @@ pitch = -pitch; size = (FT_ULong)pitch * bitmap->rows; - if ( !size ) - return FT_Err_Ok; - if ( !FT_ALLOC( sbit->buffer, size ) ) - FT_MEM_COPY( sbit->buffer, bitmap->buffer, size ); + FT_MEM_DUP( sbit->buffer, bitmap->buffer, size ); return error; } @@ -109,13 +105,12 @@ 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 ) + if ( gindex - gnode->gindex >= snode->count ) { FT_ERROR(( "ftc_snode_load: invalid glyph index" )); return FT_THROW( Invalid_Argument ); @@ -124,8 +119,6 @@ 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; @@ -144,12 +137,13 @@ goto BadGlyph; } - /* Check whether our values fit into 8-bit containers! */ + /* Check whether our values fit into 8/16-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, (FT_Int) temp == (FT_Int) d ) #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)d ) +#define CHECK_SHRT( d ) ( temp = (FT_Short)d, (FT_Int)temp == (FT_Int) d ) /* horizontal advance in pixels */ xadvance = ( slot->advance.x + 32 ) >> 6; @@ -157,7 +151,7 @@ if ( !CHECK_BYTE( bitmap->rows ) || !CHECK_BYTE( bitmap->width ) || - !CHECK_CHAR( bitmap->pitch ) || + !CHECK_SHRT( bitmap->pitch ) || !CHECK_CHAR( slot->bitmap_left ) || !CHECK_CHAR( slot->bitmap_top ) || !CHECK_CHAR( xadvance ) || @@ -170,16 +164,25 @@ sbit->width = (FT_Byte)bitmap->width; sbit->height = (FT_Byte)bitmap->rows; - sbit->pitch = (FT_Char)bitmap->pitch; + sbit->pitch = (FT_Short)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); + 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 ); + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + /* take the bitmap ownership */ + sbit->buffer = bitmap->buffer; + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + else + { + /* copy the bitmap into a new buffer -- ignore error */ + error = ftc_sbit_copy_bitmap( sbit, bitmap, manager->memory ); + } /* now, compute size */ if ( asize ) @@ -229,7 +232,7 @@ goto Exit; } - if ( !FT_NEW( snode ) ) + if ( !FT_QNEW( snode ) ) { FT_UInt count, start; @@ -244,7 +247,9 @@ snode->count = count; for ( node_count = 0; node_count < count; node_count++ ) { - snode->sbits[node_count].width = 255; + snode->sbits[node_count].width = 255; + snode->sbits[node_count].height = 0; + snode->sbits[node_count].buffer = NULL; } error = ftc_snode_load( snode, @@ -336,10 +341,10 @@ FT_Bool result; - if (list_changed) + if ( list_changed ) *list_changed = FALSE; - result = FT_BOOL( gnode->family == gquery->family && - (FT_UInt)( gindex - gnode->gindex ) < snode->count ); + result = FT_BOOL( gnode->family == gquery->family && + gindex - gnode->gindex < snode->count ); if ( result ) { /* check if we need to load the glyph bitmap now */ @@ -391,7 +396,7 @@ { error = ftc_snode_load( snode, cache->manager, gindex, &size ); } - FTC_CACHE_TRYLOOP_END( list_changed ); + FTC_CACHE_TRYLOOP_END( list_changed ) ftcsnode->ref_count--; /* unlock the node */ @@ -405,19 +410,4 @@ return result; } - -#ifdef FTC_INLINE - - FT_LOCAL_DEF( FT_Bool ) - FTC_SNode_Compare( FTC_SNode snode, - FTC_GQuery gquery, - FTC_Cache cache, - FT_Bool* list_changed ) - { - return ftc_snode_compare( FTC_NODE( snode ), gquery, - cache, list_changed ); - } - -#endif - /* END */ diff --git a/src/thirdparty/freetype2/src/cache/ftcsbits.h b/src/thirdparty/freetype2/src/cache/ftcsbits.h index f1b71c283..20ccb13b7 100644 --- a/src/thirdparty/freetype2/src/cache/ftcsbits.h +++ b/src/thirdparty/freetype2/src/cache/ftcsbits.h @@ -4,7 +4,7 @@ * * A small-bitmap cache (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTCSBITS_H_ -#include -#include FT_CACHE_H +#include #include "ftcglyph.h" @@ -62,7 +61,7 @@ FT_BEGIN_HEADER typedef const FTC_SFamilyClassRec* FTC_SFamilyClass; -#define FTC_SFAMILY_CLASS( x ) ((FTC_SFamilyClass)(x)) +#define FTC_SFAMILY_CLASS( x ) ( (FTC_SFamilyClass)(x) ) #define FTC_CACHE_SFAMILY_CLASS( x ) \ FTC_SFAMILY_CLASS( FTC_CACHE_GCACHE_CLASS( x )->family_class ) @@ -82,17 +81,6 @@ FT_BEGIN_HEADER FTC_SNode_Weight( FTC_SNode inode ); #endif - -#ifdef FTC_INLINE - - FT_LOCAL( FT_Bool ) - FTC_SNode_Compare( FTC_SNode snode, - FTC_GQuery gquery, - FTC_Cache cache, - FT_Bool* list_changed); - -#endif - /* */ FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/cff/cffcmap.c b/src/thirdparty/freetype2/src/cff/cffcmap.c index 15cc94caf..cb69abdb9 100644 --- a/src/thirdparty/freetype2/src/cff/cffcmap.c +++ b/src/thirdparty/freetype2/src/cff/cffcmap.c @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,8 +16,7 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include #include "cffcmap.h" #include "cffload.h" @@ -33,9 +32,10 @@ /*************************************************************************/ FT_CALLBACK_DEF( FT_Error ) - cff_cmap_encoding_init( CFF_CMapStd cmap, - FT_Pointer pointer ) + cff_cmap_encoding_init( FT_CMap cmap, + FT_Pointer pointer ) { + CFF_CMapStd cffcmap = (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; @@ -43,63 +43,56 @@ FT_UNUSED( pointer ); - cmap->gids = encoding->codes; + cffcmap->gids = encoding->codes; return 0; } FT_CALLBACK_DEF( void ) - cff_cmap_encoding_done( CFF_CMapStd cmap ) + cff_cmap_encoding_done( FT_CMap cmap ) { - cmap->gids = NULL; + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + + + cffcmap->gids = NULL; } FT_CALLBACK_DEF( FT_UInt ) - cff_cmap_encoding_char_index( CFF_CMapStd cmap, - FT_UInt32 char_code ) + cff_cmap_encoding_char_index( FT_CMap cmap, + FT_UInt32 char_code ) { - FT_UInt result = 0; + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; if ( char_code < 256 ) - result = cmap->gids[char_code]; + result = cffcmap->gids[char_code]; return result; } - FT_CALLBACK_DEF( FT_UInt32 ) - cff_cmap_encoding_char_next( CFF_CMapStd cmap, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_encoding_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) { - FT_UInt result = 0; - FT_UInt32 char_code = *pchar_code; + CFF_CMapStd cffcmap = (CFF_CMapStd)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; - *pchar_code = 0; - - if ( char_code < 255 ) + while ( char_code < 255 ) { - FT_UInt code = (FT_UInt)(char_code + 1); - - - for (;;) + result = cffcmap->gids[++char_code]; + if ( result ) { - if ( code >= 256 ) - break; - - result = cmap->gids[code]; - if ( result != 0 ) - { - *pchar_code = code; - break; - } - - code++; + *pchar_code = char_code; + break; } } + return result; } @@ -131,9 +124,10 @@ /*************************************************************************/ FT_CALLBACK_DEF( const char* ) - cff_sid_to_glyph_name( TT_Face face, + cff_sid_to_glyph_name( void* face_, /* TT_Face */ FT_UInt idx ) { + TT_Face face = (TT_Face)face_; CFF_Font cff = (CFF_Font)face->extra.data; CFF_Charset charset = &cff->charset; FT_UInt sid = charset->sids[idx]; @@ -144,14 +138,15 @@ FT_CALLBACK_DEF( FT_Error ) - cff_cmap_unicode_init( PS_Unicodes unicodes, + cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ FT_Pointer pointer ) { - 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; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + 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; FT_UNUSED( pointer ); @@ -167,17 +162,18 @@ return psnames->unicodes_init( memory, unicodes, cff->num_glyphs, - (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name, + &cff_sid_to_glyph_name, (PS_FreeGlyphNameFunc)NULL, (FT_Pointer)face ); } FT_CALLBACK_DEF( void ) - cff_cmap_unicode_done( PS_Unicodes unicodes ) + cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ { - FT_Face face = FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); FT_FREE( unicodes->maps ); @@ -186,25 +182,27 @@ FT_CALLBACK_DEF( FT_UInt ) - cff_cmap_unicode_char_index( PS_Unicodes unicodes, - FT_UInt32 char_code ) + cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_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; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + 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_UInt32 ) - cff_cmap_unicode_char_next( PS_Unicodes unicodes, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_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; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + 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 ); diff --git a/src/thirdparty/freetype2/src/cff/cffcmap.h b/src/thirdparty/freetype2/src/cff/cffcmap.h index 07366bc74..60e16d948 100644 --- a/src/thirdparty/freetype2/src/cff/cffcmap.h +++ b/src/thirdparty/freetype2/src/cff/cffcmap.h @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #ifndef CFFCMAP_H_ #define CFFCMAP_H_ -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H +#include FT_BEGIN_HEADER @@ -43,7 +43,7 @@ FT_BEGIN_HEADER } CFF_CMapStdRec; - FT_DECLARE_CMAP_CLASS(cff_cmap_encoding_class_rec) + FT_DECLARE_CMAP_CLASS( cff_cmap_encoding_class_rec ) /*************************************************************************/ @@ -56,7 +56,7 @@ FT_BEGIN_HEADER /* unicode (synthetic) cmaps */ - FT_DECLARE_CMAP_CLASS(cff_cmap_unicode_class_rec) + FT_DECLARE_CMAP_CLASS( cff_cmap_unicode_class_rec ) FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/cff/cffdrivr.c b/src/thirdparty/freetype2/src/cff/cffdrivr.c index 232498981..0079ddd19 100644 --- a/src/thirdparty/freetype2/src/cff/cffdrivr.c +++ b/src/thirdparty/freetype2/src/cff/cffdrivr.c @@ -4,8 +4,8 @@ * * OpenType font driver implementation (body). * - * Copyright (C) 1996-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright (C) 1996-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, * modified, and distributed under the terms of the FreeType project @@ -16,18 +16,17 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_POSTSCRIPT_PROPS_H -#include FT_SERVICE_CID_H -#include FT_SERVICE_POSTSCRIPT_INFO_H -#include FT_SERVICE_POSTSCRIPT_NAME_H -#include FT_SERVICE_TT_CMAP_H -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "cffdrivr.h" #include "cffgload.h" @@ -37,16 +36,16 @@ #include "cffobjs.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_METRICS_VARIATIONS_H +#include +#include #endif #include "cfferrs.h" -#include FT_SERVICE_FONT_FORMAT_H -#include FT_SERVICE_GLYPH_DICT_H -#include FT_SERVICE_PROPERTIES_H -#include FT_DRIVER_H +#include +#include +#include +#include /************************************************************************** @@ -109,20 +108,33 @@ * They can be implemented by format-specific interfaces. */ FT_CALLBACK_DEF( FT_Error ) - cff_get_kerning( FT_Face ttface, /* TT_Face */ + cff_get_kerning( FT_Face face, /* CFF_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; + CFF_Face cffface = (CFF_Face)face; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; kerning->x = 0; kerning->y = 0; if ( sfnt ) - kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + { + /* Use 'kern' table if available since that can be faster; otherwise */ + /* use GPOS kerning pairs if available. */ + if ( cffface->kern_avail_bits ) + kerning->x = sfnt->get_kerning( cffface, + left_glyph, + right_glyph ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + else if ( cffface->num_gpos_lookups_kerning ) + kerning->x = sfnt->get_gpos_kerning( cffface, + left_glyph, + right_glyph ); +#endif + } return FT_Err_Ok; } @@ -159,38 +171,20 @@ * FreeType error code. 0 means success. */ FT_CALLBACK_DEF( FT_Error ) - cff_glyph_load( FT_GlyphSlot cffslot, /* CFF_GlyphSlot */ - FT_Size cffsize, /* CFF_Size */ + cff_glyph_load( FT_GlyphSlot slot, /* CFF_GlyphSlot */ + FT_Size size, /* 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; + CFF_GlyphSlot cffslot = (CFF_GlyphSlot)slot; + CFF_Size cffsize = (CFF_Size)size; - if ( !slot ) - return FT_THROW( Invalid_Slot_Handle ); - - FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index )); - - /* check whether we want a scaled outline or bitmap */ - if ( !size ) - load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; - - /* reset the size object if necessary */ - if ( load_flags & FT_LOAD_NO_SCALE ) - size = NULL; - - if ( size ) - { - /* these two objects must have the same parent */ - if ( cffsize->face != cffslot->face ) - return FT_THROW( Invalid_Face_Handle ); - } + FT_TRACE1(( "cff_glyph_load: glyph index %u\n", glyph_index )); /* now load the glyph outline if necessary */ - error = cff_slot_load( slot, size, glyph_index, load_flags ); + error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags ); /* force drop-out mode to 2 - irrelevant now */ /* slot->outline.dropout_mode = 2; */ @@ -206,105 +200,70 @@ FT_Int32 flags, FT_Fixed* advances ) { - FT_UInt nn; - FT_Error error = FT_Err_Ok; - FT_GlyphSlot slot = face->glyph; + CFF_Face cffface = (CFF_Face)face; + FT_Bool horz; + FT_UInt nn; - if ( FT_IS_SFNT( face ) ) + if ( !FT_IS_SFNT( face ) ) + return FT_THROW( Unimplemented_Feature ); + + horz = !( flags & FT_LOAD_VERTICAL_LAYOUT ); + + if ( horz ) { /* OpenType 1.7 mandates that the data from `hmtx' table be used; */ /* it is no longer necessary that those values are identical to */ /* the values in the `CFF' table */ + if ( !cffface->horizontal.number_Of_HMetrics ) + return FT_THROW( Unimplemented_Feature ); - TT_Face ttface = (TT_Face)face; - FT_Short dummy; - - - if ( flags & FT_LOAD_VERTICAL_LAYOUT ) - { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* no fast retrieval for blended MM fonts without VVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && - !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - return FT_THROW( Unimplemented_Feature ); + /* no fast retrieval for blended MM fonts without HVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); #endif + } + else /* vertical */ + { + /* check whether we have data from the `vmtx' table at all; */ + /* otherwise we extract the info from the CFF glyphstrings */ + /* (instead of synthesizing a global value using the `OS/2' */ + /* table) */ + if ( !cffface->vertical_info ) + return FT_THROW( Unimplemented_Feature ); - /* check whether we have data from the `vmtx' table at all; */ - /* otherwise we extract the info from the CFF glyphstrings */ - /* (instead of synthesizing a global value using the `OS/2' */ - /* table) */ - if ( !ttface->vertical_info ) - goto Missing_Table; - - for ( nn = 0; nn < count; nn++ ) - { - FT_UShort ah; - - - ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface, - 1, - start + nn, - &dummy, - &ah ); - - FT_TRACE5(( " idx %d: advance height %d font unit%s\n", - start + nn, - ah, - ah == 1 ? "" : "s" )); - advances[nn] = ah; - } - } - else - { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* no fast retrieval for blended MM fonts without HVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && - !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - return FT_THROW( Unimplemented_Feature ); + /* no fast retrieval for blended MM fonts without VVAR table */ + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + return FT_THROW( Unimplemented_Feature ); #endif - - /* check whether we have data from the `hmtx' table at all */ - if ( !ttface->horizontal.number_Of_HMetrics ) - goto Missing_Table; - - for ( nn = 0; nn < count; nn++ ) - { - FT_UShort aw; - - - ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface, - 0, - start + nn, - &dummy, - &aw ); - - FT_TRACE5(( " idx %d: advance width %d font unit%s\n", - start + nn, - aw, - aw == 1 ? "" : "s" )); - advances[nn] = aw; - } - } - - return error; } - Missing_Table: - flags |= (FT_UInt32)FT_LOAD_ADVANCE_ONLY; - + /* proceed to fast advances */ for ( nn = 0; nn < count; nn++ ) { - error = cff_glyph_load( slot, face->size, start + nn, flags ); - if ( error ) - break; + FT_UShort aw; + FT_Short dummy; - advances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT ) - ? slot->linearVertAdvance - : slot->linearHoriAdvance; + + ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface, + !horz, + start + nn, + &dummy, + &aw ); + + FT_TRACE5(( " idx %u: advance %s %d font unit%s\n", + start + nn, + horz ? "width" : "height", + aw, + aw == 1 ? "" : "s" )); + advances[nn] = aw; } - return error; + return FT_Err_Ok; } @@ -313,13 +272,14 @@ * */ - static FT_Error - cff_get_glyph_name( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_glyph_name( FT_Face face, /* CFF_Face */ FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max ) { - CFF_Font font = (CFF_Font)face->extra.data; + CFF_Face cffface = (CFF_Face)face; + CFF_Font font = (CFF_Font)cffface->extra.data; FT_String* gname; FT_UShort sid; FT_Error error; @@ -339,15 +299,12 @@ if ( service && service->get_name ) - return service->get_name( FT_FACE( face ), - glyph_index, - buffer, - buffer_max ); + return service->get_name( face, glyph_index, buffer, buffer_max ); else { FT_ERROR(( "cff_get_glyph_name:" - " cannot get glyph name from a CFF2 font\n" - " " + " cannot get glyph name from a CFF2 font\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -357,8 +314,8 @@ if ( !font->psnames ) { FT_ERROR(( "cff_get_glyph_name:" - " cannot get glyph name from CFF & CEF fonts\n" - " " + " cannot get glyph name from CFF & CEF fonts\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -367,7 +324,7 @@ /* first, locate the sid in the charset table */ sid = font->charset.sids[glyph_index]; - /* now, lookup the name itself */ + /* now, look up the name itself */ gname = cff_index_get_sid_string( font, sid ); if ( gname ) @@ -380,21 +337,19 @@ } - static FT_UInt - cff_get_name_index( CFF_Face face, + FT_CALLBACK_DEF( FT_UInt ) + cff_get_name_index( FT_Face face, /* CFF_Face */ const FT_String* glyph_name ) { - CFF_Font cff; - CFF_Charset charset; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + CFF_Charset charset = &cff->charset; FT_Service_PsCMaps psnames; FT_String* name; FT_UShort sid; FT_UInt i; - cff = (CFF_FontRec *)face->extra.data; - charset = &cff->charset; - /* CFF2 table does not have glyph names; */ /* we need to use `post' table method */ if ( cff->version_major == 2 ) @@ -409,12 +364,12 @@ if ( service && service->name_index ) - return service->name_index( FT_FACE( face ), glyph_name ); + return service->name_index( face, glyph_name ); else { FT_ERROR(( "cff_get_name_index:" - " cannot get glyph index from a CFF2 font\n" - " " + " cannot get glyph index from a CFF2 font\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); return 0; } @@ -447,8 +402,8 @@ FT_DEFINE_SERVICE_GLYPHDICTREC( cff_service_glyph_dict, - (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, /* get_name */ - (FT_GlyphDict_NameIndexFunc)cff_get_name_index /* name_index */ + cff_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + cff_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ ) @@ -457,29 +412,36 @@ * */ - static FT_Int + FT_CALLBACK_DEF( 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, + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_info( FT_Face face, /* CFF_Face */ PS_FontInfoRec* afont_info ) { - CFF_Font cff = (CFF_Font)face->extra.data; - FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; + if ( cffface->is_cff2 ) + { + error = FT_THROW( Invalid_Argument ); + goto Fail; + } + if ( cff && !cff->font_info ) { CFF_FontRecDict dict = &cff->top_font.font_dict; - PS_FontInfoRec *font_info = NULL; - FT_Memory memory = face->root.memory; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_FontInfoRec* font_info = NULL; - if ( FT_ALLOC( font_info, sizeof ( *font_info ) ) ) + if ( FT_QNEW( font_info ) ) goto Fail; font_info->version = cff_index_get_sid_string( cff, @@ -508,23 +470,24 @@ } - static FT_Error - cff_ps_get_font_extra( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_ps_get_font_extra( FT_Face face, /* CFF_Face */ PS_FontExtraRec* afont_extra ) { - CFF_Font cff = (CFF_Font)face->extra.data; - FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + FT_Error error = FT_Err_Ok; - if ( cff && cff->font_extra == NULL ) + if ( cff && !cff->font_extra ) { CFF_FontRecDict dict = &cff->top_font.font_dict; + FT_Memory memory = FT_FACE_MEMORY( face ); PS_FontExtraRec* font_extra = NULL; - FT_Memory memory = face->root.memory; FT_String* embedded_postscript; - if ( FT_ALLOC( font_extra, sizeof ( *font_extra ) ) ) + if ( FT_QNEW( font_extra ) ) goto Fail; font_extra->fs_type = 0U; @@ -589,13 +552,13 @@ FT_DEFINE_SERVICE_PSINFOREC( cff_service_ps_info, - (PS_GetFontInfoFunc) cff_ps_get_font_info, /* ps_get_font_info */ - (PS_GetFontExtraFunc) cff_ps_get_font_extra, /* ps_get_font_extra */ - (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, /* ps_has_glyph_names */ + cff_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cff_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + cff_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ /* unsupported with CFF fonts */ - (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ /* not implemented */ - (PS_GetFontValueFunc) NULL /* ps_get_font_value */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ ) @@ -604,17 +567,18 @@ * */ - static const char* - cff_get_ps_name( CFF_Face face ) + FT_CALLBACK_DEF( const char* ) + cff_get_ps_name( FT_Face face ) /* CFF_Face */ { - CFF_Font cff = (CFF_Font)face->extra.data; - SFNT_Service sfnt = (SFNT_Service)face->sfnt; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; + SFNT_Service sfnt = (SFNT_Service)cffface->sfnt; /* following the OpenType specification 1.7, we return the name stored */ /* in the `name' table for a CFF wrapped into an SFNT container */ - if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt ) + if ( FT_IS_SFNT( face ) && sfnt ) { FT_Library library = FT_FACE_LIBRARY( face ); FT_Module sfnt_module = FT_Get_Module( library, "sfnt" ); @@ -626,17 +590,17 @@ if ( service && service->get_ps_font_name ) - return service->get_ps_font_name( FT_FACE( face ) ); + return service->get_ps_font_name( face ); } - return (const char*)cff->font_name; + return cff ? (const char*)cff->font_name : NULL; } FT_DEFINE_SERVICE_PSFONTNAMEREC( cff_service_ps_name, - (FT_PsName_GetFunc)cff_get_ps_name /* get_ps_font_name */ + cff_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ ) @@ -650,7 +614,7 @@ * Otherwise call the service function in the sfnt module. * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) cff_get_cmap_info( FT_CharMap charmap, TT_CMapInfo *cmap_info ) { @@ -684,7 +648,7 @@ FT_DEFINE_SERVICE_TTCMAPSREC( cff_service_get_cmap_info, - (TT_CMap_Info_GetFunc)cff_get_cmap_info /* get_cmap_info */ + cff_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ ) @@ -692,14 +656,15 @@ * CID INFO SERVICE * */ - static FT_Error - cff_get_ros( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_ros( FT_Face face, /* FT_Face */ const char* *registry, const char* *ordering, FT_Int *supplement ) { - FT_Error error = FT_Err_Ok; - CFF_Font cff = (CFF_Font)face->extra.data; + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; if ( cff ) @@ -738,7 +703,7 @@ { if ( dict->cid_supplement < FT_INT_MIN || dict->cid_supplement > FT_INT_MAX ) - FT_TRACE1(( "cff_get_ros: too large supplement %d is truncated\n", + FT_TRACE1(( "cff_get_ros: too large supplement %ld is truncated\n", dict->cid_supplement )); *supplement = (FT_Int)dict->cid_supplement; } @@ -749,12 +714,13 @@ } - static FT_Error - cff_get_is_cid( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_is_cid( FT_Face face, /* CFF_Face */ FT_Bool *is_cid ) { - FT_Error error = FT_Err_Ok; - CFF_Font cff = (CFF_Font)face->extra.data; + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; *is_cid = 0; @@ -772,17 +738,16 @@ } - static FT_Error - cff_get_cid_from_glyph_index( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_cid_from_glyph_index( FT_Face face, /* CFF_Face */ FT_UInt glyph_index, FT_UInt *cid ) { - FT_Error error = FT_Err_Ok; - CFF_Font cff; + FT_Error error = FT_Err_Ok; + CFF_Face cffface = (CFF_Face)face; + CFF_Font cff = (CFF_Font)cffface->extra.data; - cff = (CFF_Font)face->extra.data; - if ( cff ) { FT_UInt c; @@ -815,12 +780,12 @@ FT_DEFINE_SERVICE_CIDREC( cff_service_cid_info, - (FT_CID_GetRegistryOrderingSupplementFunc) - cff_get_ros, /* get_ros */ - (FT_CID_GetIsInternallyCIDKeyedFunc) - cff_get_is_cid, /* get_is_cid */ - (FT_CID_GetCIDFromGlyphIndexFunc) - cff_get_cid_from_glyph_index /* get_cid_from_glyph_index */ + cff_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cff_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cff_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ ) @@ -832,9 +797,9 @@ FT_DEFINE_SERVICE_PROPERTIESREC( cff_service_properties, - (FT_Properties_SetFunc)ps_property_set, /* set_property */ - (FT_Properties_GetFunc)ps_property_get ) /* get_property */ - + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT @@ -843,116 +808,231 @@ * */ - static FT_Error - cff_set_mm_blend( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_blend( FT_Face face, /* CFF_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->set_mm_blend( FT_FACE( face ), num_coords, coords ); + return mm->set_mm_blend( face, num_coords, coords ); } - static FT_Error - cff_get_mm_blend( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_blend( FT_Face face, /* CFF_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->get_mm_blend( FT_FACE( face ), num_coords, coords ); + return mm->get_mm_blend( face, num_coords, coords ); } - static FT_Error - cff_set_mm_weightvector( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_set_mm_weightvector( FT_Face face, /* CFF_Face */ FT_UInt len, FT_Fixed* weightvector ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector ); + return mm->set_mm_weightvector( face, len, weightvector ); } - static FT_Error - cff_get_mm_weightvector( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_weightvector( FT_Face face, /* CFF_Face */ FT_UInt* len, FT_Fixed* weightvector ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector ); + return mm->get_mm_weightvector( face, len, weightvector ); } - static FT_Error - cff_get_mm_var( CFF_Face face, + FT_CALLBACK_DEF( void ) + cff_construct_ps_name( FT_Face face ) /* CFF_Face */ + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->construct_ps_name( face ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_get_mm_var( FT_Face face, /* CFF_Face */ FT_MM_Var* *master ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->get_mm_var( FT_FACE( face ), master ); + return mm->get_mm_var( face, master ); } - static FT_Error - cff_set_var_design( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_set_var_design( FT_Face face, /* CFF_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->set_var_design( FT_FACE( face ), num_coords, coords ); + return mm->set_var_design( face, num_coords, coords ); } - static FT_Error - cff_get_var_design( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_get_var_design( FT_Face face, /* CFF_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->get_var_design( FT_FACE( face ), num_coords, coords ); + return mm->get_var_design( face, num_coords, coords ); } - static FT_Error - cff_set_instance( CFF_Face face, - FT_UInt instance_index ) + FT_CALLBACK_DEF( FT_Error ) + cff_set_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt instance_index ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->set_instance( FT_FACE( face ), instance_index ); + return mm->set_named_instance( face, instance_index ); } + FT_CALLBACK_DEF( FT_Error ) + cff_get_default_named_instance( FT_Face face, /* CFF_Face */ + FT_UInt *instance_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_default_named_instance( face, instance_index ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_item_variation_store( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_item_var_store( face, offset, itemStore ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_load_delta_set_index_mapping( FT_Face face, /* CFF_Face */ + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->load_delta_set_idx_map( face, offset, map, + itemStore, table_len ); + } + + + FT_CALLBACK_DEF( FT_Int ) + cff_get_item_delta( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + return mm->get_item_delta( face, itemStore, outerIndex, innerIndex ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_item_variation_store( FT_Face face, /* CFF_Face */ + GX_ItemVarStore itemStore ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_item_var_store( face, itemStore ); + } + + + FT_CALLBACK_DEF( void ) + cff_done_delta_set_index_map( FT_Face face, /* CFF_Face */ + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; + + + mm->done_delta_set_idx_map( face, deltaSetIdxMap ); + } + + + FT_DEFINE_SERVICE_MULTIMASTERSREC( cff_service_multi_masters, - (FT_Get_MM_Func) NULL, /* get_mm */ - (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ - (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */ - (FT_Set_Var_Design_Func) cff_set_var_design, /* set_var_design */ - (FT_Get_Var_Design_Func) cff_get_var_design, /* get_var_design */ - (FT_Set_Instance_Func) cff_set_instance, /* set_instance */ - (FT_Set_MM_WeightVector_Func)cff_set_mm_weightvector, /* set_mm_weightvector */ - (FT_Get_MM_WeightVector_Func)cff_get_mm_weightvector, /* get_mm_weightvector */ - - (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */ - (FT_Done_Blend_Func) cff_done_blend /* done_blend */ + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + cff_set_mm_blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + cff_get_mm_blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + cff_get_mm_var, /* FT_Get_MM_Var_Func get_mm_var */ + cff_set_var_design, /* FT_Set_Var_Design_Func set_var_design */ + cff_get_var_design, /* FT_Get_Var_Design_Func get_var_design */ + cff_set_named_instance, + /* FT_Set_Named_Instance_Func set_named_instance */ + cff_get_default_named_instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + cff_set_mm_weightvector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + cff_get_mm_weightvector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ + cff_construct_ps_name, + /* FT_Construct_PS_Name_Func construct_ps_name */ + cff_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + cff_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + cff_get_item_delta, + /* FT_Var_Get_Item_Delta_Func get_item_delta */ + cff_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + cff_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + cff_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + cff_done_blend /* FT_Done_Blend_Func done_blend */ ) @@ -961,41 +1041,46 @@ * */ - static FT_Error - cff_hadvance_adjust( CFF_Face face, + FT_CALLBACK_DEF( FT_Error ) + cff_hadvance_adjust( FT_Face face, /* CFF_Face */ FT_UInt gindex, FT_Int *avalue ) { - FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; - return var->hadvance_adjust( FT_FACE( face ), gindex, avalue ); + return var->hadvance_adjust( face, gindex, avalue ); } - static void - cff_metrics_adjust( CFF_Face face ) + FT_CALLBACK_DEF( void ) + cff_metrics_adjust( FT_Face face ) /* CFF_Face */ { - FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MetricsVariations + var = (FT_Service_MetricsVariations)cffface->tt_var; - var->metrics_adjust( FT_FACE( face ) ); + var->metrics_adjust( face ); } FT_DEFINE_SERVICE_METRICSVARIATIONSREC( cff_service_metrics_variations, - (FT_HAdvance_Adjust_Func)cff_hadvance_adjust, /* hadvance_adjust */ - (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */ - (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */ + cff_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ - (FT_VAdvance_Adjust_Func)NULL, /* vadvance_adjust */ - (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */ - (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */ - (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */ + NULL, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ - (FT_Metrics_Adjust_Func) cff_metrics_adjust /* metrics_adjust */ + cff_metrics_adjust, /* FT_Metrics_Adjust_Func metrics_adjust */ + NULL /* FT_Size_Reset_Func size_reset */ ) #endif @@ -1008,11 +1093,11 @@ FT_DEFINE_SERVICE_CFFLOADREC( cff_service_cff_load, - (FT_Get_Standard_Encoding_Func)cff_get_standard_encoding, - (FT_Load_Private_Dict_Func) cff_load_private_dict, - (FT_FD_Select_Get_Func) cff_fd_select_get, - (FT_Blend_Check_Vector_Func) cff_blend_check_vector, - (FT_Blend_Build_Vector_Func) cff_blend_build_vector + cff_get_standard_encoding, /* FT_Get_Standard_Encoding_Func get_standard_encoding */ + cff_load_private_dict, /* FT_Load_Private_Dict_Func load_private_dict */ + cff_fd_select_get, /* FT_FD_Select_Get_Func fd_select_get */ + cff_blend_check_vector, /* FT_Blend_Check_Vector_Func blend_check_vector */ + cff_blend_build_vector /* FT_Blend_Build_Vector_Func blend_build_vector */ ) @@ -1028,8 +1113,7 @@ /*************************************************************************/ /*************************************************************************/ -#if !defined FT_CONFIG_OPTION_NO_GLYPH_NAMES && \ - defined TT_CONFIG_OPTION_GX_VAR_SUPPORT +#if defined TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_DEFINE_SERVICEDESCREC10( cff_services, @@ -1044,7 +1128,7 @@ FT_SERVICE_ID_PROPERTIES, &cff_service_properties, FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load ) -#elif !defined FT_CONFIG_OPTION_NO_GLYPH_NAMES +#else FT_DEFINE_SERVICEDESCREC8( cff_services, @@ -1057,32 +1141,6 @@ FT_SERVICE_ID_PROPERTIES, &cff_service_properties, FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load ) -#elif defined TT_CONFIG_OPTION_GX_VAR_SUPPORT - FT_DEFINE_SERVICEDESCREC9( - cff_services, - - FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, - FT_SERVICE_ID_MULTI_MASTERS, &cff_service_multi_masters, - FT_SERVICE_ID_METRICS_VARIATIONS, &cff_service_metrics_var, - FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, - FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, - FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, - FT_SERVICE_ID_CID, &cff_service_cid_info, - FT_SERVICE_ID_PROPERTIES, &cff_service_properties, - FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load - ) -#else - FT_DEFINE_SERVICEDESCREC7( - cff_services, - - FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, - FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, - FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, - FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, - FT_SERVICE_ID_CID, &cff_service_cid_info, - FT_SERVICE_ID_PROPERTIES, &cff_service_properties, - FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load - ) #endif diff --git a/src/thirdparty/freetype2/src/cff/cffdrivr.h b/src/thirdparty/freetype2/src/cff/cffdrivr.h index f2bbcfe4f..52a1e727a 100644 --- a/src/thirdparty/freetype2/src/cff/cffdrivr.h +++ b/src/thirdparty/freetype2/src/cff/cffdrivr.h @@ -4,7 +4,7 @@ * * High-level OpenType driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define CFFDRIVER_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/cff/cfferrs.h b/src/thirdparty/freetype2/src/cff/cfferrs.h index 78d47a156..7491886c7 100644 --- a/src/thirdparty/freetype2/src/cff/cfferrs.h +++ b/src/thirdparty/freetype2/src/cff/cfferrs.h @@ -4,7 +4,7 @@ * * CFF error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef CFFERRS_H_ #define CFFERRS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_BASE FT_Mod_Err_CFF -#include FT_ERRORS_H +#include #endif /* CFFERRS_H_ */ diff --git a/src/thirdparty/freetype2/src/cff/cffgload.c b/src/thirdparty/freetype2/src/cff/cffgload.c index 36aa7d1b9..e8bab3c1e 100644 --- a/src/thirdparty/freetype2/src/cff/cffgload.c +++ b/src/thirdparty/freetype2/src/cff/cffgload.c @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,20 +16,27 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_OUTLINE_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include +#include +#include #include "cffload.h" #include "cffgload.h" #include "cfferrs.h" +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#define IS_DEFAULT_INSTANCE( _face ) \ + ( !( FT_IS_NAMED_INSTANCE( _face ) || \ + FT_IS_VARIATION( _face ) ) ) +#else +#define IS_DEFAULT_INSTANCE( _face ) 1 +#endif + /************************************************************************** * @@ -60,7 +67,7 @@ *pointer = (FT_Byte*)data.pointer; - *length = (FT_ULong)data.length; + *length = data.length; return error; } @@ -68,7 +75,7 @@ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - CFF_Font cff = (CFF_Font)(face->extra.data); + CFF_Font cff = (CFF_Font)( face->extra.data ); return cff_index_access_element( &cff->charstrings_index, glyph_index, @@ -95,7 +102,7 @@ data.pointer = *pointer; - data.length = (FT_Int)length; + data.length = (FT_UInt)length; face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, &data ); @@ -104,7 +111,7 @@ #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - CFF_Font cff = (CFF_Font)(face->extra.data); + CFF_Font cff = (CFF_Font)( face->extra.data ); cff_index_forget_element( &cff->charstrings_index, pointer ); @@ -207,8 +214,8 @@ PSAux_Service psaux = (PSAux_Service)face->psaux; const CFF_Decoder_Funcs decoder_funcs = psaux->cff_decoder_funcs; - FT_Matrix font_matrix; - FT_Vector font_offset; + FT_Matrix font_matrix; + FT_Vector font_offset; force_scaling = FALSE; @@ -231,24 +238,12 @@ else if ( glyph_index >= cff->num_glyphs ) return FT_THROW( 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; @@ -256,8 +251,8 @@ if ( size->strike_index != 0xFFFFFFFFUL && - sfnt->load_eblc && - ( load_flags & FT_LOAD_NO_BITMAP ) == 0 ) + ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && + IS_DEFAULT_INSTANCE( size->root.face ) ) { TT_SBit_MetricsRec metrics; @@ -277,9 +272,6 @@ FT_Short dummy; - glyph->root.outline.n_points = 0; - glyph->root.outline.n_contours = 0; - glyph->root.metrics.width = (FT_Pos)metrics.width * 64; glyph->root.metrics.height = (FT_Pos)metrics.height * 64; @@ -347,6 +339,94 @@ if ( load_flags & FT_LOAD_SBITS_ONLY ) return FT_THROW( Invalid_Argument ); +#ifdef FT_CONFIG_OPTION_SVG + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + /* + * We load the SVG document and try to grab the advances from the + * table. For the bearings we rely on the presetting hook to do that. + */ + + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + if ( size && (size->root.metrics.x_ppem < 1 || + size->root.metrics.y_ppem < 1 ) ) + { + error = FT_THROW( Invalid_Size_Handle ); + return error; + } + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( (FT_GlyphSlot)glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short dummy; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->root.format = FT_GLYPH_FORMAT_SVG; + + /* + * If horizontal or vertical advances are not present in the table, + * this is a problem with the font since the standard requires them. + * However, we are graceful and calculate the values by ourselves + * for the vertical case. + */ + sfnt->get_metrics( face, + FALSE, + glyph_index, + &dummy, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &dummy, + &advanceY ); + + glyph->root.linearHoriAdvance = advanceX; + glyph->root.linearVertAdvance = advanceY; + + glyph->root.metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->root.metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + return error; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + /* top-level code ensures that FT_LOAD_NO_HINTING is set */ + /* if FT_LOAD_NO_SCALE is active */ + hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); + scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); + + glyph->hint = hinting; + glyph->scaled = scaled; + + if ( scaled ) + { + glyph->x_scale = size->root.metrics.x_scale; + glyph->y_scale = size->root.metrics.y_scale; + } + else + { + glyph->x_scale = 0x10000L; + glyph->y_scale = 0x10000L; + } + /* if we have a CID subfont, use its matrix (which has already */ /* been multiplied with the root matrix) */ @@ -364,7 +444,6 @@ top_upm = (FT_Long)cff->top_font.font_dict.units_per_em; sub_upm = (FT_Long)cff->subfonts[fd_index]->font_dict.units_per_em; - font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; font_offset = cff->subfonts[fd_index]->font_dict.font_offset; @@ -382,24 +461,11 @@ font_offset = cff->top_font.font_dict.font_offset; } - glyph->root.outline.n_points = 0; - glyph->root.outline.n_contours = 0; - - /* top-level code ensures that FT_LOAD_NO_HINTING is set */ - /* if FT_LOAD_NO_SCALE is active */ - hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); - scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); - - glyph->hint = hinting; - glyph->scaled = scaled; - glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */ - { #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( face ); #endif - FT_Byte* charstring; FT_ULong charstring_len; @@ -416,13 +482,14 @@ decoder.builder.no_recurse = FT_BOOL( load_flags & FT_LOAD_NO_RECURSE ); - /* now load the unscaled outline */ - error = cff_get_glyph_data( face, glyph_index, - &charstring, &charstring_len ); + /* this function also checks for a valid subfont index */ + error = decoder_funcs->prepare( &decoder, size, glyph_index ); if ( error ) goto Glyph_Build_Finished; - error = decoder_funcs->prepare( &decoder, size, glyph_index ); + /* now load the unscaled outline */ + error = cff_get_glyph_data( face, glyph_index, + &charstring, &charstring_len ); if ( error ) goto Glyph_Build_Finished; @@ -527,10 +594,8 @@ { /* 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. */ + /* 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; @@ -549,6 +614,12 @@ FT_Bool has_vertical_info; + glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; + + glyph->root.outline.flags = FT_OUTLINE_REVERSE_FILL; + if ( size && size->root.metrics.y_ppem < 24 ) + glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION; + if ( face->horizontal.number_Of_HMetrics ) { FT_Short horiBearingX = 0; @@ -602,14 +673,6 @@ 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 any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) @@ -632,7 +695,7 @@ metrics->vertAdvance += font_offset.y; } - if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) + if ( scaled || force_scaling ) { /* scale the outline and the metrics */ FT_Int n; @@ -665,8 +728,12 @@ metrics->horiBearingY = cbox.yMax; if ( has_vertical_info ) + { metrics->vertBearingX = metrics->horiBearingX - metrics->horiAdvance / 2; + metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, + glyph->y_scale ); + } else { if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) diff --git a/src/thirdparty/freetype2/src/cff/cffgload.h b/src/thirdparty/freetype2/src/cff/cffgload.h index 754c55acf..662bb7cff 100644 --- a/src/thirdparty/freetype2/src/cff/cffgload.h +++ b/src/thirdparty/freetype2/src/cff/cffgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define CFFGLOAD_H_ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/cff/cffload.c b/src/thirdparty/freetype2/src/cff/cffload.c index 12efd18dc..326f88505 100644 --- a/src/thirdparty/freetype2/src/cff/cffload.c +++ b/src/thirdparty/freetype2/src/cff/cffload.c @@ -4,7 +4,7 @@ * * OpenType and CFF data/program tables loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,17 +16,16 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include FT_TYPE1_TABLES_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H +#include +#include #endif #include "cffload.h" @@ -357,9 +356,9 @@ data_size = (FT_ULong)( idx->count + 1 ) * offsize; - if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) || - FT_STREAM_SEEK( idx->start + idx->hdr_size ) || - FT_FRAME_ENTER( data_size ) ) + if ( FT_QNEW_ARRAY( idx->offsets, idx->count + 1 ) || + FT_STREAM_SEEK( idx->start + idx->hdr_size ) || + FT_FRAME_ENTER( data_size ) ) goto Exit; poff = idx->offsets; @@ -401,7 +400,7 @@ /* Allocate a table containing pointers to an index's elements. */ /* The `pool' argument makes this function convert the index */ - /* entries to C-style strings (this is, NULL-terminated). */ + /* entries to C-style strings (that is, null-terminated). */ static FT_Error cff_index_get_pointers( CFF_Index idx, FT_Byte*** table, @@ -411,7 +410,7 @@ FT_Error error = FT_Err_Ok; FT_Memory memory = idx->stream->memory; - FT_Byte** t = NULL; + FT_Byte** tbl = NULL; FT_Byte* new_bytes = NULL; FT_ULong new_size; @@ -428,11 +427,11 @@ new_size = idx->data_size + idx->count; if ( idx->count > 0 && - !FT_NEW_ARRAY( t, idx->count + 1 ) && + !FT_QNEW_ARRAY( tbl, idx->count + 1 ) && ( !pool || !FT_ALLOC( new_bytes, new_size ) ) ) { FT_ULong n, cur_offset; - FT_ULong extra = 0; + FT_ULong extra = 0; FT_Byte* org_bytes = idx->bytes; @@ -443,15 +442,15 @@ if ( cur_offset != 0 ) { FT_TRACE0(( "cff_index_get_pointers:" - " invalid first offset value %d set to zero\n", + " invalid first offset value %lu set to zero\n", cur_offset )); cur_offset = 0; } if ( !pool ) - t[0] = org_bytes + cur_offset; + tbl[0] = org_bytes + cur_offset; else - t[0] = new_bytes + cur_offset; + tbl[0] = new_bytes + cur_offset; for ( n = 1; n <= idx->count; n++ ) { @@ -465,23 +464,25 @@ next_offset = idx->data_size; if ( !pool ) - t[n] = org_bytes + next_offset; + tbl[n] = org_bytes + next_offset; else { - t[n] = new_bytes + next_offset + extra; + tbl[n] = new_bytes + next_offset + extra; if ( next_offset != cur_offset ) { - FT_MEM_COPY( t[n - 1], org_bytes + cur_offset, t[n] - t[n - 1] ); - t[n][0] = '\0'; - t[n] += 1; + FT_MEM_COPY( tbl[n - 1], + org_bytes + cur_offset, + tbl[n] - tbl[n - 1] ); + tbl[n][0] = '\0'; + tbl[n] += 1; extra++; } } cur_offset = next_offset; } - *table = t; + *table = tbl; if ( pool ) *pool = new_bytes; @@ -490,6 +491,11 @@ } Exit: + if ( error && new_bytes ) + FT_FREE( new_bytes ); + if ( error && tbl ) + FT_FREE( tbl ); + return error; } @@ -553,8 +559,8 @@ idx->data_offset > stream->size - off2 + 1 ) { FT_ERROR(( "cff_index_access_element:" - " offset to next entry (%d)" - " exceeds the end of stream (%d)\n", + " offset to next entry (%lu)" + " exceeds the end of stream (%lu)\n", off2, stream->size - idx->data_offset + 1 )); off2 = stream->size - idx->data_offset + 1; } @@ -616,7 +622,7 @@ FT_Byte* bytes; FT_ULong byte_len; FT_Error error; - FT_String* name = 0; + FT_String* name = NULL; if ( !idx->stream ) /* CFF2 does not include a name index */ @@ -628,10 +634,9 @@ if ( error ) goto Exit; - if ( !FT_ALLOC( name, byte_len + 1 ) ) + if ( !FT_QALLOC( name, byte_len + 1 ) ) { - if ( byte_len ) - FT_MEM_COPY( name, bytes, byte_len ); + FT_MEM_COPY( name, bytes, byte_len ); name[byte_len] = 0; } cff_index_forget_element( idx, &bytes ); @@ -766,8 +771,7 @@ case 3: /* first, compare to the cache */ - if ( (FT_UInt)( glyph_index - fdselect->cache_first ) < - fdselect->cache_count ) + if ( glyph_index - fdselect->cache_first < fdselect->cache_count ) { fd = fdselect->cache_fd; break; @@ -830,7 +834,6 @@ { FT_Error error = FT_Err_Ok; FT_UInt i; - FT_Long j; FT_UShort max_cid = 0; @@ -848,9 +851,10 @@ /* When multiple GIDs map to the same CID, we choose the lowest */ /* GID. This is not described in any spec, but it matches the */ - /* behaviour of recent Acroread versions. */ - for ( j = (FT_Long)num_glyphs - 1; j >= 0; j-- ) - charset->cids[charset->sids[j]] = (FT_UShort)j; + /* behaviour of recent Acroread versions. The loop stops when */ + /* the unsigned index wraps around after reaching zero. */ + for ( i = num_glyphs - 1; i < num_glyphs; i-- ) + charset->cids[charset->sids[i]] = (FT_UShort)i; charset->max_cid = max_cid; charset->num_glyphs = num_glyphs; @@ -926,7 +930,7 @@ goto Exit; /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* assign the .notdef glyph */ @@ -978,7 +982,7 @@ if ( glyph_sid > 0xFFFFL - nleft ) { FT_ERROR(( "cff_charset_load: invalid SID range trimmed" - " nleft=%d -> %d\n", nleft, 0xFFFFL - glyph_sid )); + " nleft=%u -> %ld\n", nleft, 0xFFFFL - glyph_sid )); nleft = ( FT_UInt )( 0xFFFFL - glyph_sid ); } @@ -1012,14 +1016,14 @@ case 0: if ( num_glyphs > 229 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe ISO-Latin)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe ISO-Latin)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1030,14 +1034,14 @@ case 1: if ( num_glyphs > 166 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe Expert)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1048,14 +1052,14 @@ case 2: if ( num_glyphs > 87 ) { - FT_ERROR(( "cff_charset_load: implicit charset larger than\n" - "predefined charset (Adobe Expert Subset)\n" )); + FT_ERROR(( "cff_charset_load: implicit charset larger than\n" )); + FT_ERROR(( "predefined charset (Adobe Expert Subset)\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } /* Allocate memory for sids. */ - if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) + if ( FT_QNEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ @@ -1081,7 +1085,6 @@ FT_FREE( charset->cids ); charset->format = 0; charset->offset = 0; - charset->sids = 0; } return error; @@ -1135,6 +1138,8 @@ { FT_UInt vsOffset; FT_UInt format; + FT_UInt dataCount; + FT_UInt regionCount; FT_ULong regionListOffset; @@ -1157,16 +1162,16 @@ } /* read top level fields */ - if ( FT_READ_ULONG( regionListOffset ) || - FT_READ_USHORT( vstore->dataCount ) ) + if ( FT_READ_ULONG( regionListOffset ) || + FT_READ_USHORT( dataCount ) ) goto Exit; /* make temporary copy of item variation data offsets; */ /* we'll parse region list first, then come back */ - if ( FT_NEW_ARRAY( dataOffsetArray, vstore->dataCount ) ) + if ( FT_QNEW_ARRAY( dataOffsetArray, dataCount ) ) goto Exit; - for ( i = 0; i < vstore->dataCount; i++ ) + for ( i = 0; i < dataCount; i++ ) { if ( FT_READ_ULONG( dataOffsetArray[i] ) ) goto Exit; @@ -1175,43 +1180,52 @@ /* parse regionList and axisLists */ if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) || FT_READ_USHORT( vstore->axisCount ) || - FT_READ_USHORT( vstore->regionCount ) ) + FT_READ_USHORT( regionCount ) ) goto Exit; - if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) ) + vstore->regionCount = 0; + if ( FT_QNEW_ARRAY( vstore->varRegionList, regionCount ) ) goto Exit; - for ( i = 0; i < vstore->regionCount; i++ ) + for ( i = 0; i < regionCount; i++ ) { CFF_VarRegion* region = &vstore->varRegionList[i]; - if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) ) + if ( FT_QNEW_ARRAY( region->axisList, vstore->axisCount ) ) goto Exit; + /* keep track of how many axisList to deallocate on error */ + vstore->regionCount++; + for ( j = 0; j < vstore->axisCount; j++ ) { CFF_AxisCoords* axis = ®ion->axisList[j]; - FT_Int16 start14, peak14, end14; + FT_Int start, peak, end; - if ( FT_READ_SHORT( start14 ) || - FT_READ_SHORT( peak14 ) || - FT_READ_SHORT( end14 ) ) + if ( FT_READ_SHORT( start ) || + FT_READ_SHORT( peak ) || + FT_READ_SHORT( end ) ) goto Exit; - axis->startCoord = FT_fdot14ToFixed( start14 ); - axis->peakCoord = FT_fdot14ToFixed( peak14 ); - axis->endCoord = FT_fdot14ToFixed( end14 ); + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; + + axis->startCoord = FT_fdot14ToFixed( start ); + axis->peakCoord = FT_fdot14ToFixed( peak ); + axis->endCoord = FT_fdot14ToFixed( end ); } } /* use dataOffsetArray now to parse varData items */ - if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) ) + vstore->dataCount = 0; + if ( FT_QNEW_ARRAY( vstore->varData, dataCount ) ) goto Exit; - for ( i = 0; i < vstore->dataCount; i++ ) + for ( i = 0; i < dataCount; i++ ) { CFF_VarData* data = &vstore->varData[i]; @@ -1230,9 +1244,12 @@ if ( FT_READ_USHORT( data->regionIdxCount ) ) goto Exit; - if ( FT_NEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) + if ( FT_QNEW_ARRAY( data->regionIndices, data->regionIdxCount ) ) goto Exit; + /* keep track of how many regionIndices to deallocate on error */ + vstore->dataCount++; + for ( j = 0; j < data->regionIdxCount; j++ ) { if ( FT_READ_USHORT( data->regionIndices[j] ) ) @@ -1275,7 +1292,7 @@ /* Blended values are written to a different buffer, */ /* using reserved operator 255. */ /* */ - /* Blend calculation is done in 16.16 fixed point. */ + /* Blend calculation is done in 16.16 fixed-point. */ FT_LOCAL_DEF( FT_Error ) cff_blend_doBlend( CFF_SubFont subFont, CFF_Parser parser, @@ -1298,7 +1315,7 @@ if ( numOperands > count ) { - FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d argument%s\n", + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %u argument%s\n", count, count == 1 ? "" : "s" )); @@ -1316,9 +1333,9 @@ /* increase or allocate `blend_stack' and reset `blend_top'; */ /* prepare to append `numBlends' values to the buffer */ - if ( FT_REALLOC( subFont->blend_stack, - subFont->blend_alloc, - subFont->blend_alloc + size ) ) + if ( FT_QREALLOC( subFont->blend_stack, + subFont->blend_alloc, + subFont->blend_alloc + size ) ) goto Exit; subFont->blend_top = subFont->blend_stack + subFont->blend_used; @@ -1348,27 +1365,28 @@ for ( i = 0; i < numBlends; i++ ) { const FT_Int32* weight = &blend->BV[1]; - FT_UInt32 sum; + FT_Fixed sum; /* convert inputs to 16.16 fixed point */ - sum = cff_parse_num( parser, &parser->stack[i + base] ) * 0x10000; + sum = cff_parse_fixed( parser, &parser->stack[i + base] ); for ( j = 1; j < blend->lenBV; j++ ) - sum += cff_parse_num( parser, &parser->stack[delta++] ) * *weight++; + sum += FT_MulFix( cff_parse_fixed( parser, &parser->stack[delta++] ), + *weight++ ); /* point parser stack to new value on blend_stack */ parser->stack[i + base] = subFont->blend_top; - /* Push blended result as Type 2 5-byte fixed point number. This */ + /* Push blended result as Type 2 5-byte fixed-point number. This */ /* will not conflict with actual DICTs because 255 is a reserved */ /* opcode in both CFF and CFF2 DICTs. See `cff_parse_num' for */ /* decode of this, which rounds to an integer. */ *subFont->blend_top++ = 255; - *subFont->blend_top++ = (FT_Byte)( sum >> 24 ); - *subFont->blend_top++ = (FT_Byte)( sum >> 16 ); - *subFont->blend_top++ = (FT_Byte)( sum >> 8 ); - *subFont->blend_top++ = (FT_Byte)sum; + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 24 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 16 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum >> 8 ); + *subFont->blend_top++ = (FT_Byte)( (FT_UInt32)sum ); } /* leave only numBlends results on parser stack */ @@ -1431,9 +1449,7 @@ /* prepare buffer for the blend vector */ len = varData->regionIdxCount + 1; /* add 1 for default component */ - if ( FT_REALLOC( blend->BV, - blend->lenBV * sizeof( *blend->BV ), - len * sizeof( *blend->BV ) ) ) + if ( FT_QRENEW_ARRAY( blend->BV, blend->lenBV, len ) ) goto Exit; blend->lenBV = len; @@ -1450,10 +1466,8 @@ if ( master == 0 ) { blend->BV[master] = FT_FIXED_ONE; - FT_TRACE4(( " build blend vector len %d\n" - " [ %f ", - len, - blend->BV[master] / 65536.0 )); + FT_TRACE4(( " build blend vector len %u\n", len )); + FT_TRACE4(( " [ %f ", blend->BV[master] / 65536.0 )); continue; } @@ -1485,44 +1499,31 @@ for ( j = 0; j < lenNDV; j++ ) { CFF_AxisCoords* axis = &varRegion->axisList[j]; - FT_Fixed axisScalar; - /* compute the scalar contribution of this axis; */ - /* ignore invalid ranges */ - if ( axis->startCoord > axis->peakCoord || - axis->peakCoord > axis->endCoord ) - axisScalar = FT_FIXED_ONE; - - else if ( axis->startCoord < 0 && - axis->endCoord > 0 && - axis->peakCoord != 0 ) - axisScalar = FT_FIXED_ONE; - - /* peak of 0 means ignore this axis */ - else if ( axis->peakCoord == 0 ) - axisScalar = FT_FIXED_ONE; + /* compute the scalar contribution of this axis */ + /* with peak of 0 used for invalid axes */ + if ( axis->peakCoord == NDV[j] || + axis->peakCoord == 0 ) + continue; /* ignore this region if coords are out of range */ - else if ( NDV[j] < axis->startCoord || - NDV[j] > axis->endCoord ) - axisScalar = 0; - - /* calculate a proportional factor */ - else + else if ( NDV[j] <= axis->startCoord || + NDV[j] >= axis->endCoord ) { - if ( NDV[j] == axis->peakCoord ) - axisScalar = FT_FIXED_ONE; - else if ( NDV[j] < axis->peakCoord ) - axisScalar = FT_DivFix( NDV[j] - axis->startCoord, - axis->peakCoord - axis->startCoord ); - else - axisScalar = FT_DivFix( axis->endCoord - NDV[j], - axis->endCoord - axis->peakCoord ); + blend->BV[master] = 0; + break; } - /* take product of all the axis scalars */ - blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar ); + /* adjust proportionally */ + else if ( NDV[j] < axis->peakCoord ) + blend->BV[master] = FT_MulDiv( blend->BV[master], + NDV[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* NDV[j] > axis->peakCoord ) */ + blend->BV[master] = FT_MulDiv( blend->BV[master], + axis->endCoord - NDV[j], + axis->endCoord - axis->peakCoord ); } FT_TRACE4(( ", %f ", @@ -1537,9 +1538,7 @@ if ( lenNDV != 0 ) { /* user has set a normalized vector */ - if ( FT_REALLOC( blend->lastNDV, - blend->lenNDV * sizeof ( *NDV ), - lenNDV * sizeof ( *NDV ) ) ) + if ( FT_QRENEW_ARRAY( blend->lastNDV, blend->lenNDV, lenNDV ) ) goto Exit; FT_MEM_COPY( blend->lastNDV, @@ -1582,16 +1581,17 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_LOCAL_DEF( FT_Error ) - cff_get_var_blend( CFF_Face face, + cff_get_var_blend( FT_Face face, /* CFF_Face */ FT_UInt *num_coords, FT_Fixed* *coords, FT_Fixed* *normalizedcoords, FT_MM_Var* *mm_var ) { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - return mm->get_var_blend( FT_FACE( face ), + return mm->get_var_blend( face, num_coords, coords, normalizedcoords, @@ -1600,13 +1600,14 @@ FT_LOCAL_DEF( void ) - cff_done_blend( CFF_Face face ) + cff_done_blend( FT_Face face ) /* CFF_Face */ { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + CFF_Face cffface = (CFF_Face)face; + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm; - if (mm) - mm->done_blend( FT_FACE( face ) ); + if ( mm ) + mm->done_blend( face ); } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ @@ -1643,13 +1644,6 @@ 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: */ @@ -1664,6 +1658,10 @@ if ( offset > 1 ) { + /* Zero out the code to gid/sid mappings. */ + FT_ARRAY_ZERO( encoding->sids, 256 ); + FT_ARRAY_ZERO( encoding->codes, 256 ); + encoding->offset = base_offset + offset; /* we need to parse the table to determine its size */ @@ -1821,7 +1819,8 @@ /* Construct code to GID mapping from code to SID mapping */ /* and charset. */ - encoding->count = 0; + encoding->offset = offset; /* used in cff_face_init */ + encoding->count = 0; error = cff_charset_compute_cids( charset, num_glyphs, stream->memory ); @@ -1945,7 +1944,7 @@ if ( priv->blue_shift > 1000 || priv->blue_shift < 0 ) { FT_TRACE2(( "cff_load_private_dict:" - " setting unlikely BlueShift value %d to default (7)\n", + " setting unlikely BlueShift value %ld to default (7)\n", priv->blue_shift )); priv->blue_shift = 7; } @@ -1953,7 +1952,7 @@ if ( priv->blue_fuzz > 1000 || priv->blue_fuzz < 0 ) { FT_TRACE2(( "cff_load_private_dict:" - " setting unlikely BlueFuzz value %d to default (1)\n", + " setting unlikely BlueFuzz value %ld to default (1)\n", priv->blue_fuzz )); priv->blue_fuzz = 1; } @@ -2004,7 +2003,7 @@ /* Top and Font DICTs are not allowed to have blend operators. */ error = cff_parser_init( &parser, code, - &subfont->font_dict, + top, font->library, stackSize, 0, @@ -2057,7 +2056,7 @@ if ( !error ) { FT_TRACE4(( " top dictionary:\n" )); - error = cff_parser_run( &parser, dict, dict + dict_len ); + error = cff_parser_run( &parser, dict, FT_OFFSET( dict, dict_len ) ); } /* clean up regardless of error */ @@ -2342,7 +2341,7 @@ if ( face_index > 0 && subfont_index >= font->name_index.count ) { FT_ERROR(( "cff_font_load:" - " invalid subfont index for pure CFF font (%d)\n", + " invalid subfont index for pure CFF font (%u)\n", subfont_index )); error = FT_THROW( Invalid_Argument ); goto Exit; @@ -2357,8 +2356,8 @@ if ( font->name_index.count > 1 ) { FT_ERROR(( "cff_font_load:" - " invalid CFF font with multiple subfonts\n" - " " + " invalid CFF font with multiple subfonts\n" )); + FT_ERROR(( " " " in SFNT wrapper\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; diff --git a/src/thirdparty/freetype2/src/cff/cffload.h b/src/thirdparty/freetype2/src/cff/cffload.h index 42d2696f3..fdc132c8f 100644 --- a/src/thirdparty/freetype2/src/cff/cffload.h +++ b/src/thirdparty/freetype2/src/cff/cffload.h @@ -4,7 +4,7 @@ * * OpenType & CFF data/program tables loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define CFFLOAD_H_ -#include -#include FT_INTERNAL_CFF_TYPES_H +#include #include "cffparse.h" -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H /* for CFF_Face */ +#include /* for CFF_Face */ FT_BEGIN_HEADER @@ -106,14 +105,14 @@ FT_BEGIN_HEADER #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_LOCAL( FT_Error ) - cff_get_var_blend( CFF_Face face, + cff_get_var_blend( FT_Face face, FT_UInt *num_coords, FT_Fixed* *coords, FT_Fixed* *normalizedcoords, FT_MM_Var* *mm_var ); FT_LOCAL( void ) - cff_done_blend( CFF_Face face ); + cff_done_blend( FT_Face face ); #endif diff --git a/src/thirdparty/freetype2/src/cff/cffobjs.c b/src/thirdparty/freetype2/src/cff/cffobjs.c index f76245f30..1aeb908f4 100644 --- a/src/thirdparty/freetype2/src/cff/cffobjs.c +++ b/src/thirdparty/freetype2/src/cff/cffobjs.c @@ -4,7 +4,7 @@ * * OpenType objects manager (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,33 +16,34 @@ */ -#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_DRIVER_H +#include +#include +#include +#include +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_METRICS_VARIATIONS_H +#include +#include +#include #endif -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H +#include #include "cffobjs.h" #include "cffload.h" #include "cffcmap.h" #include "cfferrs.h" -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include +#include +#define CFF_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) /************************************************************************** * @@ -70,8 +71,8 @@ FT_Module module; - module = FT_Get_Module( size->root.face->driver->root.library, - "pshinter" ); + module = FT_Get_Module( font->library, "pshinter" ); + return ( module && pshinter && pshinter->get_globals_funcs ) ? pshinter->get_globals_funcs( module ) : 0; @@ -125,19 +126,20 @@ 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]; + priv->blue_values[n] = CFF_fixedToInt( 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]; + priv->other_blues[n] = CFF_fixedToInt( 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]; + priv->family_blues[n] = CFF_fixedToInt( 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->family_other_blues[n] = + CFF_fixedToInt( cpriv->family_other_blues[n] ); priv->blue_scale = cpriv->blue_scale; priv->blue_shift = (FT_Int)cpriv->blue_shift; @@ -167,46 +169,54 @@ FT_Error error = FT_Err_Ok; PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size ); + FT_Memory memory = cffsize->face->memory; + CFF_Internal internal = NULL; + CFF_Face face = (CFF_Face)cffsize->face; + CFF_Font font = (CFF_Font)face->extra.data; - if ( funcs ) + PS_PrivateRec priv; + + FT_UInt i; + + if ( !funcs ) + goto Exit; + + if ( FT_NEW( internal ) ) + goto Exit; + + cff_make_private_dict( &font->top_font, &priv ); + error = funcs->create( memory, &priv, &internal->topfont ); + if ( error ) + goto Exit; + + for ( i = font->num_subfonts; i > 0; i-- ) { - CFF_Face face = (CFF_Face)cffsize->face; - CFF_Font font = (CFF_Font)face->extra.data; - CFF_Internal internal = NULL; - - PS_PrivateRec priv; - FT_Memory memory = cffsize->face->memory; - - FT_UInt i; + CFF_SubFont sub = font->subfonts[i - 1]; - if ( FT_NEW( internal ) ) - goto Exit; - - cff_make_private_dict( &font->top_font, &priv ); - error = funcs->create( cffsize->face->memory, &priv, - &internal->topfont ); + cff_make_private_dict( sub, &priv ); + error = funcs->create( memory, &priv, &internal->subfonts[i - 1] ); if ( error ) goto Exit; - - for ( i = font->num_subfonts; i > 0; i-- ) - { - CFF_SubFont sub = font->subfonts[i - 1]; - - - cff_make_private_dict( sub, &priv ); - error = funcs->create( cffsize->face->memory, &priv, - &internal->subfonts[i - 1] ); - if ( error ) - goto Exit; - } - - cffsize->internal->module_data = internal; } + cffsize->internal->module_data = internal; + size->strike_index = 0xFFFFFFFFUL; Exit: + if ( error ) + { + if ( internal ) + { + for ( i = font->num_subfonts; i > 0; i-- ) + FT_FREE( internal->subfonts[i - 1] ); + FT_FREE( internal->topfont ); + } + + FT_FREE( internal ); + } + return error; } @@ -274,6 +284,8 @@ cff_size_request( FT_Size size, FT_Size_Request req ) { + FT_Error error; + CFF_Size cffsize = (CFF_Size)size; PSH_Globals_Funcs funcs; @@ -295,7 +307,9 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - FT_Request_Metrics( size->face, req ); + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; funcs = cff_size_get_globals_funcs( cffsize ); @@ -336,7 +350,8 @@ } } - return FT_Err_Ok; + Exit: + return error; } @@ -349,7 +364,8 @@ FT_LOCAL_DEF( void ) cff_slot_done( FT_GlyphSlot slot ) { - slot->internal->glyph_hints = NULL; + if ( slot->internal ) + slot->internal->glyph_hints = NULL; } @@ -366,8 +382,7 @@ FT_Module module; - module = FT_Get_Module( slot->face->driver->root.library, - "pshinter" ); + module = FT_Get_Module( slot->library, "pshinter" ); if ( module ) { T2_Hints_Funcs funcs; @@ -396,9 +411,7 @@ FT_String* result; - (void)FT_STRDUP( result, source ); - - FT_UNUSED( error ); + FT_MEM_STRDUP( result, source ); return result; } @@ -411,32 +424,23 @@ static void remove_subset_prefix( FT_String* name ) { - FT_Int32 idx = 0; - FT_Int32 length = (FT_Int32)ft_strlen( name ) + 1; - FT_Bool continue_search = 1; + FT_UInt32 i = 0, idx = 0; - while ( continue_search ) + /* six ASCII uppercase letters followed by a plus sign */ + while ( 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + 'A' <= name[i] && name[i++] <= 'Z' && + name[i++] == '+' ) { - if ( length >= 7 && name[6] == '+' ) - { - for ( idx = 0; idx < 6; idx++ ) - { - /* ASCII uppercase letters */ - if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) ) - continue_search = 0; - } - - if ( continue_search ) - { - for ( idx = 7; idx < length; idx++ ) - name[idx - 7] = name[idx]; - length -= 7; - } - } - else - continue_search = 0; + idx = i; } + + if ( idx ) + FT_MEM_MOVE( name, name + idx, ft_strlen( name + idx ) + 1 ); } @@ -446,42 +450,20 @@ remove_style( FT_String* family_name, const FT_String* style_name ) { - FT_Int32 family_name_length, style_name_length; + FT_String* f = family_name + ft_strlen( family_name ); + const FT_String* s = style_name + ft_strlen( style_name ); - family_name_length = (FT_Int32)ft_strlen( family_name ); - style_name_length = (FT_Int32)ft_strlen( style_name ); + /* compare strings moving backwards */ + while ( s > style_name ) + if ( f == family_name || *--s != *--f ) + return; - if ( family_name_length > style_name_length ) - { - FT_Int idx; - - - for ( idx = 1; idx <= style_name_length; idx++ ) - { - if ( family_name[family_name_length - idx] != - style_name[style_name_length - idx] ) - break; - } - - if ( idx > style_name_length ) - { - /* family_name ends with style_name; remove it */ - idx = family_name_length - style_name_length - 1; - - /* also remove special characters */ - /* between real family name and style */ - while ( idx > 0 && - ( family_name[idx] == '-' || - family_name[idx] == ' ' || - family_name[idx] == '_' || - family_name[idx] == '+' ) ) - idx--; - - if ( idx > 0 ) - family_name[idx + 1] = '\0'; - } - } + /* terminate and remove special characters */ + do + *f = '\0'; + while ( f-- > family_name && + ( *f == '-' || *f == ' ' || *f == '_' || *f == '+' ) ); } @@ -555,8 +537,8 @@ 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 */ + /* the font may be OpenType/CFF, SVG CEF, or sfnt/CFF; a `head' table */ + /* implies OpenType/CFF, otherwise just look for an optional cmap */ error = face->goto_table( face, TTAG_head, stream, 0 ); if ( !error ) { @@ -572,7 +554,9 @@ { /* load the `cmap' table explicitly */ error = sfnt->load_cmap( face, stream ); - if ( error ) + + /* this may fail because CID-keyed fonts don't have a cmap */ + if ( FT_ERR_NEQ( error, Table_Missing ) && FT_ERR_NEQ( error, Ok ) ) goto Exit; } @@ -649,8 +633,8 @@ if ( dict->cid_registry == 0xFFFFU && !psnames ) { FT_ERROR(( "cff_face_init:" - " cannot open CFF & CEF fonts\n" - " " + " cannot open CFF & CEF fonts\n" )); + FT_ERROR(( " " " without the `psnames' module\n" )); error = FT_THROW( Missing_Module ); goto Exit; @@ -669,22 +653,22 @@ { s = cff_index_get_sid_string( cff, idx ); if ( s ) - FT_TRACE4(( " %5d %s\n", idx, s )); + FT_TRACE4(( " %5u %s\n", idx, s )); } /* In Multiple Master CFFs, two SIDs hold the Normalize Design */ /* Vector (NDV) and Convert Design Vector (CDV) charstrings, */ - /* which may contain NULL bytes in the middle of the data, too. */ + /* which may contain null bytes in the middle of the data, too. */ /* We thus access `cff->strings' directly. */ for ( idx = 1; idx < cff->num_strings; idx++ ) { FT_Byte* s1 = cff->strings[idx - 1]; FT_Byte* s2 = cff->strings[idx]; - FT_PtrDist s1len = s2 - s1 - 1; /* without the final NULL byte */ + FT_PtrDist s1len = s2 - s1 - 1; /* without the final null byte */ FT_PtrDist l; - FT_TRACE4(( " %5d ", idx + 390 )); + FT_TRACE4(( " %5u ", idx + 390 )); for ( l = 0; l < s1len; l++ ) FT_TRACE4(( "%c", s1[l] )); FT_TRACE4(( "\n" )); @@ -699,7 +683,7 @@ FT_PtrDist l; - FT_TRACE4(( " %5d ", cff->num_strings + 390 )); + FT_TRACE4(( " %5u ", cff->num_strings + 390 )); for ( l = 0; l < s1len; l++ ) FT_TRACE4(( "%c", s1[l] )); FT_TRACE4(( "\n" )); @@ -709,22 +693,14 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT { - FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; - FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var; - FT_UInt instance_index = (FT_UInt)face_index >> 16; - if ( FT_HAS_MULTIPLE_MASTERS( cffface ) && - mm && - instance_index > 0 ) + if ( FT_HAS_MULTIPLE_MASTERS( cffface ) ) { - error = mm->set_instance( cffface, instance_index ); + error = FT_Set_Named_Instance( cffface, instance_index ); if ( error ) goto Exit; - - if ( var ) - var->metrics_adjust( cffface ); } } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ @@ -940,7 +916,8 @@ style_name = cff_strcpy( memory, fullp ); /* remove the style part from the family name (if present) */ - remove_style( cffface->family_name, style_name ); + if ( style_name ) + remove_style( cffface->family_name, style_name ); } break; } @@ -1017,12 +994,10 @@ cffface->style_flags = flags; } -#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 ) + /* CID-keyed CFF or CFF2 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 && !cff2 ) cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; -#endif if ( dict->cid_registry != 0xFFFFU && pure_cff ) cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; @@ -1038,11 +1013,11 @@ { FT_CharMapRec cmaprec; FT_CharMap cmap; - FT_UInt nn; + FT_Int nn; CFF_Encoding encoding = &cff->encoding; - for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) + for ( nn = 0; nn < cffface->num_charmaps; nn++ ) { cmap = cffface->charmaps[nn]; @@ -1067,7 +1042,7 @@ cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; cmaprec.encoding = FT_ENCODING_UNICODE; - nn = (FT_UInt)cffface->num_charmaps; + nn = cffface->num_charmaps; error = FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL ); @@ -1078,7 +1053,7 @@ error = FT_Err_Ok; /* if no Unicode charmap was previously selected, select this one */ - if ( !cffface->charmap && nn != (FT_UInt)cffface->num_charmaps ) + if ( !cffface->charmap && nn != cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: @@ -1148,7 +1123,7 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - cff_done_blend( face ); + cff_done_blend( cffface ); face->blend = NULL; #endif } @@ -1163,11 +1138,7 @@ /* set default property values, cf. `ftcffdrv.h' */ -#ifdef CFF_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff --git a/src/thirdparty/freetype2/src/cff/cffobjs.h b/src/thirdparty/freetype2/src/cff/cffobjs.h index 03bc78a67..982dcd64d 100644 --- a/src/thirdparty/freetype2/src/cff/cffobjs.h +++ b/src/thirdparty/freetype2/src/cff/cffobjs.h @@ -4,7 +4,7 @@ * * OpenType objects manager (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define CFFOBJS_H_ -#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/cff/cffparse.c b/src/thirdparty/freetype2/src/cff/cffparse.c index 008752c3a..864b2490b 100644 --- a/src/thirdparty/freetype2/src/cff/cffparse.c +++ b/src/thirdparty/freetype2/src/cff/cffparse.c @@ -4,7 +4,7 @@ * * CFF token stream parser (body) * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ */ -#include #include "cffparse.h" -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_LIST_H +#include +#include +#include +#include +#include #include "cfferrs.h" #include "cffload.h" @@ -63,11 +62,8 @@ parser->num_axes = num_axes; /* allocate the stack buffer */ - if ( FT_NEW_ARRAY( parser->stack, stackSize ) ) - { - FT_FREE( parser->stack ); + if ( FT_QNEW_ARRAY( parser->stack, stackSize ) ) goto Exit; - } parser->stackSize = stackSize; parser->top = parser->stack; /* empty stack */ @@ -77,23 +73,6 @@ } -#ifdef CFF_CONFIG_OPTION_OLD_ENGINE - static void - finalize_t2_strings( FT_Memory memory, - void* data, - void* user ) - { - CFF_T2_String t2 = (CFF_T2_String)data; - - - FT_UNUSED( user ); - - memory->free( memory, t2->start ); - memory->free( memory, data ); - } -#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ - - FT_LOCAL_DEF( void ) cff_parser_done( CFF_Parser parser ) { @@ -103,63 +82,19 @@ FT_FREE( parser->stack ); #ifdef CFF_CONFIG_OPTION_OLD_ENGINE - FT_List_Finalize( &parser->t2_strings, - finalize_t2_strings, - memory, - NULL ); + FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL ); #endif } - /* Assuming `first >= last'. */ - - static FT_Error - cff_parser_within_limits( CFF_Parser parser, - FT_Byte* first, - FT_Byte* last ) - { -#ifndef CFF_CONFIG_OPTION_OLD_ENGINE - - /* Fast path for regular FreeType builds with the "new" engine; */ - /* `first >= parser->start' can be assumed. */ - - FT_UNUSED( first ); - - return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument ); - -#else /* CFF_CONFIG_OPTION_OLD_ENGINE */ - - FT_ListNode node; - - - if ( first >= parser->start && - last < parser->limit ) - return FT_Err_Ok; - - node = parser->t2_strings.head; - - while ( node ) - { - CFF_T2_String t2 = (CFF_T2_String)node->data; - - - if ( first >= t2->start && - last < t2->limit ) - return FT_Err_Ok; - - node = node->next; - } - - return FT_THROW( Invalid_Argument ); - -#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ - } - + /* The parser limit checks in the next two functions are supposed */ + /* to detect the immediate crossing of the stream boundary. They */ + /* shall not be triggered from the distant t2_strings buffers. */ /* read an integer */ static FT_Long - cff_parse_integer( CFF_Parser parser, - FT_Byte* start ) + cff_parse_integer( FT_Byte* start, + FT_Byte* limit ) { FT_Byte* p = start; FT_Int v = *p++; @@ -168,14 +103,14 @@ if ( v == 28 ) { - if ( cff_parser_within_limits( parser, p, p + 1 ) ) + if ( p + 2 > limit && limit >= p ) goto Bad; val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] ); } else if ( v == 29 ) { - if ( cff_parser_within_limits( parser, p, p + 3 ) ) + if ( p + 4 > limit && limit >= p ) goto Bad; val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) | @@ -189,14 +124,14 @@ } else if ( v < 251 ) { - if ( cff_parser_within_limits( parser, p, p ) ) + if ( p + 1 > limit && limit >= p ) goto Bad; val = ( v - 247 ) * 256 + p[0] + 108; } else { - if ( cff_parser_within_limits( parser, p, p ) ) + if ( p + 1 > limit && limit >= p ) goto Bad; val = -( v - 251 ) * 256 - p[0] - 108; @@ -245,10 +180,10 @@ /* read a real */ static FT_Fixed - cff_parse_real( CFF_Parser parser, - FT_Byte* start, - FT_Long power_ten, - FT_Long* scaling ) + cff_parse_real( FT_Byte* start, + FT_Byte* limit, + FT_Long power_ten, + FT_Long* scaling ) { FT_Byte* p = start; FT_Int nib; @@ -283,7 +218,7 @@ p++; /* Make sure we don't read past the end. */ - if ( cff_parser_within_limits( parser, p, p ) ) + if ( p + 1 > limit && limit >= p ) goto Bad; } @@ -320,7 +255,7 @@ p++; /* Make sure we don't read past the end. */ - if ( cff_parser_within_limits( parser, p, p ) ) + if ( p + 1 > limit && limit >= p ) goto Bad; } @@ -359,7 +294,7 @@ p++; /* Make sure we don't read past the end. */ - if ( cff_parser_within_limits( parser, p, p ) ) + if ( p + 1 > limit && limit >= p ) goto Bad; } @@ -526,12 +461,12 @@ if ( **d == 30 ) { /* binary-coded decimal is truncated to integer */ - return cff_parse_real( parser, *d, 0, NULL ) >> 16; + return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16; } else if ( **d == 255 ) { - /* 16.16 fixed point is used internally for CFF2 blend results. */ + /* 16.16 fixed-point is used internally for CFF2 blend results. */ /* Since these are trusted values, a limit check is not needed. */ /* After the 255, 4 bytes give the number. */ @@ -552,7 +487,7 @@ } else - return cff_parse_integer( parser, *d ); + return cff_parse_integer( *d, parser->limit ); } @@ -563,15 +498,33 @@ FT_Long scaling ) { if ( **d == 30 ) - return cff_parse_real( parser, *d, scaling, NULL ); - else + return cff_parse_real( *d, parser->limit, scaling, NULL ); + else if ( **d == 255 ) { - FT_Long val = cff_parse_integer( parser, *d ); - + FT_Fixed val = (FT_Int32)( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) | + ( (FT_UInt32)*( d[0] + 2 ) << 16 ) | + ( (FT_UInt32)*( d[0] + 3 ) << 8 ) | + (FT_UInt32)*( d[0] + 4 ) ) ); if ( scaling ) { if ( FT_ABS( val ) > power_ten_limits[scaling] ) + { + FT_TRACE4(( "!!!OVERFLOW:!!!" )); + return val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; + } + val *= power_tens[scaling]; + } + return val; + } + else + { + FT_Long val = cff_parse_integer( *d, parser->limit ); + + + if ( scaling ) + { + if ( ( FT_ABS( val ) << 16 ) > power_ten_limits[scaling] ) { val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL; goto Overflow; @@ -601,7 +554,7 @@ /* read a floating point number, either integer or real */ - static FT_Fixed + FT_LOCAL_DEF( FT_Fixed ) cff_parse_fixed( CFF_Parser parser, FT_Byte** d ) { @@ -631,14 +584,14 @@ FT_ASSERT( scaling ); if ( **d == 30 ) - return cff_parse_real( parser, *d, 0, scaling ); + return cff_parse_real( *d, parser->limit, 0, scaling ); else { FT_Long number; FT_Int integer_length; - number = cff_parse_integer( parser, d[0] ); + number = cff_parse_integer( *d, parser->limit ); if ( number > 0x7FFFL ) { @@ -687,7 +640,7 @@ dict->has_font_matrix = TRUE; - /* We expect a well-formed font matrix, this is, the matrix elements */ + /* We expect a well-formed font matrix, that is, the matrix elements */ /* `xx' and `yy' are of approximately the same magnitude. To avoid */ /* loss of precision, we use the magnitude of the largest matrix */ /* element to scale all other elements. The scaling factor is then */ @@ -714,9 +667,10 @@ ( max_scaling - min_scaling ) > 9 ) { FT_TRACE1(( "cff_parse_font_matrix:" - " strange scaling values (minimum %d, maximum %d),\n" - " " - " using default matrix\n", min_scaling, max_scaling )); + " strange scaling values (minimum %ld, maximum %ld),\n", + min_scaling, max_scaling )); + FT_TRACE1(( " " + " using default matrix\n" )); goto Unlikely; } @@ -758,12 +712,12 @@ *upm = (FT_ULong)power_tens[-max_scaling]; FT_TRACE4(( " [%f %f %f %f %f %f]\n", - (double)matrix->xx / *upm / 65536, - (double)matrix->xy / *upm / 65536, - (double)matrix->yx / *upm / 65536, - (double)matrix->yy / *upm / 65536, - (double)offset->x / *upm / 65536, - (double)offset->y / *upm / 65536 )); + (double)matrix->xx / (double)*upm / 65536, + (double)matrix->xy / (double)*upm / 65536, + (double)matrix->yx / (double)*upm / 65536, + (double)matrix->yy / (double)*upm / 65536, + (double)offset->x / (double)*upm / 65536, + (double)offset->y / (double)*upm / 65536 )); if ( !FT_Matrix_Check( matrix ) ) { @@ -811,7 +765,7 @@ bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) ); error = FT_Err_Ok; - FT_TRACE4(( " [%d %d %d %d]\n", + FT_TRACE4(( " [%ld %ld %ld %ld]\n", bbox->xMin / 65536, bbox->yMin / 65536, bbox->xMax / 65536, @@ -934,11 +888,11 @@ FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" )); dict->cid_supplement = cff_parse_num( parser, data ); if ( dict->cid_supplement < 0 ) - FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n", + FT_TRACE1(( "cff_parse_cid_ros: negative supplement %ld is found\n", dict->cid_supplement )); error = FT_Err_Ok; - FT_TRACE4(( " %d %d %d\n", + FT_TRACE4(( " %u %u %ld\n", dict->cid_registry, dict->cid_ordering, dict->cid_supplement )); @@ -975,7 +929,7 @@ priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); - FT_TRACE4(( " %d\n", priv->vsindex )); + FT_TRACE4(( " %u\n", priv->vsindex )); error = FT_Err_Ok; @@ -1025,7 +979,7 @@ goto Exit; } - FT_TRACE4(( " %d value%s blended\n", + FT_TRACE4(( " %u value%s blended\n", numBlends, numBlends == 1 ? "" : "s" )); @@ -1060,7 +1014,7 @@ if ( dict->maxstack < CFF2_DEFAULT_STACK ) dict->maxstack = CFF2_DEFAULT_STACK; - FT_TRACE4(( " %d\n", dict->maxstack )); + FT_TRACE4(( " %u\n", dict->maxstack )); Exit: return error; @@ -1077,10 +1031,14 @@ CFF_FIELD( code, name, id, cff_kind_string ) #define CFF_FIELD_BOOL( code, name, id ) \ CFF_FIELD( code, name, id, cff_kind_bool ) +#define CFF_FIELD_DELTA( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta ) +#define CFF_FIELD_DELTA_FIXED( code, name, max, id ) \ + CFF_FIELD_DELTA_KIND( code, name, max, id, cff_kind_delta_fixed ) #undef CFF_FIELD -#undef CFF_FIELD_DELTA +#undef CFF_FIELD_DELTA_KIND #ifndef FT_DEBUG_LEVEL_TRACE @@ -1110,18 +1068,18 @@ code | CFFCODE, \ FT_FIELD_OFFSET( name ), \ FT_FIELD_SIZE( name ), \ - 0, 0, 0 \ + NULL, 0, 0 \ }, -#define CFF_FIELD_DELTA( code, name, max, id ) \ - { \ - cff_kind_delta, \ - code | CFFCODE, \ - FT_FIELD_OFFSET( name ), \ - FT_FIELD_SIZE_DELTA( name ), \ - 0, \ - max, \ - FT_FIELD_OFFSET( num_ ## name ) \ +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ) \ }, static const CFF_Field_Handler cff_field_handlers[] = @@ -1129,7 +1087,7 @@ #include "cfftoken.h" - { 0, 0, 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, NULL, 0, 0 } }; @@ -1163,20 +1121,20 @@ code | CFFCODE, \ FT_FIELD_OFFSET( name ), \ FT_FIELD_SIZE( name ), \ - 0, 0, 0, \ + NULL, 0, 0, \ id \ }, -#define CFF_FIELD_DELTA( code, name, max, id ) \ - { \ - cff_kind_delta, \ - code | CFFCODE, \ - FT_FIELD_OFFSET( name ), \ - FT_FIELD_SIZE_DELTA( name ), \ - 0, \ - max, \ - FT_FIELD_OFFSET( num_ ## name ), \ - id \ +#define CFF_FIELD_DELTA_KIND( code, name, max, id, kind ) \ + { \ + kind, \ + code | CFFCODE, \ + FT_FIELD_OFFSET( name ), \ + FT_FIELD_SIZE_DELTA( name ), \ + NULL, \ + max, \ + FT_FIELD_OFFSET( num_ ## name ), \ + id \ }, static const CFF_Field_Handler cff_field_handlers[] = @@ -1184,7 +1142,7 @@ #include "cfftoken.h" - { 0, 0, 0, 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, NULL, 0, 0, NULL } }; @@ -1264,11 +1222,8 @@ FT_Byte* charstring_base; FT_ULong charstring_len; - FT_Fixed* stack; - FT_ListNode node; - CFF_T2_String t2; - size_t t2_size; - FT_Byte* q; + FT_Fixed* stack; + FT_Byte* q = NULL; charstring_base = ++p; @@ -1309,39 +1264,18 @@ /* Now copy the stack data in the temporary decoder object, */ /* converting it back to charstring number representations */ /* (this is ugly, I know). */ + /* The maximum required size is 5 bytes per stack element. */ + if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) + + 5 * ( decoder.top - decoder.stack ) ) ) + goto Exit; - node = (FT_ListNode)memory->alloc( memory, - sizeof ( FT_ListNodeRec ) ); - if ( !node ) - goto Out_Of_Memory_Error; + FT_List_Add( &parser->t2_strings, (FT_ListNode)q ); - FT_List_Add( &parser->t2_strings, node ); + q += 2 * sizeof ( FT_ListNode ); - t2 = (CFF_T2_String)memory->alloc( memory, - sizeof ( CFF_T2_StringRec ) ); - if ( !t2 ) - goto Out_Of_Memory_Error; - - node->data = t2; - - /* `5' is the conservative upper bound of required bytes per stack */ - /* element. */ - - t2_size = 5 * ( decoder.top - decoder.stack ); - - q = (FT_Byte*)memory->alloc( memory, t2_size ); - if ( !q ) - goto Out_Of_Memory_Error; - - t2->start = q; - t2->limit = q + t2_size; - - stack = decoder.stack; - - while ( stack < decoder.top ) + for ( stack = decoder.stack; stack < decoder.top; stack++ ) { - FT_ULong num; - FT_Bool neg; + FT_Long num = *stack; if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize ) @@ -1349,69 +1283,37 @@ *parser->top++ = q; - if ( *stack < 0 ) - { - num = (FT_ULong)NEG_LONG( *stack ); - neg = 1; - } - else - { - num = (FT_ULong)*stack; - neg = 0; - } - if ( num & 0xFFFFU ) { - if ( neg ) - num = (FT_ULong)-num; - *q++ = 255; - *q++ = ( num & 0xFF000000U ) >> 24; - *q++ = ( num & 0x00FF0000U ) >> 16; - *q++ = ( num & 0x0000FF00U ) >> 8; - *q++ = num & 0x000000FFU; + *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF ); + *q++ = (FT_Byte)( ( num >> 8 ) & 0xFF ); + *q++ = (FT_Byte)( ( num ) & 0xFF ); } else { num >>= 16; - if ( neg ) + if ( -107 <= num && num <= 107 ) + *q++ = (FT_Byte)( num + 139 ); + else if ( 108 <= num && num <= 1131 ) { - if ( num <= 107 ) - *q++ = (FT_Byte)( 139 - num ); - else if ( num <= 1131 ) - { - *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 ); - *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); - } - else - { - num = (FT_ULong)-num; - - *q++ = 28; - *q++ = (FT_Byte)( num >> 8 ); - *q++ = (FT_Byte)( num & 0xFF ); - } + *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); + *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); + } + else if ( -1131 <= num && num <= -108 ) + { + *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 ); + *q++ = (FT_Byte)( ( -num - 108) & 0xFF ); } else { - if ( num <= 107 ) - *q++ = (FT_Byte)( num + 139 ); - else if ( num <= 1131 ) - { - *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 ); - *q++ = (FT_Byte)( ( num - 108 ) & 0xFF ); - } - else - { - *q++ = 28; - *q++ = (FT_Byte)( num >> 8 ); - *q++ = (FT_Byte)( num & 0xFF ); - } + *q++ = 28; + *q++ = (FT_Byte)( num >> 8 ); + *q++ = (FT_Byte)( num & 0xFF ); } } - - stack++; } } #endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ @@ -1458,7 +1360,8 @@ /* check that we have enough arguments -- except for */ /* delta encoded arrays, which can be empty */ - if ( field->kind != cff_kind_delta && num_args < 1 ) + if ( field->kind != cff_kind_delta && + field->kind != cff_kind_delta_fixed && num_args < 1 ) goto Stack_Underflow; switch ( field->kind ) @@ -1516,6 +1419,7 @@ case cff_kind_fixed_thousand: FT_TRACE4(( " %f\n", (double)val / 65536 / 1000 )); + break; default: ; /* never reached */ @@ -1572,6 +1476,38 @@ } break; + case cff_kind_delta_fixed: + { + 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; + + FT_TRACE4(( " [" )); + + /* store count */ + *qcount = (FT_Byte)num_args; + + val = 0; + while ( num_args > 0 ) + { + val = ADD_LONG( val, cff_parse_fixed( parser, data++ ) ); + *(FT_Long*)q = val; + + FT_TRACE4(( " %f\n", (double)val / 65536 )); + + q += field->size; + num_args--; + } + + FT_TRACE4(( "]\n" )); + } + break; + default: /* callback or blend */ error = field->reader( parser ); if ( error ) @@ -1597,12 +1533,6 @@ Exit: return error; -#ifdef CFF_CONFIG_OPTION_OLD_ENGINE - Out_Of_Memory_Error: - error = FT_THROW( Out_Of_Memory ); - goto Exit; -#endif - Stack_Overflow: error = FT_THROW( Invalid_Argument ); goto Exit; diff --git a/src/thirdparty/freetype2/src/cff/cffparse.h b/src/thirdparty/freetype2/src/cff/cffparse.h index 4e74709a2..47cceb1a4 100644 --- a/src/thirdparty/freetype2/src/cff/cffparse.h +++ b/src/thirdparty/freetype2/src/cff/cffparse.h @@ -4,7 +4,7 @@ * * CFF token stream parser (specification) * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define CFFPARSE_H_ -#include -#include FT_INTERNAL_CFF_TYPES_H -#include FT_INTERNAL_OBJECTS_H +#include +#include FT_BEGIN_HEADER @@ -77,6 +76,10 @@ FT_BEGIN_HEADER cff_parse_num( CFF_Parser parser, FT_Byte** d ); + FT_LOCAL( FT_Fixed ) + cff_parse_fixed( CFF_Parser parser, + FT_Byte** d ); + FT_LOCAL( FT_Error ) cff_parser_init( CFF_Parser parser, FT_UInt code, @@ -104,6 +107,7 @@ FT_BEGIN_HEADER cff_kind_string, cff_kind_bool, cff_kind_delta, + cff_kind_delta_fixed, cff_kind_callback, cff_kind_blend, @@ -134,15 +138,6 @@ FT_BEGIN_HEADER FT_END_HEADER -#ifdef CFF_CONFIG_OPTION_OLD_ENGINE - typedef struct CFF_T2_String_ - { - FT_Byte* start; - FT_Byte* limit; - - } CFF_T2_StringRec, *CFF_T2_String; -#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */ - #endif /* CFFPARSE_H_ */ diff --git a/src/thirdparty/freetype2/src/cff/cfftoken.h b/src/thirdparty/freetype2/src/cff/cfftoken.h index 063a7b3be..cc5aaa286 100644 --- a/src/thirdparty/freetype2/src/cff/cfftoken.h +++ b/src/thirdparty/freetype2/src/cff/cfftoken.h @@ -4,7 +4,7 @@ * * CFF token definitions (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -80,26 +80,26 @@ #undef CFFCODE #define CFFCODE CFF_CODE_PRIVATE - CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) - CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) - CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) - CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) - CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) - CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) - CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) - CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) - CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) - CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) - CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) - CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) - CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) - CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) - CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) - CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) - CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) - CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) - CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) - CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_BOOL ( 0x10E, force_bold, "ForceBold" ) + CFF_FIELD_FIXED ( 0x10F, force_bold_threshold, "ForceBoldThreshold" ) + CFF_FIELD_NUM ( 0x110, lenIV, "lenIV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_NUM ( 0x113, initial_random_seed, "initialRandomSeed" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" ) + CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" ) #undef FT_STRUCTURE @@ -129,22 +129,22 @@ #undef CFFCODE #define CFFCODE CFF2_CODE_PRIVATE - CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" ) - CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" ) - CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" ) - CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" ) - CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" ) - CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) - CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) - CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) - CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) - CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) - CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) - CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) - CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) - CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) - CFF_FIELD_BLEND ( 23, "blend" ) - CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) + CFF_FIELD_DELTA_FIXED( 6, blue_values, 14, "BlueValues" ) + CFF_FIELD_DELTA_FIXED( 7, other_blues, 10, "OtherBlues" ) + CFF_FIELD_DELTA_FIXED( 8, family_blues, 14, "FamilyBlues" ) + CFF_FIELD_DELTA_FIXED( 9, family_other_blues, 10, "FamilyOtherBlues" ) + CFF_FIELD_FIXED_1000 ( 0x109, blue_scale, "BlueScale" ) + CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" ) + CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" ) + CFF_FIELD_NUM ( 10, standard_width, "StdHW" ) + CFF_FIELD_NUM ( 11, standard_height, "StdVW" ) + CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" ) + CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) + CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) + CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) + CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) + CFF_FIELD_BLEND ( 23, "blend" ) + CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) /* END */ diff --git a/src/thirdparty/freetype2/src/cid/ciderrs.h b/src/thirdparty/freetype2/src/cid/ciderrs.h index be80bed3b..1591979d3 100644 --- a/src/thirdparty/freetype2/src/cid/ciderrs.h +++ b/src/thirdparty/freetype2/src/cid/ciderrs.h @@ -4,7 +4,7 @@ * * CID error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef CIDERRS_H_ #define CIDERRS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX CID_Err_ #define FT_ERR_BASE FT_Mod_Err_CID -#include FT_ERRORS_H +#include #endif /* CIDERRS_H_ */ diff --git a/src/thirdparty/freetype2/src/cid/cidgload.c b/src/thirdparty/freetype2/src/cid/cidgload.c index f59f2880f..249ede575 100644 --- a/src/thirdparty/freetype2/src/cid/cidgload.c +++ b/src/thirdparty/freetype2/src/cid/cidgload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 Glyph Loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,17 +16,16 @@ */ -#include #include "cidload.h" #include "cidgload.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_OUTLINE_H -#include FT_INTERNAL_CALC_H +#include +#include +#include +#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_CFF_TYPES_H -#include FT_DRIVER_H +#include +#include +#include #include "ciderrs.h" @@ -41,6 +40,117 @@ #define FT_COMPONENT cidgload + /* + * A helper function to compute FD number (`fd_select`), the offset to the + * head of the glyph data (`off1`), and the offset to the and of the glyph + * data (`off2`). + * + * The number how many times `cid_get_offset` is invoked can be controlled + * by the number of non-NULL arguments. If `fd_select` is non-NULL but + * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for + * `fd_select`; `off1` and `off2` are not validated. + * + */ + FT_LOCAL_DEF( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ) + { + FT_Error error = FT_Err_Ok; + + CID_FaceInfo cid = &face->cid; + FT_Stream stream = face->cid_stream; + FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes; + + FT_Byte* p; + FT_Bool need_frame_exit = 0; + FT_ULong fd_select, off1, off2; + + + /* For ordinary fonts, read the CID font dictionary index */ + /* and charstring offset from the CIDMap. */ + + if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + + glyph_index * entry_len ) || + FT_FRAME_ENTER( 2 * entry_len ) ) + goto Exit; + + need_frame_exit = 1; + + p = (FT_Byte*)stream->cursor; + fd_select = cid_get_offset( &p, cid->fd_bytes ); + off1 = cid_get_offset( &p, cid->gd_bytes ); + + p += cid->fd_bytes; + off2 = cid_get_offset( &p, cid->gd_bytes ); + + if ( fd_select_p ) + *fd_select_p = fd_select; + if ( off1_p ) + *off1_p = off1; + if ( off2_p ) + *off2_p = off2; + + if ( fd_select >= cid->num_dicts ) + { + /* + * fd_select == 0xFF is often used to indicate that the CID + * has no charstring to be rendered, similar to GID = 0xFFFF + * in TrueType fonts. + */ + if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) || + ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) + { + FT_TRACE1(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE1(( " FD number %lu is the maximum\n", + fd_select )); + FT_TRACE1(( " integer fitting into %u byte%s\n", + cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" )); + } + else + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE0(( " FD number %lu is larger\n", + fd_select )); + FT_TRACE0(( " than number of dictionaries (%u)\n", + cid->num_dicts )); + } + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off2 > stream->size ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE0(( " end of the glyph data\n" )); + FT_TRACE0(( " is beyond the data stream\n" )); + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off1 > off2 ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE0(( " the end position of glyph data\n" )); + FT_TRACE0(( " is set before the start position\n" )); + + error = FT_THROW( Invalid_Offset ); + } + + Exit: + if ( need_frame_exit ) + FT_FRAME_EXIT(); + + return error; + } + + FT_CALLBACK_DEF( FT_Error ) cid_load_glyph( T1_Decoder decoder, FT_UInt glyph_index ) @@ -64,7 +174,7 @@ #endif - FT_TRACE1(( "cid_load_glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "cid_load_glyph: glyph index %u\n", glyph_index )); #ifdef FT_CONFIG_OPTION_INCREMENTAL @@ -77,20 +187,17 @@ error = inc->funcs->get_glyph_data( inc->object, glyph_index, &glyph_data ); - if ( error ) + if ( error || glyph_data.length < cid->fd_bytes ) goto Exit; p = (FT_Byte*)glyph_data.pointer; - fd_select = cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); + fd_select = cid_get_offset( &p, cid->fd_bytes ); - if ( glyph_data.length != 0 ) - { - glyph_length = (FT_ULong)( glyph_data.length - cid->fd_bytes ); - (void)FT_ALLOC( charstring, glyph_length ); - if ( !error ) - ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes, + glyph_length = glyph_data.length - cid->fd_bytes; + + if ( !FT_QALLOC( charstring, glyph_length ) ) + FT_MEM_COPY( charstring, glyph_data.pointer + cid->fd_bytes, glyph_length ); - } inc->funcs->free_glyph_data( inc->object, &glyph_data ); @@ -101,41 +208,20 @@ 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 = (FT_UInt)( cid->fd_bytes + cid->gd_bytes ); FT_ULong off1, off2; - if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset + - glyph_index * entry_len ) || - FT_FRAME_ENTER( 2 * entry_len ) ) + error = cid_compute_fd_and_offsets( face, glyph_index, + &fd_select, &off1, &off2 ); + if ( error ) goto Exit; - p = (FT_Byte*)stream->cursor; - fd_select = cid_get_offset( &p, (FT_Byte)cid->fd_bytes ); - off1 = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); - p += cid->fd_bytes; - off2 = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ); - FT_FRAME_EXIT(); - - if ( fd_select >= (FT_ULong)cid->num_dicts || - off2 > stream->size || - off1 > off2 ) - { - FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" )); - error = FT_THROW( Invalid_Offset ); - goto Exit; - } - glyph_length = off2 - off1; - if ( glyph_length == 0 ) - goto Exit; - if ( FT_ALLOC( charstring, glyph_length ) ) - goto Exit; - if ( FT_STREAM_READ_AT( cid->data_offset + off1, + + if ( glyph_length == 0 || + FT_QALLOC( charstring, glyph_length ) || + FT_STREAM_READ_AT( cid->data_offset + off1, charstring, glyph_length ) ) goto Exit; } @@ -166,7 +252,9 @@ cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0; if ( cs_offset > glyph_length ) { - FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" )); + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%u," + " offset to the charstring is beyond glyph length\n", + glyph_index )); error = FT_THROW( Invalid_Offset ); goto Exit; } @@ -364,16 +452,12 @@ 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 ); scaled = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); glyph->hint = hinting; glyph->scaled = scaled; - cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; error = psaux->t1_decoder_funcs->init( &decoder, cidglyph->face, @@ -413,12 +497,8 @@ /* 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 */ + /* 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 = cidglyph->internal; @@ -439,6 +519,13 @@ FT_Glyph_Metrics* metrics = &cidglyph->metrics; + cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; + + cidglyph->outline.flags &= FT_OUTLINE_OWNER; + cidglyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + if ( cidsize->metrics.y_ppem < 24 ) + cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); @@ -451,11 +538,6 @@ face->cid.font_bbox.yMin ) >> 16; cidglyph->linearVertAdvance = metrics->vertAdvance; - cidglyph->format = FT_GLYPH_FORMAT_OUTLINE; - - if ( cidsize->metrics.y_ppem < 24 ) - cidglyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || font_matrix.xy != 0 || font_matrix.yx != 0 ) diff --git a/src/thirdparty/freetype2/src/cid/cidgload.h b/src/thirdparty/freetype2/src/cid/cidgload.h index 37eba7ca7..cef96073d 100644 --- a/src/thirdparty/freetype2/src/cid/cidgload.h +++ b/src/thirdparty/freetype2/src/cid/cidgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define CIDGLOAD_H_ -#include #include "cidobjs.h" @@ -43,6 +42,14 @@ FT_BEGIN_HEADER FT_Int32 load_flags ); + FT_LOCAL( FT_Error ) + cid_compute_fd_and_offsets( CID_Face face, + FT_UInt glyph_index, + FT_ULong* fd_select_p, + FT_ULong* off1_p, + FT_ULong* off2_p ); + + FT_END_HEADER #endif /* CIDGLOAD_H_ */ diff --git a/src/thirdparty/freetype2/src/cid/cidload.c b/src/thirdparty/freetype2/src/cid/cidload.c index fce3e37da..bb1bf13e2 100644 --- a/src/thirdparty/freetype2/src/cid/cidload.c +++ b/src/thirdparty/freetype2/src/cid/cidload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,11 +17,11 @@ #include -#include FT_INTERNAL_DEBUG_H +#include #include FT_CONFIG_CONFIG_H -#include FT_MULTIPLE_MASTERS_H -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include #include "cidload.h" @@ -41,7 +41,7 @@ /* read a single offset */ FT_LOCAL_DEF( FT_ULong ) cid_get_offset( FT_Byte* *start, - FT_Byte offsize ) + FT_UInt offsize ) { FT_ULong result; FT_Byte* p = *start; @@ -113,7 +113,7 @@ CID_FaceDict dict; - if ( parser->num_dict < 0 || parser->num_dict >= cid->num_dicts ) + if ( parser->num_dict >= cid->num_dicts ) { FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", keyword->ident )); @@ -155,23 +155,24 @@ FT_CALLBACK_DEF( void ) - cid_parse_font_matrix( CID_Face face, - CID_Parser* parser ) + cid_parse_font_matrix( FT_Face face, /* CID_Face */ + void* parser_ ) { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; CID_FaceDict dict; - FT_Face root = (FT_Face)&face->root; FT_Fixed temp[6]; FT_Fixed temp_scale; - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + if ( parser->num_dict < cidface->cid.num_dicts ) { FT_Matrix* matrix; FT_Vector* offset; FT_Int result; - dict = face->cid.font_dicts + parser->num_dict; + dict = cidface->cid.font_dicts + parser->num_dict; matrix = &dict->font_matrix; offset = &dict->font_offset; @@ -204,7 +205,7 @@ if ( temp_scale != 0x10000L ) { /* set units per EM based on FontMatrix values */ - root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); @@ -237,24 +238,26 @@ FT_CALLBACK_DEF( void ) - parse_fd_array( CID_Face face, - CID_Parser* parser ) + parse_fd_array( FT_Face face, /* CID_Face */ + void* parser_ ) { - CID_FaceInfo cid = &face->cid; - FT_Memory memory = face->root.memory; - FT_Stream stream = parser->stream; - FT_Error error = FT_Err_Ok; - FT_Long num_dicts; + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + CID_FaceInfo cid = &cidface->cid; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Stream stream = parser->stream; + FT_Error error = FT_Err_Ok; + FT_Long num_dicts, max_dicts; num_dicts = cid_parser_to_int( parser ); - if ( num_dicts < 0 ) + if ( num_dicts < 0 || num_dicts > FT_INT_MAX ) { FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" )); goto Exit; } - FT_TRACE4(( " %d\n", num_dicts )); + FT_TRACE4(( " %ld\n", num_dicts )); /* * A single entry in the FDArray must (at least) contain the following @@ -272,18 +275,18 @@ * need a `dup X' at the very beginning and a `put' at the end, so a * rough guess using 100 bytes as the minimum is justified. */ - if ( (FT_ULong)num_dicts > stream->size / 100 ) + max_dicts = (FT_Long)( stream->size / 100 ); + if ( num_dicts > max_dicts ) { FT_TRACE0(( "parse_fd_array: adjusting FDArray size" - " (from %d to %d)\n", - num_dicts, - stream->size / 100 )); - num_dicts = (FT_Long)( stream->size / 100 ); + " (from %ld to %ld)\n", + num_dicts, max_dicts )); + num_dicts = max_dicts; } if ( !cid->font_dicts ) { - FT_Int n; + FT_UInt n; if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) @@ -313,23 +316,25 @@ /* By mistake, `expansion_factor' appears both in PS_PrivateRec */ /* and CID_FaceDictRec (both are public header files and can't */ - /* changed). We simply copy the value. */ + /* be thus changed). We simply copy the value. */ FT_CALLBACK_DEF( void ) - parse_expansion_factor( CID_Face face, - CID_Parser* parser ) + parse_expansion_factor( FT_Face face, /* CID_Face */ + void* parser_ ) { + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; CID_FaceDict dict; - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + if ( parser->num_dict < cidface->cid.num_dicts ) { - dict = face->cid.font_dicts + parser->num_dict; + dict = cidface->cid.font_dicts + parser->num_dict; dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); dict->private_dict.expansion_factor = dict->expansion_factor; - FT_TRACE4(( "%d\n", dict->expansion_factor )); + FT_TRACE4(( "%ld\n", dict->expansion_factor )); } return; @@ -341,11 +346,15 @@ /* to catch it for producing better trace output. */ FT_CALLBACK_DEF( void ) - parse_font_name( CID_Face face, - CID_Parser* parser ) + parse_font_name( FT_Face face, /* CID_Face */ + void* parser_ ) { #ifdef FT_DEBUG_LEVEL_TRACE - if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) + CID_Face cidface = (CID_Face)face; + CID_Parser* parser = (CID_Parser*)parser_; + + + if ( parser->num_dict < cidface->cid.num_dicts ) { T1_TokenRec token; FT_UInt len; @@ -361,7 +370,7 @@ } #else FT_UNUSED( face ); - FT_UNUSED( parser ); + FT_UNUSED( parser_ ); #endif return; @@ -379,7 +388,7 @@ T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 ) - { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + T1_FIELD_ZERO }; @@ -427,7 +436,7 @@ parser->num_dict++; #ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE4(( " FontDict %d", parser->num_dict )); + FT_TRACE4(( " FontDict %u", parser->num_dict )); if ( parser->num_dict > face->cid.num_dicts ) FT_TRACE4(( " (ignored)" )); FT_TRACE4(( "\n" )); @@ -460,36 +469,23 @@ T1_Field keyword = (T1_Field)cid_field_records; - for (;;) + while ( keyword->len ) { - FT_Byte* name; + FT_Byte* name = (FT_Byte*)keyword->ident; - name = (FT_Byte*)keyword->ident; - if ( !name ) - break; - - if ( cur[0] == name[0] && - len == ft_strlen( (const char*)name ) ) + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) { - FT_UInt 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; - } + /* 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++; } } @@ -517,7 +513,7 @@ FT_Memory memory = face->root.memory; FT_Stream stream = face->cid_stream; FT_Error error; - FT_Int n; + FT_UInt n; CID_Subrs subr; FT_UInt max_offsets = 0; FT_ULong* offsets = NULL; @@ -552,20 +548,20 @@ goto Fail; } - if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) + if ( FT_QRENEW_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 ) * (FT_UInt)dict->sd_bytes ) ) + 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 ); + offsets[count] = cid_get_offset( &p, dict->sd_bytes ); FT_FRAME_EXIT(); @@ -589,12 +585,12 @@ /* 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 ) ) + if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || + FT_QALLOC( subr->code[0], data_len ) ) goto Fail; if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || - FT_STREAM_READ( subr->code[0], data_len ) ) + FT_STREAM_READ( subr->code[0], data_len ) ) goto Fail; /* set up pointers */ @@ -665,17 +661,18 @@ static FT_Error - cid_hex_to_binary( FT_Byte* data, - FT_ULong data_len, - FT_ULong offset, - CID_Face face ) + cid_hex_to_binary( FT_Byte* data, + FT_ULong data_len, + FT_ULong offset, + CID_Face face, + FT_ULong* data_written ) { FT_Stream stream = face->root.stream; FT_Error error; FT_Byte buffer[256]; FT_Byte *p, *plimit; - FT_Byte *d, *dlimit; + FT_Byte *d = data, *dlimit; FT_Byte val; FT_Bool upper_nibble, done; @@ -684,7 +681,6 @@ if ( FT_STREAM_SEEK( offset ) ) goto Exit; - d = data; dlimit = d + data_len; p = buffer; plimit = p; @@ -715,7 +711,7 @@ if ( ft_isdigit( *p ) ) val = (FT_Byte)( *p - '0' ); else if ( *p >= 'a' && *p <= 'f' ) - val = (FT_Byte)( *p - 'a' ); + val = (FT_Byte)( *p - 'a' + 10 ); else if ( *p >= 'A' && *p <= 'F' ) val = (FT_Byte)( *p - 'A' + 10 ); else if ( *p == ' ' || @@ -758,6 +754,7 @@ error = FT_Err_Ok; Exit: + *data_written = (FT_ULong)( d - data ); return error; } @@ -770,12 +767,11 @@ CID_Parser* parser; FT_Memory memory = face->root.memory; FT_Error error; - FT_Int n; + FT_UInt n; CID_FaceInfo cid = &face->cid; FT_ULong binary_length; - FT_ULong entry_len; cid_init_loader( &loader, face ); @@ -803,8 +799,8 @@ if ( parser->binary_length > face->root.stream->size - parser->data_offset ) { - FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" - " (from %d to %d bytes)\n", + FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" )); + FT_TRACE0(( " (from %lu to %lu bytes)\n", parser->binary_length, face->root.stream->size - parser->data_offset )); parser->binary_length = face->root.stream->size - @@ -812,15 +808,16 @@ } /* we must convert the data section from hexadecimal to binary */ - if ( FT_ALLOC( face->binary_data, parser->binary_length ) || + if ( FT_QALLOC( face->binary_data, parser->binary_length ) || FT_SET_ERROR( cid_hex_to_binary( face->binary_data, parser->binary_length, parser->data_offset, - face ) ) ) + face, + &binary_length ) ) ) goto Exit; FT_Stream_OpenMemory( face->cid_stream, - face->binary_data, parser->binary_length ); + face->binary_data, binary_length ); cid->data_offset = 0; } else @@ -831,10 +828,10 @@ /* sanity tests */ - if ( cid->fd_bytes < 0 || cid->gd_bytes < 1 ) + if ( cid->gd_bytes == 0 ) { FT_ERROR(( "cid_face_open:" - " Invalid `FDBytes' or `GDBytes' value\n" )); + " Invalid `GDBytes' value\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -843,15 +840,32 @@ if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 ) { FT_ERROR(( "cid_face_open:" - " Values of `FDBytes' or `GDBytes' larger than 4\n" - " " + " Values of `FDBytes' or `GDBytes' larger than 4\n" )); + FT_ERROR(( " " " are not supported\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } binary_length = face->cid_stream->size - cid->data_offset; - entry_len = (FT_ULong)( cid->fd_bytes + cid->gd_bytes ); + + if ( cid->cidmap_offset > binary_length ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + + /* the initial pre-check prevents the multiplication overflow */ + if ( cid->cid_count > FT_ULONG_MAX / 8 || + cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) > + binary_length - cid->cidmap_offset ) + { + FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; + } + for ( n = 0; n < cid->num_dicts; n++ ) { @@ -877,8 +891,7 @@ dict->private_dict.blue_fuzz = 1; } - if ( dict->sd_bytes < 0 || - ( dict->num_subrs && dict->sd_bytes < 1 ) ) + if ( dict->num_subrs && dict->sd_bytes == 0 ) { FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" )); error = FT_THROW( Invalid_File_Format ); @@ -901,11 +914,10 @@ goto Exit; } - /* `num_subrs' is scanned as a signed integer */ - if ( (FT_Int)dict->num_subrs < 0 || - ( dict->sd_bytes && - dict->num_subrs > ( binary_length - dict->subrmap_offset ) / - (FT_UInt)dict->sd_bytes ) ) + /* the initial pre-check prevents the multiplication overflow */ + if ( dict->num_subrs > FT_UINT_MAX / 4 || + dict->num_subrs * dict->sd_bytes > + binary_length - dict->subrmap_offset ) { FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" )); error = FT_THROW( Invalid_File_Format ); @@ -913,22 +925,6 @@ } } - if ( cid->cidmap_offset > binary_length ) - { - FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - - if ( entry_len && - cid->cid_count > - ( binary_length - cid->cidmap_offset ) / entry_len ) - { - FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - /* we can now safely proceed */ error = cid_read_subrs( face ); diff --git a/src/thirdparty/freetype2/src/cid/cidload.h b/src/thirdparty/freetype2/src/cid/cidload.h index fb9d46216..659dd0e37 100644 --- a/src/thirdparty/freetype2/src/cid/cidload.h +++ b/src/thirdparty/freetype2/src/cid/cidload.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define CIDLOAD_H_ -#include -#include FT_INTERNAL_STREAM_H +#include #include "cidparse.h" @@ -38,7 +37,7 @@ FT_BEGIN_HEADER FT_LOCAL( FT_ULong ) cid_get_offset( FT_Byte** start, - FT_Byte offsize ); + FT_UInt offsize ); FT_LOCAL( FT_Error ) cid_face_open( CID_Face face, diff --git a/src/thirdparty/freetype2/src/cid/cidobjs.c b/src/thirdparty/freetype2/src/cid/cidobjs.c index 4e9728719..634bbf2f1 100644 --- a/src/thirdparty/freetype2/src/cid/cidobjs.c +++ b/src/thirdparty/freetype2/src/cid/cidobjs.c @@ -4,7 +4,7 @@ * * CID objects manager (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,17 +16,16 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H +#include +#include #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 FT_DRIVER_H +#include +#include +#include +#include #include "ciderrs.h" @@ -50,7 +49,8 @@ FT_LOCAL_DEF( void ) cid_slot_done( FT_GlyphSlot slot ) { - slot->internal->glyph_hints = NULL; + if ( slot->internal ) + slot->internal->glyph_hints = NULL; } @@ -69,8 +69,7 @@ FT_Module module; - module = FT_Get_Module( slot->face->driver->root.library, - "pshinter" ); + module = FT_Get_Module( slot->library, "pshinter" ); if ( module ) { T1_Hints_Funcs funcs; @@ -153,14 +152,18 @@ } - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) cid_size_request( FT_Size size, FT_Size_Request req ) { + FT_Error error; + PSH_Globals_Funcs funcs; - FT_Request_Metrics( size->face, req ); + error = FT_Request_Metrics( size->face, req ); + if ( error ) + goto Exit; funcs = cid_size_get_globals_funcs( (CID_Size)size ); @@ -170,7 +173,8 @@ size->metrics.y_scale, 0, 0 ); - return FT_Err_Ok; + Exit: + return error; } @@ -211,7 +215,7 @@ /* release subrs */ if ( face->subrs ) { - FT_Int n; + FT_UInt n; for ( n = 0; n < cid->num_dicts; n++ ) @@ -263,7 +267,8 @@ * * @Input: * stream :: - * The source font stream. + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. * * face_index :: * The index of the font face in the resource. @@ -370,6 +375,14 @@ if ( info->is_fixed_pitch ) cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; + /* + * For the sfnt-wrapped CID fonts for MacOS, currently, + * its `cmap' tables are ignored, and the content in + * its `CID ' table is treated the same as naked CID-keyed + * font. See ft_lookup_PS_in_sfnt_stream(). + */ + cidface->face_flags |= FT_FACE_FLAG_CID_KEYED; + /* XXX: TODO: add kerning with .afm support */ /* get style name -- be careful, some broken fonts only */ @@ -479,11 +492,7 @@ /* set default property values, cf. `ftt1drv.h' */ -#ifdef T1_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff --git a/src/thirdparty/freetype2/src/cid/cidobjs.h b/src/thirdparty/freetype2/src/cid/cidobjs.h index 89c9aa74a..800268efa 100644 --- a/src/thirdparty/freetype2/src/cid/cidobjs.h +++ b/src/thirdparty/freetype2/src/cid/cidobjs.h @@ -4,7 +4,7 @@ * * CID objects manager (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,9 +21,9 @@ #include -#include FT_INTERNAL_OBJECTS_H +#include #include FT_CONFIG_CONFIG_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/cid/cidparse.c b/src/thirdparty/freetype2/src/cid/cidparse.c index 1be46ec32..4d1ba3359 100644 --- a/src/thirdparty/freetype2/src/cid/cidparse.c +++ b/src/thirdparty/freetype2/src/cid/cidparse.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_STREAM_H +#include +#include +#include #include "cidparse.h" @@ -74,7 +73,11 @@ /* first of all, check the font format in the header */ if ( FT_FRAME_ENTER( 31 ) ) + { + FT_TRACE2(( " not a CID-keyed font\n" )); + error = FT_THROW( Unknown_File_Format ); goto Exit; + } if ( ft_strncmp( (char *)stream->cursor, "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) @@ -87,10 +90,15 @@ if ( error ) goto Exit; - Again: - /* now, read the rest of the file until we find */ - /* `StartData' or `/sfnts' */ + if ( !stream->read ) { + /* just parse memory-based streams */ + offset = stream->size; + } + else { + /* Find the last `StartData` or `/sfnts`. The parser requires */ + /* contiguous memory; attempt to pin as little as necessary. */ + /* * The algorithm is as follows (omitting the case with less than 256 * bytes to fill for simplicity). @@ -116,7 +124,8 @@ FT_Byte* p = buffer; - for ( offset = FT_STREAM_POS(); ; offset += 256 ) + offset = 0; + while ( 1 ) { FT_ULong stream_len; @@ -124,7 +133,7 @@ stream_len = stream->size - FT_STREAM_POS(); read_len = FT_MIN( read_len, stream_len ); - if ( FT_STREAM_READ( p, read_len ) ) + if ( read_len && FT_STREAM_READ( p, read_len ) ) goto Exit; /* ensure that we do not compare with data beyond the buffer */ @@ -138,20 +147,23 @@ ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) { /* save offset of binary data after `StartData' */ - offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; - goto Found; + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; } else if ( p[1] == 's' && ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) { - offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; - goto Found; + offset = FT_STREAM_POS() - read_len - read_offset + + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; } } - if ( read_offset + read_len < STARTDATA_LEN ) + if ( read_offset + read_len <= STARTDATA_LEN ) { - FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); + if ( offset ) + goto Found; + + FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -168,9 +180,9 @@ } 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. */ + /* We have found an efficient range to look for the binary data or */ + /* `/sfnts' token. Now rewind and extract the frame corresponding to */ + /* this PostScript section. */ ps_len = offset - base_offset; if ( FT_STREAM_SEEK( base_offset ) || @@ -182,10 +194,10 @@ parser->root.base = parser->postscript; parser->root.cursor = parser->postscript; parser->root.limit = parser->root.cursor + ps_len; - parser->num_dict = -1; + parser->num_dict = FT_UINT_MAX; - /* Finally, we check whether `StartData' or `/sfnts' was real -- */ - /* it could be in a comment or string. We also get the arguments */ + /* Find the first real `StartData' or `/sfnts' -- the last one */ + /* 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. */ @@ -211,20 +223,45 @@ cur <= limit - STARTDATA_LEN && ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) { - if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) + T1_TokenRec type_token; + FT_Long binary_length; + FT_ULong found_offset; + + + parser->root.cursor = arg1; + cid_parser_to_token( parser, &type_token ); + if ( type_token.limit - type_token.start == 5 && + ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 ) { - FT_Long tmp = ft_strtol( (const char *)arg2, NULL, 10 ); - - - if ( tmp < 0 ) + parser->root.cursor = arg2; + binary_length = cid_parser_to_int( parser ); + if ( binary_length < 0 ) { FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); error = FT_THROW( Invalid_File_Format ); } else - parser->binary_length = (FT_ULong)tmp; + parser->binary_length = (FT_ULong)binary_length; } + /* set the real values for the parser, if different */ + found_offset = (FT_ULong)( cur - parser->postscript ) + + STARTDATA_LEN + 1; + if ( found_offset != offset ) + { + FT_FRAME_RELEASE( parser->postscript ); + + ps_len = found_offset - base_offset; + if ( FT_STREAM_SEEK( base_offset ) || + FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) + goto Exit; + + parser->data_offset = found_offset; + parser->postscript_len = ps_len; + parser->root.base = parser->postscript; + parser->root.cursor = parser->postscript; + parser->root.limit = parser->root.cursor + ps_len; + } goto Exit; } else if ( cur[1] == 's' && @@ -242,11 +279,8 @@ 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; + FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" )); + error = FT_THROW( Invalid_File_Format ); Exit: return error; diff --git a/src/thirdparty/freetype2/src/cid/cidparse.h b/src/thirdparty/freetype2/src/cid/cidparse.h index ec1f6a346..6ae2e5423 100644 --- a/src/thirdparty/freetype2/src/cid/cidparse.h +++ b/src/thirdparty/freetype2/src/cid/cidparse.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define CIDPARSE_H_ -#include -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include FT_BEGIN_HEADER @@ -79,7 +78,7 @@ FT_BEGIN_HEADER FT_ULong binary_length; CID_FaceInfo cid; - FT_Int num_dict; + FT_UInt num_dict; } CID_Parser; diff --git a/src/thirdparty/freetype2/src/cid/cidriver.c b/src/thirdparty/freetype2/src/cid/cidriver.c index 4d91e8752..a3a587c57 100644 --- a/src/thirdparty/freetype2/src/cid/cidriver.c +++ b/src/thirdparty/freetype2/src/cid/cidriver.c @@ -4,7 +4,7 @@ * * CID driver interface (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,22 +16,21 @@ */ -#include #include "cidriver.h" #include "cidgload.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_POSTSCRIPT_PROPS_H +#include +#include #include "ciderrs.h" -#include FT_SERVICE_POSTSCRIPT_NAME_H -#include FT_SERVICE_FONT_FORMAT_H -#include FT_SERVICE_POSTSCRIPT_INFO_H -#include FT_SERVICE_CID_H -#include FT_SERVICE_PROPERTIES_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include +#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include /************************************************************************** @@ -49,10 +48,11 @@ * */ - static const char* - cid_get_postscript_name( CID_Face face ) + FT_CALLBACK_DEF( const char* ) + cid_get_postscript_name( FT_Face face ) /* CID_Face */ { - const char* result = face->cid.cid_font_name; + CID_Face cidface = (CID_Face)face; + const char* result = cidface->cid.cid_font_name; if ( result && result[0] == '/' ) @@ -73,34 +73,36 @@ * */ - static FT_Error - cid_ps_get_font_info( FT_Face face, + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_info( FT_Face face, /* CID_Face */ PS_FontInfoRec* afont_info ) { - *afont_info = ((CID_Face)face)->cid.font_info; + *afont_info = ( (CID_Face)face )->cid.font_info; return FT_Err_Ok; } - static FT_Error - cid_ps_get_font_extra( FT_Face face, - PS_FontExtraRec* afont_extra ) + + FT_CALLBACK_DEF( FT_Error ) + cid_ps_get_font_extra( FT_Face face, /* CID_Face */ + PS_FontExtraRec* afont_extra ) { - *afont_extra = ((CID_Face)face)->font_extra; + *afont_extra = ( (CID_Face)face )->font_extra; return FT_Err_Ok; } + static const FT_Service_PsInfoRec cid_service_ps_info = { - (PS_GetFontInfoFunc) cid_ps_get_font_info, /* ps_get_font_info */ - (PS_GetFontExtraFunc) cid_ps_get_font_extra, /* ps_get_font_extra */ + cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ /* unsupported with CID fonts */ - (PS_HasGlyphNamesFunc) NULL, /* ps_has_glyph_names */ + NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ /* unsupported */ - (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ + NULL, /* PS_GetFontPrivateFunc ps_get_font_private */ /* not implemented */ - (PS_GetFontValueFunc) NULL /* ps_get_font_value */ + NULL /* PS_GetFontValueFunc ps_get_font_value */ }; @@ -108,13 +110,14 @@ * CID INFO SERVICE * */ - static FT_Error - cid_get_ros( CID_Face face, + FT_CALLBACK_DEF( FT_Error ) + cid_get_ros( FT_Face face, /* CID_Face */ const char* *registry, const char* *ordering, FT_Int *supplement ) { - CID_FaceInfo cid = &face->cid; + CID_Face cidface = (CID_Face)face; + CID_FaceInfo cid = &cidface->cid; if ( registry ) @@ -130,32 +133,48 @@ } - static FT_Error - cid_get_is_cid( CID_Face face, + FT_CALLBACK_DEF( FT_Error ) + cid_get_is_cid( FT_Face face, /* CID_Face */ FT_Bool *is_cid ) { FT_Error error = FT_Err_Ok; FT_UNUSED( face ); + /* + * XXX: If the ROS is Adobe-Identity-H or -V, + * the font has no reliable information about + * its glyph collection. Should we not set + * *is_cid in such cases? + */ if ( is_cid ) - *is_cid = 1; /* cid driver is only used for CID keyed fonts */ + *is_cid = 1; return error; } - static FT_Error - cid_get_cid_from_glyph_index( CID_Face face, + FT_CALLBACK_DEF( FT_Error ) + cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */ FT_UInt glyph_index, FT_UInt *cid ) { - FT_Error error = FT_Err_Ok; - FT_UNUSED( face ); + FT_Error error = FT_Err_Ok; + CID_Face cidface = (CID_Face)face; - if ( cid ) - *cid = glyph_index; /* identity mapping */ + /* + * Currently, FreeType does not support incrementally-defined, CID-keyed + * fonts that store the glyph description data in a `/GlyphDirectory` + * array or dictionary. Fonts loaded by the incremental loading feature + * are thus not handled here. + */ + error = cid_compute_fd_and_offsets( cidface, glyph_index, + NULL, NULL, NULL ); + if ( error ) + *cid = 0; + else + *cid = glyph_index; return error; } @@ -163,12 +182,12 @@ static const FT_Service_CIDRec cid_service_cid_info = { - (FT_CID_GetRegistryOrderingSupplementFunc) - cid_get_ros, /* get_ros */ - (FT_CID_GetIsInternallyCIDKeyedFunc) - cid_get_is_cid, /* get_is_cid */ - (FT_CID_GetCIDFromGlyphIndexFunc) - cid_get_cid_from_glyph_index /* get_cid_from_glyph_index */ + cid_get_ros, + /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */ + cid_get_is_cid, + /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */ + cid_get_cid_from_glyph_index + /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */ }; @@ -180,9 +199,9 @@ FT_DEFINE_SERVICE_PROPERTIESREC( cid_service_properties, - (FT_Properties_SetFunc)ps_property_set, /* set_property */ - (FT_Properties_GetFunc)ps_property_get ) /* get_property */ - + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) /* * SERVICE LIST @@ -210,7 +229,6 @@ } - FT_CALLBACK_TABLE_DEF const FT_Driver_ClassRec t1cid_driver_class = { diff --git a/src/thirdparty/freetype2/src/cid/cidriver.h b/src/thirdparty/freetype2/src/cid/cidriver.h index 3402fd7e9..55d0b8a0d 100644 --- a/src/thirdparty/freetype2/src/cid/cidriver.h +++ b/src/thirdparty/freetype2/src/cid/cidriver.h @@ -4,7 +4,7 @@ * * High-level CID driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define CIDRIVER_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/cid/cidtoken.h b/src/thirdparty/freetype2/src/cid/cidtoken.h index f505c9e16..25ba74fed 100644 --- a/src/thirdparty/freetype2/src/cid/cidtoken.h +++ b/src/thirdparty/freetype2/src/cid/cidtoken.h @@ -4,7 +4,7 @@ * * CID token definitions (specification only). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/dlg/dlg.c b/src/thirdparty/freetype2/src/dlg/dlg.c new file mode 100644 index 000000000..0e6bc74b6 --- /dev/null +++ b/src/thirdparty/freetype2/src/dlg/dlg.c @@ -0,0 +1,803 @@ +// Copyright (c) 2019 nyorain +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt + +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200809L +#define _WIN32_WINNT 0x0600 + +// Needed on windows so that we can use sprintf without warning. +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +const char* const dlg_reset_sequence = "\033[0m"; +const struct dlg_style dlg_default_output_styles[] = { + {dlg_text_style_italic, dlg_color_green, dlg_color_none}, + {dlg_text_style_dim, dlg_color_gray, dlg_color_none}, + {dlg_text_style_none, dlg_color_cyan, dlg_color_none}, + {dlg_text_style_none, dlg_color_yellow, dlg_color_none}, + {dlg_text_style_none, dlg_color_red, dlg_color_none}, + {dlg_text_style_bold, dlg_color_red, dlg_color_none} +}; + +static void* xalloc(size_t size) { + void* ret = calloc(size, 1); + if(!ret) fprintf(stderr, "dlg: calloc returned NULL, probably crashing (size: %zu)\n", size); + return ret; +} + +static void* xrealloc(void* ptr, size_t size) { + void* ret = realloc(ptr, size); + if(!ret) fprintf(stderr, "dlg: realloc returned NULL, probably crashing (size: %zu)\n", size); + return ret; +} + +struct dlg_tag_func_pair { + const char* tag; + const char* func; +}; + +struct dlg_data { + const char** tags; // vec + struct dlg_tag_func_pair* pairs; // vec + char* buffer; + size_t buffer_size; +}; + +static dlg_handler g_handler = dlg_default_output; +static void* g_data = NULL; + +static void dlg_free_data(void* data); +static struct dlg_data* dlg_create_data(void); + +// platform-specific +#if defined(__unix__) || defined(__unix) || defined(__linux__) || defined(__APPLE__) || defined(__MACH__) + #define DLG_OS_UNIX + #include + #include + #include + + static pthread_key_t dlg_data_key; + + static void dlg_main_cleanup(void) { + void* data = pthread_getspecific(dlg_data_key); + if(data) { + dlg_free_data(data); + pthread_setspecific(dlg_data_key, NULL); + } + } + + static void init_data_key(void) { + pthread_key_create(&dlg_data_key, dlg_free_data); + atexit(dlg_main_cleanup); + } + + static struct dlg_data* dlg_data(void) { + static pthread_once_t key_once = PTHREAD_ONCE_INIT; + pthread_once(&key_once, init_data_key); + + void* data = pthread_getspecific(dlg_data_key); + if(!data) { + data = dlg_create_data(); + pthread_setspecific(dlg_data_key, data); + } + + return (struct dlg_data*) data; + } + + static void lock_file(FILE* file) { + flockfile(file); + } + + static void unlock_file(FILE* file) { + funlockfile(file); + } + + bool dlg_is_tty(FILE* stream) { + return isatty(fileno(stream)); + } + + static unsigned get_msecs(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec; + } + +// platform switch -- end unix +#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) + #define DLG_OS_WIN + #define WIN32_LEAN_AND_MEAN + #define DEFINE_CONSOLEV2_PROPERTIES + #include + #include + + // thanks for nothing, microsoft + #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #endif + + // the max buffer size we will convert on the stack + #define DLG_MAX_STACK_BUF_SIZE 1024 + + static void WINAPI dlg_fls_destructor(void* data) { + dlg_free_data(data); + } + + // TODO: error handling + static BOOL CALLBACK dlg_init_fls(PINIT_ONCE io, void* param, void** lpContext) { + (void) io; + (void) param; + **((DWORD**) lpContext) = FlsAlloc(dlg_fls_destructor); + return true; + } + + static struct dlg_data* dlg_data(void) { + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static DWORD fls = 0; + void* flsp = (void*) &fls; + InitOnceExecuteOnce(&init_once, dlg_init_fls, NULL, &flsp); + void* data = FlsGetValue(fls); + if(!data) { + data = dlg_create_data(); + FlsSetValue(fls, data); + } + + return (struct dlg_data*) data; + } + + static void lock_file(FILE* file) { + _lock_file(file); + } + + static void unlock_file(FILE* file) { + _unlock_file(file); + } + + bool dlg_is_tty(FILE* stream) { + return _isatty(_fileno(stream)); + } + +#ifdef DLG_WIN_CONSOLE + static bool init_ansi_console(void) { + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE err = GetStdHandle(STD_ERROR_HANDLE); + if(out == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE) + return false; + + DWORD outMode, errMode; + if(!GetConsoleMode(out, &outMode) || !GetConsoleMode(err, &errMode)) + return false; + + outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + errMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if(!SetConsoleMode(out, outMode) || !SetConsoleMode(out, errMode)) + return false; + + return true; + } + + static bool win_write_heap(void* handle, int needed, const char* format, va_list args) { + char* buf1 = xalloc(3 * needed + 3 + (needed % 2)); + wchar_t* buf2 = (wchar_t*) (buf1 + needed + 1 + (needed % 2)); + vsnprintf(buf1, needed + 1, format, args); + needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1); + bool ret = (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0); + free(buf1); + return ret; + } + + static bool win_write_stack(void* handle, int needed, const char* format, va_list args) { + char buf1[DLG_MAX_STACK_BUF_SIZE]; + wchar_t buf2[DLG_MAX_STACK_BUF_SIZE]; + vsnprintf(buf1, needed + 1, format, args); + needed = MultiByteToWideChar(CP_UTF8, 0, buf1, needed, buf2, needed + 1); + return (needed != 0 && WriteConsoleW(handle, buf2, needed, NULL, NULL) != 0); + } +#endif // DLG_WIN_CONSOLE + + static unsigned get_msecs() { + SYSTEMTIME st; + GetSystemTime(&st); + return st.wMilliseconds; + } + +#else // platform switch -- end windows + #error Cannot determine platform (needed for color and utf-8 and stuff) +#endif + +// general +void dlg_escape_sequence(struct dlg_style style, char buf[12]) { + int nums[3]; + unsigned int count = 0; + + if(style.fg != dlg_color_none) { + nums[count++] = style.fg + 30; + } + + if(style.bg != dlg_color_none) { + nums[count++] = style.fg + 40; + } + + if(style.style != dlg_text_style_none) { + nums[count++] = style.style; + } + + switch(count) { + case 1: snprintf(buf, 12, "\033[%dm", nums[0]); break; + case 2: snprintf(buf, 12, "\033[%d;%dm", nums[0], nums[1]); break; + case 3: snprintf(buf, 12, "\033[%d;%d;%dm", nums[0], nums[1], nums[2]); break; + default: buf[0] = '\0'; break; + } +} + +int dlg_vfprintf(FILE* stream, const char* format, va_list args) { +#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE) + void* handle = NULL; + if(stream == stdout) { + handle = GetStdHandle(STD_OUTPUT_HANDLE); + } else if(stream == stderr) { + handle = GetStdHandle(STD_ERROR_HANDLE); + } + + if(handle) { + va_list args_copy; + va_copy(args_copy, args); + int needed = vsnprintf(NULL, 0, format, args_copy); + va_end(args_copy); + + if(needed < 0) { + return needed; + } + + // We don't allocate too much on the stack + // but we also don't want to call alloc every logging call + // or use another cached buffer + if(needed >= DLG_MAX_STACK_BUF_SIZE) { + if(win_write_heap(handle, needed, format, args)) { + return needed; + } + } else { + if(win_write_stack(handle, needed, format, args)) { + return needed; + } + } + } +#endif + + return vfprintf(stream, format, args); +} + +int dlg_fprintf(FILE* stream, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = dlg_vfprintf(stream, format, args); + va_end(args); + return ret; +} + +int dlg_styled_fprintf(FILE* stream, struct dlg_style style, const char* format, ...) { + char buf[12]; + dlg_escape_sequence(style, buf); + + fprintf(stream, "%s", buf); + va_list args; + va_start(args, format); + int ret = dlg_vfprintf(stream, format, args); + va_end(args); + fprintf(stream, "%s", dlg_reset_sequence); + return ret; +} + +void dlg_generic_output(dlg_generic_output_handler output, void* data, + unsigned int features, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + // We never print any dynamic content below so we can be sure at compile + // time that a buffer of size 64 is large enough. + char format_buf[64]; + char* format = format_buf; + + if(features & dlg_output_style) { + format += sprintf(format, "%%s"); + } + + if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) { + format += sprintf(format, "["); + } + + bool first_meta = true; + if(features & dlg_output_time) { + format += sprintf(format, "%%h"); + first_meta = false; + } + + if(features & dlg_output_time_msecs) { + if(!first_meta) { + format += sprintf(format, ":"); + } + + format += sprintf(format, "%%m"); + first_meta = false; + } + + if(features & dlg_output_file_line) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "%%o"); + first_meta = false; + } + + if(features & dlg_output_func) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "%%f"); + first_meta = false; + } + + if(features & dlg_output_tags) { + if(!first_meta) { + format += sprintf(format, " "); + } + + format += sprintf(format, "{%%t}"); + first_meta = false; + } + + if(features & (dlg_output_time | dlg_output_file_line | dlg_output_tags | dlg_output_func)) { + format += sprintf(format, "] "); + } + + format += sprintf(format, "%%c"); + + if(features & dlg_output_newline) { + format += sprintf(format, "\n"); + } + + *format = '\0'; + dlg_generic_outputf(output, data, format_buf, origin, string, styles); +} + +void dlg_generic_outputf(dlg_generic_output_handler output, void* data, + const char* format_string, const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + bool reset_style = false; + for(const char* it = format_string; *it; it++) { + if(*it != '%') { + output(data, "%c", *it); + continue; + } + + char next = *(it + 1); // must be valid since *it is not '\0' + if(next == 'h') { + time_t t = time(NULL); + struct tm tm_info; + + #ifdef DLG_OS_WIN + if(localtime_s(&tm_info, &t)) { + #else + if(!localtime_r(&t, &tm_info)) { + #endif + output(data, ""); + } else { + char timebuf[32]; + strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm_info); + output(data, "%s", timebuf); + } + it++; + } else if(next == 'm') { + output(data, "%06d", get_msecs()); + it++; + } else if(next == 't') { + bool first_tag = true; + for(const char** tags = origin->tags; *tags; ++tags) { + if(!first_tag) { + output(data, ", "); + } + + output(data, "%s", *tags); + first_tag = false; + } + ++it; + } else if(next == 'f') { + output(data, "%s", origin->func); + ++it; + } else if(next == 'o') { + output(data, "%s:%u", origin->file, origin->line); + ++it; + } else if(next == 's') { + char buf[12]; + dlg_escape_sequence(styles[origin->level], buf); + output(data, "%s", buf); + reset_style = true; + ++it; + } else if(next == 'r') { + output(data, "%s", dlg_reset_sequence); + reset_style = false; + ++it; + } else if(next == 'c') { + if(origin->expr && string) { + output(data, "assertion '%s' failed: '%s'", origin->expr, string); + } else if(origin->expr) { + output(data, "assertion '%s' failed", origin->expr); + } else if(string) { + output(data, "%s", string); + } + ++it; + } else if(next == '%') { + output(data, "%s", "%"); + ++it; + } else { + // in this case it's a '%' without known format specifier following + output(data, "%s", "%"); + } + } + + if(reset_style) { + output(data, "%s", dlg_reset_sequence); + } +} + +struct buf { + char* buf; + size_t* size; +}; + +static void print_size(void* size, const char* format, ...) { + va_list args; + va_start(args, format); + + int ret = vsnprintf(NULL, 0, format, args); + va_end(args); + + if(ret > 0) { + *((size_t*) size) += ret; + } +} + +static void print_buf(void* dbuf, const char* format, ...) { + struct buf* buf = (struct buf*) dbuf; + va_list args; + va_start(args, format); + + int printed = vsnprintf(buf->buf, *buf->size, format, args); + va_end(args); + + if(printed > 0) { + *buf->size -= printed; + buf->buf += printed; + } +} + +void dlg_generic_output_buf(char* buf, size_t* size, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + if(buf) { + struct buf mbuf; + mbuf.buf = buf; + mbuf.size = size; + dlg_generic_output(print_buf, &mbuf, features, origin, string, styles); + } else { + *size = 0; + dlg_generic_output(print_size, size, features, origin, string, styles); + } +} + +void dlg_generic_outputf_buf(char* buf, size_t* size, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + if(buf) { + struct buf mbuf; + mbuf.buf = buf; + mbuf.size = size; + dlg_generic_outputf(print_buf, &mbuf, format_string, origin, string, styles); + } else { + *size = 0; + dlg_generic_outputf(print_size, size, format_string, origin, string, styles); + } +} + +static void print_stream(void* stream, const char* format, ...) { + va_list args; + va_start(args, format); + dlg_vfprintf((FILE*) stream, format, args); + va_end(args); +} + +void dlg_generic_output_stream(FILE* stream, unsigned int features, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6]) { + stream = stream ? stream : stdout; + if(features & dlg_output_threadsafe) { + lock_file(stream); + } + + dlg_generic_output(print_stream, stream, features, origin, string, styles); + if(features & dlg_output_threadsafe) { + unlock_file(stream); + } +} + +void dlg_generic_outputf_stream(FILE* stream, const char* format_string, + const struct dlg_origin* origin, const char* string, + const struct dlg_style styles[6], bool lock_stream) { + stream = stream ? stream : stdout; + if(lock_stream) { + lock_file(stream); + } + + dlg_generic_outputf(print_stream, stream, format_string, origin, string, styles); + if(lock_stream) { + unlock_file(stream); + } +} + +void dlg_default_output(const struct dlg_origin* origin, const char* string, void* data) { + FILE* stream = data ? (FILE*) data : stdout; + unsigned int features = dlg_output_file_line | + dlg_output_newline | + dlg_output_threadsafe; + +#ifdef DLG_DEFAULT_OUTPUT_ALWAYS_COLOR + dlg_win_init_ansi(); + features |= dlg_output_style; +#else + if(dlg_is_tty(stream) && dlg_win_init_ansi()) { + features |= dlg_output_style; + } +#endif + + dlg_generic_output_stream(stream, features, origin, string, dlg_default_output_styles); + fflush(stream); +} + +bool dlg_win_init_ansi(void) { +#if defined(DLG_OS_WIN) && defined(DLG_WIN_CONSOLE) + // TODO: use init once + static volatile LONG status = 0; + LONG res = InterlockedCompareExchange(&status, 1, 0); + if(res == 0) { // not initialized + InterlockedExchange(&status, 3 + init_ansi_console()); + } + + while(status == 1); // currently initialized in another thread, spinlock + return (status == 4); +#else + return true; +#endif +} + +// small dynamic vec/array implementation +// Since the macros vec_init and vec_add[c]/vec_push might +// change the pointers value it must not be referenced somewhere else. +#define vec__raw(vec) (((unsigned int*) vec) - 2) + +static void* vec_do_create(unsigned int typesize, unsigned int cap, unsigned int size) { + unsigned long a = (size > cap) ? size : cap; + void* ptr = xalloc(2 * sizeof(unsigned int) + a * typesize); + unsigned int* begin = (unsigned int*) ptr; + begin[0] = size * typesize; + begin[1] = a * typesize; + return begin + 2; +} + +// NOTE: can be more efficient if we are allowed to reorder vector +static void vec_do_erase(void* vec, unsigned int pos, unsigned int size) { + unsigned int* begin = vec__raw(vec); + begin[0] -= size; + char* buf = (char*) vec; + memcpy(buf + pos, buf + pos + size, size); +} + +static void* vec_do_add(void** vec, unsigned int size) { + unsigned int* begin = vec__raw(*vec); + unsigned int needed = begin[0] + size; + if(needed >= begin[1]) { + void* ptr = xrealloc(begin, sizeof(unsigned int) * 2 + needed * 2); + begin = (unsigned int*) ptr; + begin[1] = needed * 2; + (*vec) = begin + 2; + } + + void* ptr = ((char*) (*vec)) + begin[0]; + begin[0] += size; + return ptr; +} + +#define vec_create(type, size) (type*) vec_do_create(sizeof(type), size * 2, size) +#define vec_create_reserve(type, size, capacity) (type*) vec_do_create(sizeof(type), capcity, size) +#define vec_init(array, size) array = vec_do_create(sizeof(*array), size * 2, size) +#define vec_init_reserve(array, size, capacity) *((void**) &array) = vec_do_create(sizeof(*array), capacity, size) +#define vec_free(vec) (free((vec) ? vec__raw(vec) : NULL), vec = NULL) +#define vec_erase_range(vec, pos, count) vec_do_erase(vec, pos * sizeof(*vec), count * sizeof(*vec)) +#define vec_erase(vec, pos) vec_do_erase(vec, pos * sizeof(*vec), sizeof(*vec)) +#define vec_size(vec) (vec__raw(vec)[0] / sizeof(*vec)) +#define vec_capacity(vec) (vec_raw(vec)[1] / sizeof(*vec)) +#define vec_add(vec) vec_do_add((void**) &vec, sizeof(*vec)) +#define vec_addc(vec, count) (vec_do_add((void**) &vec, sizeof(*vec) * count)) +#define vec_push(vec, value) (vec_do_add((void**) &vec, sizeof(*vec)), vec_last(vec) = (value)) +#define vec_pop(vec) (vec__raw(vec)[0] -= sizeof(*vec)) +#define vec_popc(vec, count) (vec__raw(vec)[0] -= sizeof(*vec) * count) +#define vec_clear(vec) (vec__raw(vec)[0] = 0) +#define vec_last(vec) (vec[vec_size(vec) - 1]) + +static struct dlg_data* dlg_create_data(void) { + struct dlg_data* data = (struct dlg_data*) xalloc(sizeof(struct dlg_data)); + vec_init_reserve(data->tags, 0, 20); + vec_init_reserve(data->pairs, 0, 20); + data->buffer_size = 100; + data->buffer = (char*) xalloc(data->buffer_size); + return data; +} + +static void dlg_free_data(void* ddata) { + struct dlg_data* data = (struct dlg_data*) ddata; + if(data) { + vec_free(data->pairs); + vec_free(data->tags); + free(data->buffer); + free(data); + } +} + +void dlg_add_tag(const char* tag, const char* func) { + struct dlg_data* data = dlg_data(); + struct dlg_tag_func_pair* pair = + (struct dlg_tag_func_pair*) vec_add(data->pairs); + pair->tag = tag; + pair->func = func; +} + +bool dlg_remove_tag(const char* tag, const char* func) { + struct dlg_data* data = dlg_data(); + for(unsigned int i = 0; i < vec_size(data->pairs); ++i) { + if(data->pairs[i].func == func && data->pairs[i].tag == tag) { + vec_erase(data->pairs, i); + return true; + } + } + + return false; +} + +char** dlg_thread_buffer(size_t** size) { + struct dlg_data* data = dlg_data(); + if(size) { + *size = &data->buffer_size; + } + return &data->buffer; +} + +void dlg_set_handler(dlg_handler handler, void* data) { + g_handler = handler; + g_data = data; +} + +dlg_handler dlg_get_handler(void** data) { + *data = g_data; + return g_handler; +} + +const char* dlg__printf_format(const char* str, ...) { + va_list vlist; + va_start(vlist, str); + + va_list vlistcopy; + va_copy(vlistcopy, vlist); + int needed = vsnprintf(NULL, 0, str, vlist); + if(needed < 0) { + printf("dlg__printf_format: invalid format given\n"); + va_end(vlist); + va_end(vlistcopy); + return NULL; + } + + va_end(vlist); + + size_t* buf_size; + char** buf = dlg_thread_buffer(&buf_size); + if(*buf_size <= (unsigned int) needed) { + *buf_size = (needed + 1) * 2; + *buf = (char*) xrealloc(*buf, *buf_size); + } + + vsnprintf(*buf, *buf_size, str, vlistcopy); + va_end(vlistcopy); + + return *buf; +} + +void dlg__do_log(enum dlg_level lvl, const char* const* tags, const char* file, int line, + const char* func, const char* string, const char* expr) { + struct dlg_data* data = dlg_data(); + unsigned int tag_count = 0; + + // push default tags + while(tags[tag_count]) { + vec_push(data->tags, tags[tag_count++]); + } + + // push current global tags + for(size_t i = 0; i < vec_size(data->pairs); ++i) { + const struct dlg_tag_func_pair pair = data->pairs[i]; + if(pair.func == NULL || !strcmp(pair.func, func)) { + vec_push(data->tags, pair.tag); + } + } + + // push call-specific tags, skip first terminating NULL + ++tag_count; + while(tags[tag_count]) { + vec_push(data->tags, tags[tag_count++]); + } + + vec_push(data->tags, NULL); // terminating NULL + struct dlg_origin origin; + origin.level = lvl; + origin.file = file; + origin.line = line; + origin.func = func; + origin.expr = expr; + origin.tags = data->tags; + + g_handler(&origin, string, g_data); + vec_clear(data->tags); +} + +#ifdef _MSC_VER +// shitty msvc compatbility +// meson gives us sane paths (separated by '/') while on MSVC, +// __FILE__ contains a '\\' separator. +static bool path_same(char a, char b) { + return (a == b) || + (a == '/' && b == '\\') || + (a == '\\' && b == '/'); +} +#else + +static inline bool path_same(char a, char b) { + return a == b; +} + +#endif + +const char* dlg__strip_root_path(const char* file, const char* base) { + if(!file) { + return NULL; + } + + const char* saved = file; + if(*file == '.') { // relative path detected + while(*(++file) == '.' || *file == '/' || *file == '\\'); + if(*file == '\0') { // weird case: purely relative path without file + return saved; + } + + return file; + } + + // strip base from file if it is given + if(base) { + char fn = *file; + char bn = *base; + while(bn != '\0' && path_same(fn, bn)) { + fn = *(++file); + bn = *(++base); + } + + if(fn == '\0' || bn != '\0') { // weird case: base isn't prefix of file + return saved; + } + } + + return file; +} diff --git a/src/thirdparty/freetype2/src/gxvalid/README b/src/thirdparty/freetype2/src/gxvalid/README index d49358784..5eb623b3d 100644 --- a/src/thirdparty/freetype2/src/gxvalid/README +++ b/src/thirdparty/freetype2/src/gxvalid/README @@ -518,7 +518,7 @@ gxvalid: TrueType GX validator ------------------------------------------------------------------------ -Copyright (C) 2004-2019 by +Copyright (C) 2004-2025 by suzuki toshiya, Masatake YAMATO, Red hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg. diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvalid.h b/src/thirdparty/freetype2/src/gxvalid/gxvalid.h index 969cd0927..a9537a156 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvalid.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvalid.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT table validation (specification only). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -28,13 +28,12 @@ #ifndef GXVALID_H_ #define GXVALID_H_ -#include -#include FT_FREETYPE_H +#include -#include "gxverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ +#include "gxverror.h" /* must come before `ftvalid.h' */ -#include FT_INTERNAL_VALIDATE_H -#include FT_INTERNAL_STREAM_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvbsln.c b/src/thirdparty/freetype2/src/gxvalid/gxvbsln.c index f22f2545f..28f1873b0 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvbsln.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvbsln.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT bsln table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvcommn.c b/src/thirdparty/freetype2/src/gxvalid/gxvcommn.c index c5cb8ebe8..f66640444 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvcommn.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvcommn.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common tables validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -46,16 +46,11 @@ /*************************************************************************/ /*************************************************************************/ - static int - gxv_compare_ushort_offset( FT_UShort* a, - FT_UShort* b ) + FT_COMPARE_DEF( int ) + gxv_compare_ushort_offset( const void* a, + const void* b ) { - if ( *a < *b ) - return -1; - else if ( *a > *b ) - return 1; - else - return 0; + return *(FT_UShort*)a - *(FT_UShort*)b; } @@ -78,7 +73,7 @@ buff[nmemb] = limit; ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_UShort ), - ( int(*)(const void*, const void*) )gxv_compare_ushort_offset ); + gxv_compare_ushort_offset ); if ( buff[nmemb] > limit ) FT_INVALID_OFFSET; @@ -111,13 +106,17 @@ /*************************************************************************/ /*************************************************************************/ - static int - gxv_compare_ulong_offset( FT_ULong* a, - FT_ULong* b ) + FT_COMPARE_DEF( int ) + gxv_compare_ulong_offset( const void* a, + const void* b ) { - if ( *a < *b ) + FT_ULong a_ = *(FT_ULong*)a; + FT_ULong b_ = *(FT_ULong*)b; + + + if ( a_ < b_ ) return -1; - else if ( *a > *b ) + else if ( a_ > b_ ) return 1; else return 0; @@ -143,7 +142,7 @@ buff[nmemb] = limit; ft_qsort( buff, ( nmemb + 1 ), sizeof ( FT_ULong ), - ( int(*)(const void*, const void*) )gxv_compare_ulong_offset ); + gxv_compare_ulong_offset ); if ( buff[nmemb] > limit ) FT_INVALID_OFFSET; @@ -439,7 +438,7 @@ 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", + GXV_TRACE(( "too short, glyphs %d - %ld are missing\n", i, gxvalid->face->num_glyphs )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); break; @@ -534,7 +533,7 @@ if ( lastGlyph < firstGlyph ) { - GXV_TRACE(( "reverse ordered range specification at unit %d:", + GXV_TRACE(( "reverse ordered range specification at unit %d:" " lastGlyph %d < firstGlyph %d ", unit, lastGlyph, firstGlyph )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); @@ -605,7 +604,7 @@ if ( lastGlyph < firstGlyph ) { - GXV_TRACE(( "reverse ordered range specification at unit %d:", + GXV_TRACE(( "reverse ordered range specification at unit %d:" " lastGlyph %d < firstGlyph %d ", unit, lastGlyph, firstGlyph )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); @@ -825,7 +824,7 @@ face = gxvalid->face; if ( face->num_glyphs < gid ) { - GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n", + GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %ld < %d\n", face->num_glyphs, gid )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); } @@ -1034,7 +1033,7 @@ GXV_NAME_ENTER( "StateArray" ); GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n", - (int)(*length_p), stateSize, (int)(maxClassID) )); + (int)( *length_p ), stateSize, (int)maxClassID )); /* * 2 states are predefined and must be described in StateArray: @@ -1419,7 +1418,7 @@ GXV_NAME_ENTER( "XStateArray" ); GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n", - (int)(*length_p), stateSize, (int)(maxClassID) )); + (int)( *length_p ), (int)stateSize, (int)maxClassID )); /* * 2 states are predefined and must be described: @@ -1493,9 +1492,11 @@ 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 )); + FT_TRACE4(( "-> new state = %d (supposed)\n", + state )); + FT_TRACE4(( "but newState index 0x%04x" + " is not aligned to %d-classes\n", + newState_idx, 1 + maxClassID )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); } @@ -1581,10 +1582,10 @@ stateArray = FT_NEXT_ULONG( p ); entryTable = FT_NEXT_ULONG( p ); - GXV_TRACE(( "nClasses =0x%08x\n", gxvalid->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 )); + GXV_TRACE(( "nClasses =0x%08lx\n", gxvalid->xstatetable.nClasses )); + GXV_TRACE(( "offset to classTable=0x%08lx\n", classTable )); + GXV_TRACE(( "offset to stateArray=0x%08lx\n", stateArray )); + GXV_TRACE(( "offset to entryTable=0x%08lx\n", entryTable )); if ( gxvalid->xstatetable.nClasses > 0xFFFFU ) FT_INVALID_DATA; @@ -1729,7 +1730,7 @@ { #ifdef FT_DEBUG_LEVEL_TRACE if ( odtect->range[i].name || odtect->range[j].name ) - GXV_TRACE(( "found overlap between range %d and range %d\n", + GXV_TRACE(( "found overlap between range %u and range %u\n", i, j )); else GXV_TRACE(( "found overlap between `%s' and `%s\'\n", diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvcommn.h b/src/thirdparty/freetype2/src/gxvalid/gxvcommn.h index 334dc9dfb..1e19ccfb6 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvcommn.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvcommn.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common tables validation (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -43,10 +43,9 @@ #define GXVCOMMN_H_ -#include #include "gxvalid.h" -#include FT_INTERNAL_DEBUG_H -#include FT_SFNT_NAMES_H +#include +#include FT_BEGIN_HEADER @@ -62,8 +61,11 @@ FT_BEGIN_HEADER #undef GXV_LOAD_UNUSED_VARS /* debug purpose */ -#define IS_PARANOID_VALIDATION ( gxvalid->root->level >= FT_VALIDATE_PARANOID ) -#define GXV_SET_ERR_IF_PARANOID( err ) { if ( IS_PARANOID_VALIDATION ) ( err ); } +#define IS_PARANOID_VALIDATION \ + ( gxvalid->root->level >= FT_VALIDATE_PARANOID ) +#define GXV_SET_ERR_IF_PARANOID( err ) \ + do { if ( IS_PARANOID_VALIDATION ) ( err ); } while ( 0 ) + /*************************************************************************/ /*************************************************************************/ @@ -262,17 +264,17 @@ FT_BEGIN_HEADER } GXV_ValidatorRec; -#define GXV_TABLE_DATA( tag, field ) \ +#define GXV_TABLE_DATA( tag, field ) \ ( ( (GXV_ ## tag ## _Data)gxvalid->table_data )->field ) #undef FT_INVALID_ -#define FT_INVALID_( _error ) \ +#define FT_INVALID_( _error ) \ ft_validator_error( gxvalid->root, FT_THROW( _error ) ) -#define GXV_LIMIT_CHECK( _count ) \ - FT_BEGIN_STMNT \ +#define GXV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ if ( p + _count > ( limit? limit : gxvalid->root->limit ) ) \ - FT_INVALID_TOO_SHORT; \ + FT_INVALID_TOO_SHORT; \ FT_END_STMNT @@ -280,19 +282,19 @@ FT_BEGIN_HEADER #define GXV_INIT gxvalid->debug_indent = 0 -#define GXV_NAME_ENTER( name ) \ - FT_BEGIN_STMNT \ - gxvalid->debug_indent += 2; \ - FT_TRACE4(( "%*.s", gxvalid->debug_indent, 0 )); \ - FT_TRACE4(( "%s table\n", name )); \ +#define GXV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + gxvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ FT_END_STMNT #define GXV_EXIT gxvalid->debug_indent -= 2 -#define GXV_TRACE( s ) \ - FT_BEGIN_STMNT \ - FT_TRACE4(( "%*.s", gxvalid->debug_indent, 0 )); \ - FT_TRACE4( s ); \ +#define GXV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", gxvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ FT_END_STMNT #else /* !FT_DEBUG_LEVEL_TRACE */ @@ -514,9 +516,6 @@ FT_BEGIN_HEADER 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 diff --git a/src/thirdparty/freetype2/src/gxvalid/gxverror.h b/src/thirdparty/freetype2/src/gxvalid/gxverror.h index da0edb35f..73acb7fa4 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxverror.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxverror.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT validation module error codes (specification only). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -35,7 +35,7 @@ #ifndef GXVERROR_H_ #define GXVERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -43,7 +43,7 @@ #define FT_ERR_PREFIX GXV_Err_ #define FT_ERR_BASE FT_Mod_Err_GXvalid -#include FT_ERRORS_H +#include #endif /* GXVERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvfeat.c b/src/thirdparty/freetype2/src/gxvalid/gxvfeat.c index e1a12a18e..5d4aca04c 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvfeat.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvfeat.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT feat table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -90,7 +90,7 @@ if ( feature >= gxv_feat_registry_length ) { - GXV_TRACE(( "feature number %d is out of range %d\n", + GXV_TRACE(( "feature number %d is out of range %lu\n", feature, gxv_feat_registry_length )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); goto Exit; @@ -306,7 +306,7 @@ FT_INVALID_FORMAT; featureNameCount = FT_NEXT_USHORT( p ); - GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount )); + GXV_TRACE(( " (featureNameCount = %u)\n", featureNameCount )); if ( !( IS_PARANOID_VALIDATION ) ) p += 6; /* skip (none) and (none) */ diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvfeat.h b/src/thirdparty/freetype2/src/gxvalid/gxvfeat.h index 6c9892910..6a0cbea35 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvfeat.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvfeat.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT feat table validation (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvjust.c b/src/thirdparty/freetype2/src/gxvalid/gxvjust.c index a58237785..1b3a8b1ac 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvjust.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvjust.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT just table validation (body). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -28,7 +28,7 @@ #include "gxvalid.h" #include "gxvcommn.h" -#include FT_SFNT_NAMES_H +#include /************************************************************************** @@ -78,7 +78,7 @@ return; GXV_TRACE(( "just table includes too large %s" - " GID=%d > %d (in maxp)\n", + " GID=%d > %ld (in maxp)\n", msg_tag, gid, gxvalid->face->num_glyphs )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); } @@ -140,7 +140,7 @@ count = FT_NEXT_ULONG( p ); for ( i = 0; i < count; i++ ) { - GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count )); + GXV_TRACE(( "validating wdc pair %lu/%lu\n", i + 1, count )); gxv_just_wdp_entry_validate( p, limit, gxvalid ); p += gxvalid->subtable_length; } @@ -156,7 +156,6 @@ { FT_Bytes p = table; FT_Bytes wdc_end = table + GXV_JUST_DATA( wdc_offset_max ); - FT_UInt i; GXV_NAME_ENTER( "just justDeltaClusters" ); @@ -164,7 +163,7 @@ if ( limit <= wdc_end ) FT_INVALID_OFFSET; - for ( i = 0; p <= wdc_end; i++ ) + while ( p <= wdc_end ) { gxv_just_wdc_entry_validate( p, limit, gxvalid ); p += gxvalid->subtable_length; @@ -206,7 +205,8 @@ if ( lowerLimit >= upperLimit ) { GXV_TRACE(( "just table includes invalid range spec:" - " lowerLimit(%d) > upperLimit(%d)\n" )); + " lowerLimit(%ld) > upperLimit(%ld)\n", + lowerLimit, upperLimit )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA ); } @@ -294,14 +294,14 @@ gxvalid->subtable_length = (FT_ULong)( p - table ); if ( variantsAxis != 0x64756374L ) /* 'duct' */ - GXV_TRACE(( "variantsAxis 0x%08x is non default value", + GXV_TRACE(( "variantsAxis 0x%08lx is non default value", variantsAxis )); if ( minimumLimit > noStretchValue ) - GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n", + GXV_TRACE(( "type4:minimumLimit 0x%08lx > noStretchValue 0x%08lx\n", minimumLimit, noStretchValue )); else if ( noStretchValue > maximumLimit ) - GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n", + GXV_TRACE(( "type4:noStretchValue 0x%08lx > maximumLimit 0x%08lx\n", noStretchValue, maximumLimit )); else if ( !IS_PARANOID_VALIDATION ) return; @@ -389,7 +389,7 @@ GXV_LIMIT_CHECK( 4 ); actionCount = FT_NEXT_ULONG( p ); - GXV_TRACE(( "actionCount = %d\n", actionCount )); + GXV_TRACE(( "actionCount = %lu\n", actionCount )); for ( i = 0; i < actionCount; i++ ) { @@ -514,14 +514,14 @@ coverage = FT_NEXT_USHORT( p ); subFeatureFlags = FT_NEXT_ULONG( p ); - GXV_TRACE(( " justClassTable: coverage = 0x%04x (%s) ", coverage )); + GXV_TRACE(( " justClassTable: coverage = 0x%04x ", coverage )); if ( ( coverage & 0x4000 ) == 0 ) GXV_TRACE(( "ascending\n" )); else GXV_TRACE(( "descending\n" )); if ( subFeatureFlags ) - GXV_TRACE(( " justClassTable: nonzero value (0x%08x)" + GXV_TRACE(( " justClassTable: nonzero value (0x%08lx)" " in unused subFeatureFlags\n", subFeatureFlags )); gxvalid->statetable.optdata = NULL; @@ -672,7 +672,7 @@ FT_TRACE3(( "validating `just' table\n" )); GXV_INIT; - limit = gxvalid->root->limit; + limit = gxvalid->root->limit; GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 ); version = FT_NEXT_ULONG( p ); @@ -684,7 +684,7 @@ /* Version 1.0 (always:2000) */ - GXV_TRACE(( " (version = 0x%08x)\n", version )); + GXV_TRACE(( " (version = 0x%08lx)\n", version )); if ( version != 0x00010000UL ) FT_INVALID_FORMAT; diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvkern.c b/src/thirdparty/freetype2/src/gxvalid/gxvkern.c index a7532335a..222fd038c 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvkern.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvkern.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT kern table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -28,8 +28,8 @@ #include "gxvalid.h" #include "gxvcommn.h" -#include FT_SFNT_NAMES_H -#include FT_SERVICE_GX_VALIDATE_H +#include +#include /************************************************************************** @@ -487,7 +487,7 @@ if ( gxvalid->face->num_glyphs != glyphCount ) { - GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", + GXV_TRACE(( "maxGID=%ld, but glyphCount=%d\n", gxvalid->face->num_glyphs, glyphCount )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID ); } @@ -745,7 +745,7 @@ #ifdef GXV_LOAD_TRACE_VARS FT_UShort version = 0; /* MS only: subtable version, unused */ #endif - FT_ULong length; /* MS: 16bit, Apple: 32bit*/ + FT_ULong length; /* MS: 16bit, Apple: 32bit */ FT_UShort coverage; #ifdef GXV_LOAD_TRACE_VARS FT_UShort tupleIndex = 0; /* Apple only */ @@ -772,7 +772,7 @@ tupleIndex = 0; #endif GXV_TRACE(( "Subtable version = %d\n", version )); - GXV_TRACE(( "Subtable length = %d\n", length )); + GXV_TRACE(( "Subtable length = %lu\n", length )); break; case KERN_DIALECT_APPLE: @@ -783,7 +783,7 @@ #ifdef GXV_LOAD_TRACE_VARS tupleIndex = 0; #endif - GXV_TRACE(( "Subtable length = %d\n", length )); + GXV_TRACE(( "Subtable length = %lu\n", length )); if ( KERN_IS_NEW( gxvalid ) ) { @@ -800,7 +800,7 @@ default: length = u16[1]; GXV_TRACE(( "cannot detect subtable dialect, " - "just skip %d byte\n", length )); + "just skip %lu byte\n", length )); goto Exit; } @@ -884,7 +884,7 @@ for ( i = 0; i < nTables; i++ ) { - GXV_TRACE(( "validating subtable %d/%d\n", i, nTables )); + GXV_TRACE(( "validating subtable %u/%lu\n", i, nTables )); /* p should be 32bit-aligned? */ gxv_kern_subtable_validate( p, 0, gxvalid ); p += gxvalid->subtable_length; diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvlcar.c b/src/thirdparty/freetype2/src/gxvalid/gxvlcar.c index 13b3de3ea..4882df424 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvlcar.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvlcar.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT lcar table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmod.c b/src/thirdparty/freetype2/src/gxvalid/gxvmod.c index eeadeb3e1..4f27c5a8a 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmod.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmod.c @@ -4,7 +4,7 @@ * * FreeType's TrueTypeGX/AAT validation module implementation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -25,12 +25,11 @@ */ -#include -#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 +#include +#include +#include +#include #include "gxvmod.h" #include "gxvalid.h" @@ -63,7 +62,7 @@ if ( error ) goto Exit; - if ( FT_ALLOC( *table, *table_len ) ) + if ( FT_QALLOC( *table, *table_len ) ) goto Exit; error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); @@ -77,27 +76,31 @@ 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_LOAD( _sfnt ) \ + FT_BEGIN_STMNT \ + 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; \ + } \ + FT_END_STMNT -#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_VALIDATE( _sfnt ) \ + FT_BEGIN_STMNT \ + 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; \ + } \ + FT_END_STMNT #define GXV_TABLE_SET( _sfnt ) \ if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) \ diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmod.h b/src/thirdparty/freetype2/src/gxvalid/gxvmod.h index 6ecd7312c..39a375d97 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmod.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmod.h @@ -5,7 +5,7 @@ * FreeType's TrueTypeGX/AAT validation module implementation * (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -29,8 +29,7 @@ #ifndef GXVMOD_H_ #define GXVMOD_H_ -#include -#include FT_MODULE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort.c index 288ef6988..846ac48b9 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT mort table validation (body). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -207,7 +207,7 @@ func = fmt_funcs_table[type]; if ( !func ) - GXV_TRACE(( "morx type %d is reserved\n", type )); + GXV_TRACE(( "morx type %u is reserved\n", type )); func( p, p + rest, gxvalid ); @@ -288,7 +288,7 @@ for ( i = 0; i < nChains; i++ ) { - GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains )); + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); gxv_mort_chain_validate( p, limit, gxvalid ); p += gxvalid->subtable_length; diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort.h b/src/thirdparty/freetype2/src/gxvalid/gxvmort.h index 0619e24fb..66d46a072 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common definition for mort table (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -31,7 +31,10 @@ #include "gxvalid.h" #include "gxvcommn.h" -#include FT_SFNT_NAMES_H +#include + + +FT_BEGIN_HEADER typedef struct GXV_mort_featureRec_ @@ -88,6 +91,8 @@ GXV_Validator gxvalid ); +FT_END_HEADER + #endif /* GXVMORT_H_ */ diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort0.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort0.c index 2c01bf95e..5817c27d7 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort0.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort0.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type0 (Indic Script Rearrangement) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort1.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort1.c index c71ba1335..20cccadf1 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort1.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort1.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type1 (Contextual Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort2.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort2.c index 889d3bd58..80aabbc9c 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort2.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort2.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type2 (Ligature Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -152,7 +152,7 @@ GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset ); if ( p < lat_base ) { - GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n", + GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%ld byte rewind)\n", ligActionOffset, lat_base - p )); /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ @@ -160,7 +160,7 @@ } else if ( lat_limit < p ) { - GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n", + GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%ld byte overrun)\n", ligActionOffset, p - lat_limit )); /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */ @@ -187,17 +187,17 @@ offset = lig_action & 0x3FFFFFFFUL; if ( offset * 2 < optdata->ligatureTable ) { - GXV_TRACE(( "too short offset 0x%08x:" - " 2 x offset < ligatureTable (%d byte rewind)\n", + GXV_TRACE(( "too short offset 0x%08lx:" + " 2 x offset < ligatureTable (%lu byte rewind)\n", offset, optdata->ligatureTable - offset * 2 )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); } else if ( offset * 2 > optdata->ligatureTable + optdata->ligatureTable_length ) { - GXV_TRACE(( "too long offset 0x%08x:" + GXV_TRACE(( "too long offset 0x%08lx:" " 2 x offset > ligatureTable + ligatureTable_length" - " (%d byte overrun)\n", + " (%lu byte overrun)\n", offset, optdata->ligatureTable + optdata->ligatureTable_length - offset * 2 )); diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort4.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort4.c index f8ce6cf78..40ed73007 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort4.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort4.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type4 (Non-Contextual Glyph Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmort5.c b/src/thirdparty/freetype2/src/gxvalid/gxvmort5.c index 1ba1e5ded..1b274be3b 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmort5.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmort5.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type5 (Contextual Glyph Insertion) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -63,7 +63,7 @@ *GXV_mort_subtable_type5_StateOptRecData; - FT_LOCAL_DEF( void ) + static void gxv_mort_subtable_type5_subtable_setup( FT_UShort table_size, FT_UShort classTable, FT_UShort stateArray, diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx.c index 8bd45c27e..931e57b00 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT morx table validation (body). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -84,7 +84,7 @@ p += 4; #endif - GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n", + GXV_TRACE(( "validating chain subtable %d/%d (%lu bytes)\n", i + 1, nSubtables, length )); type = coverage & 0x0007; @@ -99,7 +99,7 @@ func = fmt_funcs_table[type]; if ( !func ) - GXV_TRACE(( "morx type %d is reserved\n", type )); + GXV_TRACE(( "morx type %lu is reserved\n", type )); func( p, p + rest, gxvalid ); @@ -186,7 +186,7 @@ for ( i = 0; i < nChains; i++ ) { - GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains )); + GXV_TRACE(( "validating chain %lu/%lu\n", i + 1, nChains )); GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); gxv_morx_chain_validate( p, limit, gxvalid ); p += gxvalid->subtable_length; diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx.h b/src/thirdparty/freetype2/src/gxvalid/gxvmorx.h index e25727034..2b8bf3575 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx.h +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common definition for morx table (specification). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -33,7 +33,10 @@ #include "gxvcommn.h" #include "gxvmort.h" -#include FT_SFNT_NAMES_H +#include + + +FT_BEGIN_HEADER FT_LOCAL( void ) @@ -62,6 +65,8 @@ GXV_Validator gxvalid ); +FT_END_HEADER + #endif /* GXVMORX_H_ */ diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx0.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx0.c index d7764a0ae..0085ac92f 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx0.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx0.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type0 (Indic Script Rearrangement) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx1.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx1.c index 5b41b3605..b495412ff 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx1.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx1.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type1 (Contextual Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx2.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx2.c index ec4c81299..0527161dc 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx2.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx2.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type2 (Ligature Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -72,11 +72,11 @@ optdata->componentTable = FT_NEXT_ULONG( p ); optdata->ligatureTable = FT_NEXT_ULONG( p ); - GXV_TRACE(( "offset to ligActionTable=0x%08x\n", + GXV_TRACE(( "offset to ligActionTable=0x%08lx\n", optdata->ligActionTable )); - GXV_TRACE(( "offset to componentTable=0x%08x\n", + GXV_TRACE(( "offset to componentTable=0x%08lx\n", optdata->componentTable )); - GXV_TRACE(( "offset to ligatureTable=0x%08x\n", + GXV_TRACE(( "offset to ligatureTable=0x%08lx\n", optdata->ligatureTable )); } @@ -116,19 +116,19 @@ gxv_set_length_by_ulong_offset( o, l, buff, 6, table_size, gxvalid ); - GXV_TRACE(( "classTable: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "classTable: offset=0x%08lx length=0x%08lx\n", classTable, *classTable_length_p )); - GXV_TRACE(( "stateArray: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "stateArray: offset=0x%08lx length=0x%08lx\n", stateArray, *stateArray_length_p )); - GXV_TRACE(( "entryTable: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "entryTable: offset=0x%08lx length=0x%08lx\n", entryTable, *entryTable_length_p )); - GXV_TRACE(( "ligActionTable: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "ligActionTable: offset=0x%08lx length=0x%08lx\n", optdata->ligActionTable, optdata->ligActionTable_length )); - GXV_TRACE(( "componentTable: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "componentTable: offset=0x%08lx length=0x%08lx\n", optdata->componentTable, optdata->componentTable_length )); - GXV_TRACE(( "ligatureTable: offset=0x%08x length=0x%08x\n", + GXV_TRACE(( "ligatureTable: offset=0x%08lx length=0x%08lx\n", optdata->ligatureTable, optdata->ligatureTable_length )); @@ -157,12 +157,12 @@ if ( p < lat_base ) { - GXV_TRACE(( "p < lat_base (%d byte rewind)\n", lat_base - p )); + GXV_TRACE(( "p < lat_base (%ld 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 )); + GXV_TRACE(( "lat_limit < p (%ld byte overrun)\n", p - lat_limit )); FT_INVALID_OFFSET; } @@ -196,7 +196,7 @@ GXV_TRACE(( "ligature action table includes" " too negative offset moving all GID" - " below defined range: 0x%04x\n", + " below defined range: 0x%04lx\n", offset & 0xFFFFU )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); } @@ -207,14 +207,14 @@ GXV_TRACE(( "ligature action table includes" " too large offset moving all GID" - " over defined range: 0x%04x\n", + " over defined range: 0x%04lx\n", offset & 0xFFFFU )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); } GXV_TRACE(( "ligature action table includes" " invalid offset to add to 16-bit GID:" - " 0x%08x\n", offset )); + " 0x%08lx\n", offset )); GXV_SET_ERR_IF_PARANOID( FT_INVALID_OFFSET ); } } diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx4.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx4.c index 7b041534c..e6e99fcb7 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx4.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx4.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for "morx" type4 (Non-Contextual Glyph Substitution) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvmorx5.c b/src/thirdparty/freetype2/src/gxvalid/gxvmorx5.c index 70a462365..7dec9a901 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvmorx5.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvmorx5.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type5 (Contextual Glyph Insertion) subtable. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvopbd.c b/src/thirdparty/freetype2/src/gxvalid/gxvopbd.c index f055a2205..65003100c 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvopbd.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvopbd.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT opbd table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -188,7 +188,7 @@ /* only 0x00010000 is defined (1996) */ - GXV_TRACE(( "(version=0x%08x)\n", version )); + GXV_TRACE(( "(version=0x%08lx)\n", version )); if ( 0x00010000UL != version ) FT_INVALID_FORMAT; diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvprop.c b/src/thirdparty/freetype2/src/gxvalid/gxvprop.c index e1911edd4..31f2b5eb3 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvprop.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvprop.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT prop table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -283,7 +283,7 @@ format = FT_NEXT_USHORT( p ); defaultProp = FT_NEXT_USHORT( p ); - GXV_TRACE(( " version 0x%08x\n", version )); + GXV_TRACE(( " version 0x%08lx\n", version )); GXV_TRACE(( " format 0x%04x\n", format )); GXV_TRACE(( " defaultProp 0x%04x\n", defaultProp )); @@ -309,7 +309,7 @@ if ( format == 0 ) { FT_TRACE3(( "(format 0, no per-glyph properties, " - "remaining %d bytes are skipped)", limit - p )); + "remaining %ld bytes are skipped)", limit - p )); goto Exit; } diff --git a/src/thirdparty/freetype2/src/gxvalid/gxvtrak.c b/src/thirdparty/freetype2/src/gxvalid/gxvtrak.c index b7794b7af..329f12729 100644 --- a/src/thirdparty/freetype2/src/gxvalid/gxvtrak.c +++ b/src/thirdparty/freetype2/src/gxvalid/gxvtrak.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT trak table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * @@ -130,7 +130,7 @@ p = table + j * ( 4 + 2 + 2 ); t = FT_NEXT_LONG( p ); if ( t == track ) - GXV_TRACE(( "duplicated entries found for track value 0x%x\n", + GXV_TRACE(( "duplicated entries found for track value 0x%lx\n", track )); } } @@ -231,7 +231,7 @@ gxvalid->table_data = trak; gxvalid->face = face; - limit = gxvalid->root->limit; + limit = gxvalid->root->limit; FT_TRACE3(( "validating `trak' table\n" )); GXV_INIT; @@ -243,7 +243,7 @@ vertOffset = FT_NEXT_USHORT( p ); reserved = FT_NEXT_USHORT( p ); - GXV_TRACE(( " (version = 0x%08x)\n", version )); + GXV_TRACE(( " (version = 0x%08lx)\n", version )); GXV_TRACE(( " (format = 0x%04x)\n", format )); GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset )); GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset )); diff --git a/src/thirdparty/freetype2/src/gzip/ftgzip.c b/src/thirdparty/freetype2/src/gzip/ftgzip.c index 5e78bc6f8..ffa3824d4 100644 --- a/src/thirdparty/freetype2/src/gzip/ftgzip.c +++ b/src/thirdparty/freetype2/src/gzip/ftgzip.c @@ -8,7 +8,7 @@ * parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,15 +20,14 @@ */ -#include -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H -#include FT_GZIP_H +#include +#include +#include +#include #include FT_CONFIG_STANDARD_LIBRARY_H -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -36,7 +35,7 @@ #define FT_ERR_PREFIX Gzip_Err_ #define FT_ERR_BASE FT_Mod_Err_Gzip -#include FT_ERRORS_H +#include #ifdef FT_CONFIG_OPTION_USE_ZLIB @@ -70,10 +69,14 @@ /* */ /* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */ /* include the wrong `zconf.h' file, leading to errors. */ -#include "zlib.h" -#undef SLOW -#define SLOW 1 /* we can't use asm-optimized sources here! */ +#define ZEXPORT + /* prevent zlib functions from being visible outside their object files */ +#define ZEXTERN static + +#define HAVE_MEMCPY 1 +#define Z_SOLO 1 +#define Z_FREETYPE 1 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ /* We disable the warning `conversion from XXX to YYY, */ @@ -84,24 +87,25 @@ #pragma warning( disable : 4244 ) #endif /* _MSC_VER */ - /* 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 +#if defined( __GNUC__ ) +#pragma GCC diagnostic push +#ifndef __cplusplus +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif - /* infutil.c must be included before infcodes.c */ #include "zutil.c" -#include "inftrees.c" -#include "infutil.c" -#include "infcodes.c" -#include "infblock.c" +#include "inffast.c" #include "inflate.c" +#include "inftrees.c" #include "adler32.c" +#include "crc32.c" + +#if defined( __GNUC__ ) +#pragma GCC diagnostic pop +#endif #if defined( _MSC_VER ) #pragma warning( pop ) @@ -122,48 +126,32 @@ 'malloc/free' */ static voidpf - ft_gzip_alloc( FT_Memory memory, - uInt items, - uInt size ) + ft_gzip_alloc( voidpf opaque, + uInt items, + uInt size ) { - FT_ULong sz = (FT_ULong)size * items; + FT_Memory memory = (FT_Memory)opaque; + FT_ULong sz = (FT_ULong)size * items; FT_Error error; - FT_Pointer p = NULL; + FT_Pointer p = NULL; - (void)FT_ALLOC( p, sz ); + /* allocate and zero out */ + FT_MEM_ALLOC( p, sz ); return p; } static void - ft_gzip_free( FT_Memory memory, - voidpf address ) + ft_gzip_free( voidpf opaque, + voidpf address ) { + FT_Memory memory = (FT_Memory)opaque; + + FT_MEM_FREE( address ); } - -#if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC ) - - 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 && !USE_ZLIB_ZCALLOC */ - - /***************************************************************************/ /***************************************************************************/ /***** *****/ @@ -305,8 +293,8 @@ } /* 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->zalloc = ft_gzip_alloc; + zstream->zfree = ft_gzip_free; zstream->opaque = stream->memory; zstream->avail_in = 0; @@ -463,12 +451,13 @@ FT_ULong count ) { FT_Error error = FT_Err_Ok; - FT_ULong delta; for (;;) { - delta = (FT_ULong)( zip->limit - zip->cursor ); + FT_ULong delta = (FT_ULong)( zip->limit - zip->cursor ); + + if ( delta >= count ) delta = count; @@ -672,7 +661,7 @@ FT_Byte* zip_buff = NULL; - if ( !FT_ALLOC( zip_buff, zip_size ) ) + if ( !FT_QALLOC( zip_buff, zip_size ) ) { FT_ULong count; @@ -742,11 +731,12 @@ stream.next_out = output; stream.avail_out = (uInt)*output_len; - stream.zalloc = (alloc_func)ft_gzip_alloc; - stream.zfree = (free_func) ft_gzip_free; + stream.zalloc = ft_gzip_alloc; + stream.zfree = ft_gzip_free; stream.opaque = memory; err = inflateInit2( &stream, MAX_WBITS|32 ); + if ( err != Z_OK ) return FT_THROW( Invalid_Argument ); @@ -773,6 +763,9 @@ if ( err == Z_DATA_ERROR ) return FT_THROW( Invalid_Table ); + if ( err == Z_NEED_DICT ) + return FT_THROW( Invalid_Table ); + return FT_Err_Ok; } diff --git a/src/thirdparty/freetype2/src/lzw/ftlzw.c b/src/thirdparty/freetype2/src/lzw/ftlzw.c index 9805a1e3b..a03e7e5b2 100644 --- a/src/thirdparty/freetype2/src/lzw/ftlzw.c +++ b/src/thirdparty/freetype2/src/lzw/ftlzw.c @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * Albert Chin-A-Young. * * based on code in `src/gzip/ftgzip.c' @@ -21,15 +21,14 @@ * */ -#include -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H -#include FT_LZW_H +#include +#include +#include +#include #include FT_CONFIG_STANDARD_LIBRARY_H -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -37,7 +36,7 @@ #define FT_ERR_PREFIX LZW_Err_ #define FT_ERR_BASE FT_Mod_Err_LZW -#include FT_ERRORS_H +#include #ifdef FT_CONFIG_OPTION_USE_LZW @@ -370,7 +369,7 @@ FT_ZERO( stream ); stream->memory = memory; - if ( !FT_NEW( zip ) ) + if ( !FT_QNEW( zip ) ) { error = ft_lzw_file_init( zip, stream, source ); if ( error ) @@ -384,7 +383,7 @@ stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; - stream->base = 0; + stream->base = NULL; stream->read = ft_lzw_stream_io; stream->close = ft_lzw_stream_close; @@ -393,7 +392,7 @@ } -#include "ftzopen.c" +#include "ftzopen.ctpl" #else /* !FT_CONFIG_OPTION_USE_LZW */ diff --git a/src/thirdparty/freetype2/src/lzw/ftzopen.c b/src/thirdparty/freetype2/src/lzw/ftzopen.ctpl similarity index 95% rename from src/thirdparty/freetype2/src/lzw/ftzopen.c rename to src/thirdparty/freetype2/src/lzw/ftzopen.ctpl index 67e6760f9..1dffedd03 100644 --- a/src/thirdparty/freetype2/src/lzw/ftzopen.c +++ b/src/thirdparty/freetype2/src/lzw/ftzopen.ctpl @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,9 @@ */ #include "ftzopen.h" -#include FT_INTERNAL_MEMORY_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_DEBUG_H +#include +#include +#include static int @@ -127,6 +127,7 @@ new_size = new_size + ( new_size >> 1 ) + 4; + /* if relocating to heap */ if ( state->stack == state->stack_0 ) { state->stack = NULL; @@ -142,9 +143,13 @@ return -1; } - if ( FT_RENEW_ARRAY( state->stack, old_size, new_size ) ) + if ( FT_QREALLOC( state->stack, old_size, new_size ) ) return -1; + /* if relocating to heap */ + if ( old_size == 0 ) + FT_MEM_COPY( state->stack, state->stack_0, FT_LZW_DEFAULT_STACK_SIZE ); + state->stack_size = new_size; } return 0; @@ -310,7 +315,7 @@ state->phase = FT_LZW_PHASE_CODE; } - /* fall-through */ + FALL_THROUGH; case FT_LZW_PHASE_CODE: { @@ -368,7 +373,7 @@ state->phase = FT_LZW_PHASE_STACK; } - /* fall-through */ + FALL_THROUGH; case FT_LZW_PHASE_STACK: { diff --git a/src/thirdparty/freetype2/src/lzw/ftzopen.h b/src/thirdparty/freetype2/src/lzw/ftzopen.h index 44fe36d6c..e362a5366 100644 --- a/src/thirdparty/freetype2/src/lzw/ftzopen.h +++ b/src/thirdparty/freetype2/src/lzw/ftzopen.h @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner. * * This file is part of the FreeType project, and may only be used, @@ -22,9 +22,9 @@ #ifndef FTZOPEN_H_ #define FTZOPEN_H_ -#include -#include FT_FREETYPE_H +#include +FT_BEGIN_HEADER /* * This is a complete re-implementation of the LZW file reader, @@ -166,6 +166,8 @@ /* */ +FT_END_HEADER + #endif /* FTZOPEN_H_ */ diff --git a/src/thirdparty/freetype2/src/otvalid/otvalid.h b/src/thirdparty/freetype2/src/otvalid/otvalid.h index 5ca819f26..2b5598e0c 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvalid.h +++ b/src/thirdparty/freetype2/src/otvalid/otvalid.h @@ -4,7 +4,7 @@ * * OpenType table validation (specification only). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,13 +20,12 @@ #define OTVALID_H_ -#include -#include FT_FREETYPE_H +#include -#include "otverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ +#include "otverror.h" /* must come before `ftvalid.h' */ -#include FT_INTERNAL_VALIDATE_H -#include FT_INTERNAL_STREAM_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/otvalid/otvbase.c b/src/thirdparty/freetype2/src/otvalid/otvbase.c index be69d7ca3..cbaf4c27c 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvbase.c +++ b/src/thirdparty/freetype2/src/otvalid/otvbase.c @@ -4,7 +4,7 @@ * * OpenType BASE table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -44,7 +44,7 @@ BaseCoordFormat = FT_NEXT_USHORT( p ); p += 2; /* skip Coordinate */ - OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); + OTV_TRACE(( " (format %u)\n", BaseCoordFormat )); switch ( BaseCoordFormat ) { @@ -83,7 +83,7 @@ BaseTagCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); + OTV_TRACE(( " (BaseTagCount = %u)\n", BaseTagCount )); OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ @@ -106,7 +106,7 @@ p += 2; /* skip DefaultIndex */ BaseCoordCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); + OTV_TRACE(( " (BaseCoordCount = %u)\n", BaseCoordCount )); OTV_LIMIT_CHECK( BaseCoordCount * 2 ); @@ -138,7 +138,7 @@ OTV_OPTIONAL_OFFSET( MaxCoord ); FeatMinMaxCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); + OTV_TRACE(( " (FeatMinMaxCount = %u)\n", FeatMinMaxCount )); table_size = FeatMinMaxCount * 8 + 6; @@ -192,7 +192,7 @@ OTV_OPTIONAL_OFFSET( DefaultMinMax ); BaseLangSysCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); + OTV_TRACE(( " (BaseLangSysCount = %u)\n", BaseLangSysCount )); table_size = BaseLangSysCount * 6 + 6; @@ -231,7 +231,7 @@ OTV_LIMIT_CHECK( 2 ); BaseScriptCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); + OTV_TRACE(( " (BaseScriptCount = %u)\n", BaseScriptCount )); OTV_LIMIT_CHECK( BaseScriptCount * 6 ); diff --git a/src/thirdparty/freetype2/src/otvalid/otvcommn.c b/src/thirdparty/freetype2/src/otvalid/otvcommn.c index 5ed172350..d6ca7eefe 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvcommn.c +++ b/src/thirdparty/freetype2/src/otvalid/otvcommn.c @@ -4,7 +4,7 @@ * * OpenType common tables validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -52,7 +52,7 @@ OTV_LIMIT_CHECK( 4 ); CoverageFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", CoverageFormat )); + OTV_TRACE(( " (format %u)\n", CoverageFormat )); switch ( CoverageFormat ) { @@ -64,7 +64,7 @@ GlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ @@ -90,7 +90,7 @@ RangeCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); + OTV_TRACE(( " (RangeCount = %u)\n", RangeCount )); OTV_LIMIT_CHECK( RangeCount * 6 ); @@ -151,6 +151,9 @@ FT_UInt result = 0; + if ( !count ) + return result; + switch ( CoverageFormat ) { case 1: @@ -230,7 +233,7 @@ OTV_LIMIT_CHECK( 4 ); ClassFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", ClassFormat )); + OTV_TRACE(( " (format %u)\n", ClassFormat )); switch ( ClassFormat ) { @@ -245,7 +248,7 @@ StartGlyph = FT_NEXT_USHORT( p ); GlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ @@ -262,7 +265,7 @@ ClassRangeCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); + OTV_TRACE(( " (ClassRangeCount = %u)\n", ClassRangeCount )); OTV_LIMIT_CHECK( ClassRangeCount * 6 ); @@ -365,14 +368,14 @@ LookupFlag = FT_NEXT_USHORT( p ); SubTableCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (type %d)\n", LookupType )); + OTV_TRACE(( " (type %u)\n", LookupType )); if ( LookupType == 0 || LookupType > otvalid->type_count ) FT_INVALID_DATA; validate = otvalid->type_funcs[LookupType - 1]; - OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); + OTV_TRACE(( " (SubTableCount = %u)\n", SubTableCount )); OTV_LIMIT_CHECK( SubTableCount * 2 ); @@ -402,7 +405,7 @@ OTV_LIMIT_CHECK( 2 ); LookupCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + OTV_TRACE(( " (LookupCount = %u)\n", LookupCount )); OTV_LIMIT_CHECK( LookupCount * 2 ); @@ -447,7 +450,7 @@ p += 2; /* skip FeatureParams (unused) */ LookupCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + OTV_TRACE(( " (LookupCount = %u)\n", LookupCount )); OTV_LIMIT_CHECK( LookupCount * 2 ); @@ -483,7 +486,7 @@ OTV_LIMIT_CHECK( 2 ); FeatureCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + OTV_TRACE(( " (FeatureCount = %u)\n", FeatureCount )); OTV_LIMIT_CHECK( FeatureCount * 2 ); @@ -529,8 +532,8 @@ ReqFeatureIndex = FT_NEXT_USHORT( p ); FeatureCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); - OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + OTV_TRACE(( " (ReqFeatureIndex = %u)\n", ReqFeatureIndex )); + OTV_TRACE(( " (FeatureCount = %u)\n", FeatureCount )); if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= otvalid->extra1 ) FT_INVALID_DATA; @@ -568,7 +571,7 @@ DefaultLangSys = FT_NEXT_USHORT( p ); LangSysCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); + OTV_TRACE(( " (LangSysCount = %u)\n", LangSysCount )); if ( DefaultLangSys != 0 ) otv_LangSys_validate( table + DefaultLangSys, otvalid ); @@ -604,7 +607,7 @@ OTV_LIMIT_CHECK( 2 ); ScriptCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); + OTV_TRACE(( " (ScriptCount = %u)\n", ScriptCount )); OTV_LIMIT_CHECK( ScriptCount * 6 ); @@ -662,7 +665,7 @@ OTV_LIMIT_CHECK( 2 ); Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (Count = %u)\n", Count )); OTV_LIMIT_CHECK( Count * 2 ); @@ -695,7 +698,7 @@ Coverage = FT_NEXT_USHORT( p ); Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (Count = %u)\n", Count )); otv_Coverage_validate( table + Coverage, otvalid, (FT_Int)Count ); @@ -728,7 +731,7 @@ OTV_LIMIT_CHECK( 2 ); Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (Count = %u)\n", Count )); OTV_LIMIT_CHECK( Count * 2 ); @@ -762,8 +765,8 @@ Count1 = FT_NEXT_USHORT( p ); Count2 = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count1 = %d)\n", Count1 )); - OTV_TRACE(( " (Count2 = %d)\n", Count2 )); + OTV_TRACE(( " (Count1 = %u)\n", Count1 )); + OTV_TRACE(( " (Count2 = %u)\n", Count2 )); if ( Count1 == 0 ) FT_INVALID_DATA; @@ -803,7 +806,7 @@ OTV_LIMIT_CHECK( 2 ); BacktrackCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); + OTV_TRACE(( " (BacktrackCount = %u)\n", BacktrackCount )); OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); p += BacktrackCount * 2; @@ -812,21 +815,21 @@ if ( InputCount == 0 ) FT_INVALID_DATA; - OTV_TRACE(( " (InputCount = %d)\n", InputCount )); + OTV_TRACE(( " (InputCount = %u)\n", InputCount )); OTV_LIMIT_CHECK( InputCount * 2 ); p += ( InputCount - 1 ) * 2; LookaheadCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); + OTV_TRACE(( " (LookaheadCount = %u)\n", LookaheadCount )); OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); p += LookaheadCount * 2; Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (Count = %u)\n", Count )); OTV_LIMIT_CHECK( Count * 4 ); @@ -863,7 +866,7 @@ ClassDef = FT_NEXT_USHORT( p ); ClassSetCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); + OTV_TRACE(( " (ClassSetCount = %u)\n", ClassSetCount )); otv_Coverage_validate( table + Coverage, otvalid, -1 ); otv_ClassDef_validate( table + ClassDef, otvalid ); @@ -907,8 +910,8 @@ GlyphCount = FT_NEXT_USHORT( p ); Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); + OTV_TRACE(( " (Count = %u)\n", Count )); OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); @@ -952,7 +955,7 @@ LookaheadClassDef = FT_NEXT_USHORT( p ); ChainClassSetCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); + OTV_TRACE(( " (ChainClassSetCount = %u)\n", ChainClassSetCount )); otv_Coverage_validate( table + Coverage, otvalid, -1 ); @@ -999,7 +1002,7 @@ OTV_LIMIT_CHECK( 2 ); BacktrackGlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + OTV_TRACE(( " (BacktrackGlyphCount = %u)\n", BacktrackGlyphCount )); OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); @@ -1008,7 +1011,7 @@ InputGlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); + OTV_TRACE(( " (InputGlyphCount = %u)\n", InputGlyphCount )); OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); @@ -1017,7 +1020,7 @@ LookaheadGlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + OTV_TRACE(( " (LookaheadGlyphCount = %u)\n", LookaheadGlyphCount )); OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); @@ -1026,7 +1029,7 @@ count2 = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", count2 )); + OTV_TRACE(( " (Count = %u)\n", count2 )); OTV_LIMIT_CHECK( count2 * 4 ); diff --git a/src/thirdparty/freetype2/src/otvalid/otvcommn.h b/src/thirdparty/freetype2/src/otvalid/otvcommn.h index bfcc5b974..20f38b495 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvcommn.h +++ b/src/thirdparty/freetype2/src/otvalid/otvcommn.h @@ -4,7 +4,7 @@ * * OpenType common tables validation (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define OTVCOMMN_H_ -#include #include "otvalid.h" -#include FT_INTERNAL_DEBUG_H +#include FT_BEGIN_HEADER @@ -106,10 +105,11 @@ FT_BEGIN_HEADER FT_Byte* pp = (FT_Byte*)_size ## _p; \ \ \ - FT_TRACE3(( "\n" \ - "Invalid offset to optional table `%s'" \ - " set to zero.\n" \ - "\n", #_size )); \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ \ _size = pp[0] = pp[1] = 0; \ } \ @@ -128,10 +128,11 @@ FT_BEGIN_HEADER FT_Byte* pp = (FT_Byte*)_size ## _p; \ \ \ - FT_TRACE3(( "\n" \ - "Invalid offset to optional table `%s'" \ - " set to zero.\n" \ - "\n", #_size )); \ + FT_TRACE3(( "\n" )); \ + FT_TRACE3(( "Invalid offset to optional table `%s'" \ + " set to zero.\n", \ + #_size )); \ + FT_TRACE3(( "\n" )); \ \ _size = pp[0] = pp[1] = pp[2] = pp[3] = 0; \ } \ @@ -179,24 +180,24 @@ FT_BEGIN_HEADER #define OTV_ENTER \ FT_BEGIN_STMNT \ otvalid->debug_indent += 2; \ - FT_TRACE4(( "%*.s", otvalid->debug_indent, 0 )); \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ FT_TRACE4(( "%s table\n", \ otvalid->debug_function_name[otvalid->nesting_level] )); \ FT_END_STMNT -#define OTV_NAME_ENTER( name ) \ - FT_BEGIN_STMNT \ - otvalid->debug_indent += 2; \ - FT_TRACE4(( "%*.s", otvalid->debug_indent, 0 )); \ - FT_TRACE4(( "%s table\n", name )); \ +#define OTV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + otvalid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4(( "%s table\n", name )); \ FT_END_STMNT #define OTV_EXIT otvalid->debug_indent -= 2 -#define OTV_TRACE( s ) \ - FT_BEGIN_STMNT \ - FT_TRACE4(( "%*.s", otvalid->debug_indent, 0 )); \ - FT_TRACE4( s ); \ +#define OTV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", otvalid->debug_indent, "" )); \ + FT_TRACE4( s ); \ FT_END_STMNT #else /* !FT_DEBUG_LEVEL_TRACE */ diff --git a/src/thirdparty/freetype2/src/otvalid/otverror.h b/src/thirdparty/freetype2/src/otvalid/otverror.h index a7d35acf1..17fb5fb84 100644 --- a/src/thirdparty/freetype2/src/otvalid/otverror.h +++ b/src/thirdparty/freetype2/src/otvalid/otverror.h @@ -4,7 +4,7 @@ * * OpenType validation module error codes (specification only). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef OTVERROR_H_ #define OTVERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX OTV_Err_ #define FT_ERR_BASE FT_Mod_Err_OTvalid -#include FT_ERRORS_H +#include #endif /* OTVERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/otvalid/otvgdef.c b/src/thirdparty/freetype2/src/otvalid/otvgdef.c index 2529b544d..cee060148 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvgdef.c +++ b/src/thirdparty/freetype2/src/otvalid/otvgdef.c @@ -4,7 +4,7 @@ * * OpenType GDEF table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -59,7 +59,7 @@ Coverage = table + FT_NEXT_USHORT( p ); GlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); otv_Coverage_validate( Coverage, otvalid, (FT_Int)GlyphCount ); if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) @@ -104,7 +104,7 @@ CaretValueFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); + OTV_TRACE(( " (format = %u)\n", CaretValueFormat )); switch ( CaretValueFormat ) { @@ -156,7 +156,7 @@ OTV_LIMIT_CHECK( 2 ); MarkGlyphSetCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (MarkGlyphSetCount = %d)\n", MarkGlyphSetCount )); + OTV_TRACE(( " (MarkGlyphSetCount = %u)\n", MarkGlyphSetCount )); OTV_LIMIT_CHECK( MarkGlyphSetCount * 4 ); /* CoverageOffsets */ diff --git a/src/thirdparty/freetype2/src/otvalid/otvgpos.c b/src/thirdparty/freetype2/src/otvalid/otvgpos.c index f3bddeac6..e0d860801 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvgpos.c +++ b/src/thirdparty/freetype2/src/otvalid/otvgpos.c @@ -4,7 +4,7 @@ * * OpenType GPOS table validation (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -69,7 +69,7 @@ Count = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (Count = %d)\n", Count )); + OTV_TRACE(( " (Count = %u)\n", Count )); OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 ); @@ -252,7 +252,7 @@ OTV_LIMIT_CHECK( 6 ); AnchorFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", AnchorFormat )); + OTV_TRACE(( " (format %u)\n", AnchorFormat )); p += 4; /* skip XCoordinate and YCoordinate */ @@ -318,7 +318,7 @@ OTV_LIMIT_CHECK( 2 ); MarkCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + OTV_TRACE(( " (MarkCount = %u)\n", MarkCount )); OTV_LIMIT_CHECK( MarkCount * 4 ); @@ -357,7 +357,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); otvalid->extra3 = table; @@ -387,7 +387,7 @@ ValueFormat = FT_NEXT_USHORT( p ); ValueCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + OTV_TRACE(( " (ValueCount = %u)\n", ValueCount )); len_value = otv_value_length( ValueFormat ); @@ -441,7 +441,7 @@ OTV_LIMIT_CHECK( 2 ); PairValueCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + OTV_TRACE(( " (PairValueCount = %u)\n", PairValueCount )); value_len1 = otv_value_length( format1 ); value_len2 = otv_value_length( format2 ); @@ -481,7 +481,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -496,7 +496,7 @@ ValueFormat2 = FT_NEXT_USHORT( p ); PairSetCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + OTV_TRACE(( " (PairSetCount = %u)\n", PairSetCount )); otv_Coverage_validate( table + Coverage, otvalid, -1 ); @@ -524,8 +524,8 @@ ClassCount1 = FT_NEXT_USHORT( p ); ClassCount2 = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); - OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + OTV_TRACE(( " (ClassCount1 = %u)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %u)\n", ClassCount2 )); len_value1 = otv_value_length( ValueFormat1 ); len_value2 = otv_value_length( ValueFormat2 ); @@ -588,7 +588,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -605,7 +605,7 @@ Coverage = FT_NEXT_USHORT( p ); EntryExitCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + OTV_TRACE(( " (EntryExitCount = %u)\n", EntryExitCount )); otv_Coverage_validate( table + Coverage, otvalid, @@ -666,7 +666,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -707,7 +707,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -748,7 +748,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -789,7 +789,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -848,7 +848,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { @@ -909,7 +909,7 @@ OTV_LIMIT_CHECK( 2 ); PosFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", PosFormat )); + OTV_TRACE(( " (format %u)\n", PosFormat )); switch ( PosFormat ) { diff --git a/src/thirdparty/freetype2/src/otvalid/otvgpos.h b/src/thirdparty/freetype2/src/otvalid/otvgpos.h index b3154312e..2fc1309e1 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvgpos.h +++ b/src/thirdparty/freetype2/src/otvalid/otvgpos.h @@ -4,7 +4,7 @@ * * OpenType GPOS table validator (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/otvalid/otvgsub.c b/src/thirdparty/freetype2/src/otvalid/otvgsub.c index 97da997d3..0df97d8db 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvgsub.c +++ b/src/thirdparty/freetype2/src/otvalid/otvgsub.c @@ -4,7 +4,7 @@ * * OpenType GSUB table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -53,7 +53,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -61,7 +61,8 @@ { FT_Bytes Coverage; FT_Int DeltaGlyphID; - FT_Long idx; + FT_UInt first_cov, last_cov; + FT_UInt first_idx, last_idx; OTV_LIMIT_CHECK( 4 ); @@ -70,12 +71,21 @@ otv_Coverage_validate( Coverage, otvalid, -1 ); - idx = (FT_Long)otv_Coverage_get_first( Coverage ) + DeltaGlyphID; - if ( idx < 0 ) + first_cov = otv_Coverage_get_first( Coverage ); + last_cov = otv_Coverage_get_last( Coverage ); + + /* These additions are modulo 65536. */ + first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU; + last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU; + + /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */ + /* the largest possible glyph index is 65534. For this */ + /* reason there can't be a wrap-around region, which would */ + /* imply the use of the invalid glyph index 65535. */ + if ( first_idx > last_idx ) FT_INVALID_DATA; - idx = (FT_Long)otv_Coverage_get_last( Coverage ) + DeltaGlyphID; - if ( (FT_UInt)idx >= otvalid->glyph_count ) + if ( last_idx >= otvalid->glyph_count ) FT_INVALID_DATA; } break; @@ -89,7 +99,7 @@ Coverage = FT_NEXT_USHORT( p ); GlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); otv_Coverage_validate( table + Coverage, otvalid, @@ -135,7 +145,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -176,7 +186,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -223,7 +233,7 @@ CompCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (CompCount = %d)\n", CompCount )); + OTV_TRACE(( " (CompCount = %u)\n", CompCount )); if ( CompCount == 0 ) FT_INVALID_DATA; @@ -251,7 +261,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -291,7 +301,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -350,7 +360,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -411,7 +421,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -468,7 +478,7 @@ OTV_LIMIT_CHECK( 2 ); SubstFormat = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (format %d)\n", SubstFormat )); + OTV_TRACE(( " (format %u)\n", SubstFormat )); switch ( SubstFormat ) { @@ -477,7 +487,7 @@ Coverage = table + FT_NEXT_USHORT( p ); BacktrackGlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + OTV_TRACE(( " (BacktrackGlyphCount = %u)\n", BacktrackGlyphCount )); otv_Coverage_validate( Coverage, otvalid, -1 ); @@ -488,7 +498,7 @@ LookaheadGlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + OTV_TRACE(( " (LookaheadGlyphCount = %u)\n", LookaheadGlyphCount )); OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); @@ -497,7 +507,7 @@ GlyphCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (GlyphCount = %u)\n", GlyphCount )); if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) FT_INVALID_DATA; diff --git a/src/thirdparty/freetype2/src/otvalid/otvjstf.c b/src/thirdparty/freetype2/src/otvalid/otvjstf.c index d4e6d8717..8909612d9 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvjstf.c +++ b/src/thirdparty/freetype2/src/otvalid/otvjstf.c @@ -4,7 +4,7 @@ * * OpenType JSTF table validation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -163,7 +163,7 @@ OTV_OPTIONAL_OFFSET( DefJstfLangSys ); JstfLangSysCount = FT_NEXT_USHORT( p ); - OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); + OTV_TRACE(( " (JstfLangSysCount = %u)\n", JstfLangSysCount )); table_size = JstfLangSysCount * 6 + 6; @@ -227,7 +227,7 @@ JstfScriptCount = FT_NEXT_USHORT( p ); - FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); + FT_TRACE3(( " (JstfScriptCount = %u)\n", JstfScriptCount )); OTV_LIMIT_CHECK( JstfScriptCount * 6 ); diff --git a/src/thirdparty/freetype2/src/otvalid/otvmath.c b/src/thirdparty/freetype2/src/otvalid/otvmath.c index 3aaf0ec0e..78e6c6692 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvmath.c +++ b/src/thirdparty/freetype2/src/otvalid/otvmath.c @@ -4,7 +4,7 @@ * * OpenType MATH table validation (body). * - * Copyright (C) 2007-2019 by + * Copyright (C) 2007-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by George Williams. @@ -141,7 +141,7 @@ OTV_OPTIONAL_TABLE( DeviceTableOffset ); - /* OTV_NAME_ENTER( "MathKern" );*/ + /* OTV_NAME_ENTER( "MathKern" ); */ OTV_LIMIT_CHECK( 2 ); diff --git a/src/thirdparty/freetype2/src/otvalid/otvmod.c b/src/thirdparty/freetype2/src/otvalid/otvmod.c index f417bd220..d2456cb58 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvmod.c +++ b/src/thirdparty/freetype2/src/otvalid/otvmod.c @@ -4,7 +4,7 @@ * * FreeType's OpenType validation module implementation (body). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#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 +#include +#include +#include +#include #include "otvmod.h" #include "otvalid.h" @@ -54,7 +53,7 @@ if ( error ) goto Exit; - if ( FT_ALLOC( *table, *table_len ) ) + if ( FT_QALLOC( *table, *table_len ) ) goto Exit; error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); @@ -95,7 +94,7 @@ */ if ( face->num_glyphs > 0xFFFFL ) { - FT_TRACE1(( "otv_validate: Invalid glyphs index (0x0000FFFF - 0x%08x) ", + FT_TRACE1(( "otv_validate: Invalid glyphs index (0x0000FFFF - 0x%08lx) ", face->num_glyphs )); FT_TRACE1(( "are not handled by OpenType tables\n" )); num_glyphs = 0xFFFF; diff --git a/src/thirdparty/freetype2/src/otvalid/otvmod.h b/src/thirdparty/freetype2/src/otvalid/otvmod.h index 5539de7ec..aec6f6657 100644 --- a/src/thirdparty/freetype2/src/otvalid/otvmod.h +++ b/src/thirdparty/freetype2/src/otvalid/otvmod.h @@ -5,7 +5,7 @@ * FreeType's OpenType validation module implementation * (specification). * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,8 +21,7 @@ #define OTVMOD_H_ -#include -#include FT_MODULE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pcf/pcf.h b/src/thirdparty/freetype2/src/pcf/pcf.h index 33be4bcd8..3134cc355 100644 --- a/src/thirdparty/freetype2/src/pcf/pcf.h +++ b/src/thirdparty/freetype2/src/pcf/pcf.h @@ -29,9 +29,8 @@ THE SOFTWARE. #define PCF_H_ -#include -#include FT_INTERNAL_DRIVER_H -#include FT_INTERNAL_STREAM_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pcf/pcfdrivr.c b/src/thirdparty/freetype2/src/pcf/pcfdrivr.c index b39592c79..ecd684951 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfdrivr.c +++ b/src/thirdparty/freetype2/src/pcf/pcfdrivr.c @@ -25,17 +25,16 @@ THE SOFTWARE. */ -#include -#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_BZIP2_H -#include FT_ERRORS_H -#include FT_BDF_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "pcf.h" #include "pcfdrivr.h" @@ -47,10 +46,10 @@ THE SOFTWARE. #undef FT_COMPONENT #define FT_COMPONENT pcfread -#include FT_SERVICE_BDF_H -#include FT_SERVICE_FONT_FORMAT_H -#include FT_SERVICE_PROPERTIES_H -#include FT_DRIVER_H +#include +#include +#include +#include /************************************************************************** @@ -76,98 +75,82 @@ THE SOFTWARE. FT_CALLBACK_DEF( FT_Error ) - pcf_cmap_init( FT_CMap pcfcmap, /* PCF_CMap */ + pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */ FT_Pointer init_data ) { - PCF_CMap cmap = (PCF_CMap)pcfcmap; - PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap ); + PCF_CMap pcfcmap = (PCF_CMap)cmap; + PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap ); FT_UNUSED( init_data ); - cmap->enc = &face->enc; + pcfcmap->enc = &face->enc; return FT_Err_Ok; } FT_CALLBACK_DEF( void ) - pcf_cmap_done( FT_CMap pcfcmap ) /* PCF_CMap */ + pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */ { - PCF_CMap cmap = (PCF_CMap)pcfcmap; + PCF_CMap pcfcmap = (PCF_CMap)cmap; - cmap->enc = NULL; + pcfcmap->enc = NULL; } FT_CALLBACK_DEF( FT_UInt ) - pcf_cmap_char_index( FT_CMap pcfcmap, /* PCF_CMap */ + pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */ FT_UInt32 charcode ) { - PCF_CMap cmap = (PCF_CMap)pcfcmap; - PCF_Enc enc = cmap->enc; - FT_UShort charcodeRow; - FT_UShort charcodeCol; + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; - if ( charcode > (FT_UInt32)( enc->lastRow * 256 + enc->lastCol ) || - charcode < (FT_UInt32)( enc->firstRow * 256 + enc->firstCol ) ) + /* wrapped around "negative" values are also rejected */ + if ( i >= h || j >= w ) return 0; - charcodeRow = (FT_UShort)( charcode >> 8 ); - charcodeCol = (FT_UShort)( charcode & 0xFF ); - - if ( charcodeCol < enc->firstCol || - charcodeCol > enc->lastCol ) - return 0; - - return (FT_UInt)enc->offset[( charcodeRow - enc->firstRow ) * - ( enc->lastCol - enc->firstCol + 1 ) + - charcodeCol - enc->firstCol]; + return (FT_UInt)enc->offset[i * w + j]; } FT_CALLBACK_DEF( FT_UInt ) - pcf_cmap_char_next( FT_CMap pcfcmap, /* PCF_CMap */ + pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */ FT_UInt32 *acharcode ) { - PCF_CMap cmap = (PCF_CMap)pcfcmap; - PCF_Enc enc = cmap->enc; - FT_UInt32 charcode = *acharcode; - FT_UShort charcodeRow; - FT_UShort charcodeCol; - FT_Int result = 0; + PCF_Enc enc = ( (PCF_CMap)cmap )->enc; + FT_UInt32 charcode = *acharcode + 1; + + FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow; + FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol; + FT_UInt32 h = enc->lastRow - enc->firstRow + 1; + FT_UInt32 w = enc->lastCol - enc->firstCol + 1; + + FT_UInt result = 0; - while ( charcode < (FT_UInt32)( enc->lastRow * 256 + enc->lastCol ) ) - { - charcode++; + /* adjust wrapped around "negative" values */ + if ( (FT_Int32)i < 0 ) + i = 0; + if ( (FT_Int32)j < 0 ) + j = 0; - if ( charcode < (FT_UInt32)( enc->firstRow * 256 + enc->firstCol ) ) - charcode = (FT_UInt32)( enc->firstRow * 256 + enc->firstCol ); - - charcodeRow = (FT_UShort)( charcode >> 8 ); - charcodeCol = (FT_UShort)( charcode & 0xFF ); - - if ( charcodeCol < enc->firstCol ) - charcodeCol = enc->firstCol; - else if ( charcodeCol > enc->lastCol ) + for ( ; i < h; i++, j = 0 ) + for ( ; j < w; j++ ) { - charcodeRow++; - charcodeCol = enc->firstCol; + result = (FT_UInt)enc->offset[i * w + j]; + if ( result != 0xFFFFU ) + goto Exit; } - charcode = (FT_UInt32)( charcodeRow * 256 + charcodeCol ); - - result = (FT_UInt)enc->offset[( charcodeRow - enc->firstRow ) * - ( enc->lastCol - enc->firstCol + 1 ) + - charcodeCol - enc->firstCol]; - if ( result != 0xFFFFU ) - break; - } - - *acharcode = charcode; + Exit: + *acharcode = ( ( i + enc->firstRow ) << 8 ) | ( j + enc->firstCol ); return result; } @@ -187,9 +170,9 @@ THE SOFTWARE. FT_CALLBACK_DEF( void ) - PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */ + PCF_Face_Done( FT_Face face ) /* PCF_Face */ { - PCF_Face face = (PCF_Face)pcfface; + PCF_Face pcfface = (PCF_Face)face; FT_Memory memory; @@ -198,18 +181,18 @@ THE SOFTWARE. memory = FT_FACE_MEMORY( face ); - FT_FREE( face->metrics ); - FT_FREE( face->enc.offset ); + FT_FREE( pcfface->metrics ); + FT_FREE( pcfface->enc.offset ); /* free properties */ - if ( face->properties ) + if ( pcfface->properties ) { FT_Int i; - for ( i = 0; i < face->nprops; i++ ) + for ( i = 0; i < pcfface->nprops; i++ ) { - PCF_Property prop = &face->properties[i]; + PCF_Property prop = &pcfface->properties[i]; if ( prop ) @@ -220,33 +203,33 @@ THE SOFTWARE. } } - FT_FREE( face->properties ); + FT_FREE( pcfface->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_FREE( pcfface->toc.tables ); + FT_FREE( face->family_name ); + FT_FREE( face->style_name ); + FT_FREE( face->available_sizes ); + FT_FREE( pcfface->charset_encoding ); + FT_FREE( pcfface->charset_registry ); /* close compressed stream if any */ - if ( pcfface->stream == &face->comp_stream ) + if ( face->stream == &pcfface->comp_stream ) { - FT_Stream_Close( &face->comp_stream ); - pcfface->stream = face->comp_source; + FT_Stream_Close( &pcfface->comp_stream ); + face->stream = pcfface->comp_source; } } FT_CALLBACK_DEF( FT_Error ) PCF_Face_Init( FT_Stream stream, - FT_Face pcfface, /* PCF_Face */ + FT_Face face, /* PCF_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { - PCF_Face face = (PCF_Face)pcfface; + PCF_Face pcfface = (PCF_Face)face; FT_Error error; FT_UNUSED( num_params ); @@ -255,10 +238,10 @@ THE SOFTWARE. FT_TRACE2(( "PCF driver\n" )); - error = pcf_load_font( stream, face, face_index ); + error = pcf_load_font( stream, pcfface, face_index ); if ( error ) { - PCF_Face_Done( pcfface ); + PCF_Face_Done( face ); #if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ defined( FT_CONFIG_OPTION_USE_LZW ) || \ @@ -271,7 +254,7 @@ THE SOFTWARE. /* this didn't work, try gzip support! */ FT_TRACE2(( " ... try gzip stream\n" )); - error2 = FT_Stream_OpenGzip( &face->comp_stream, stream ); + error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream ); if ( FT_ERR_EQ( error2, Unimplemented_Feature ) ) goto Fail; @@ -287,7 +270,7 @@ THE SOFTWARE. /* this didn't work, try LZW support! */ FT_TRACE2(( " ... try LZW stream\n" )); - error3 = FT_Stream_OpenLZW( &face->comp_stream, stream ); + error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream ); if ( FT_ERR_EQ( error3, Unimplemented_Feature ) ) goto Fail; @@ -303,7 +286,7 @@ THE SOFTWARE. /* this didn't work, try Bzip2 support! */ FT_TRACE2(( " ... try Bzip2 stream\n" )); - error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream ); + error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream ); if ( FT_ERR_EQ( error4, Unimplemented_Feature ) ) goto Fail; @@ -314,12 +297,12 @@ THE SOFTWARE. if ( error ) goto Fail; - face->comp_source = stream; - pcfface->stream = &face->comp_stream; + pcfface->comp_source = stream; + face->stream = &pcfface->comp_stream; - stream = pcfface->stream; + stream = face->stream; - error = pcf_load_font( stream, face, face_index ); + error = pcf_load_font( stream, pcfface, face_index ); if ( error ) goto Fail; @@ -343,14 +326,14 @@ THE SOFTWARE. else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) { FT_ERROR(( "PCF_Face_Init: invalid face index\n" )); - PCF_Face_Done( pcfface ); + PCF_Face_Done( face ); return FT_THROW( Invalid_Argument ); } /* set up charmap */ { - FT_String *charset_registry = face->charset_registry; - FT_String *charset_encoding = face->charset_encoding; + FT_String *charset_registry = pcfface->charset_registry; + FT_String *charset_encoding = pcfface->charset_encoding; FT_Bool unicode_charmap = 0; @@ -366,13 +349,13 @@ THE SOFTWARE. ( s[2] == 'o' || s[2] == 'O' ) ) { s += 3; - if ( !ft_strcmp( s, "10646" ) || - ( !ft_strcmp( s, "8859" ) && - !ft_strcmp( face->charset_encoding, "1" ) ) ) + if ( !ft_strcmp( s, "10646" ) || + ( !ft_strcmp( s, "8859" ) && + !ft_strcmp( pcfface->charset_encoding, "1" ) ) ) unicode_charmap = 1; /* another name for ASCII */ - else if ( !ft_strcmp( s, "646.1991" ) && - !ft_strcmp( face->charset_encoding, "IRV" ) ) + else if ( !ft_strcmp( s, "646.1991" ) && + !ft_strcmp( pcfface->charset_encoding, "IRV" ) ) unicode_charmap = 1; } } @@ -381,7 +364,7 @@ THE SOFTWARE. FT_CharMapRec charmap; - charmap.face = FT_FACE( face ); + charmap.face = face; charmap.encoding = FT_ENCODING_NONE; /* initial platform/encoding should indicate unset status? */ charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; @@ -403,7 +386,7 @@ THE SOFTWARE. Fail: FT_TRACE2(( " not a PCF file\n" )); - PCF_Face_Done( pcfface ); + PCF_Face_Done( face ); error = FT_THROW( Unknown_File_Format ); /* error */ goto Exit; } @@ -470,7 +453,7 @@ THE SOFTWARE. FT_UInt glyph_index, FT_Int32 load_flags ) { - PCF_Face face = (PCF_Face)FT_SIZE_FACE( size ); + PCF_Face face = (PCF_Face)size->face; FT_Stream stream; FT_Error error = FT_Err_Ok; FT_Bitmap* bitmap = &slot->bitmap; @@ -478,7 +461,7 @@ THE SOFTWARE. FT_ULong bytes; - FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index )); + FT_TRACE1(( "PCF_Glyph_Load: glyph index %u\n", glyph_index )); if ( !face ) { @@ -586,15 +569,16 @@ THE SOFTWARE. * */ - static FT_Error - pcf_get_bdf_property( PCF_Face face, + FT_CALLBACK_DEF( FT_Error ) + pcf_get_bdf_property( FT_Face face, /* PCF_Face */ const char* prop_name, BDF_PropertyRec *aproperty ) { + PCF_Face pcfface = (PCF_Face)face; PCF_Property prop; - prop = pcf_find_property( face, prop_name ); + prop = pcf_find_property( pcfface, prop_name ); if ( prop ) { if ( prop->isString ) @@ -607,8 +591,9 @@ THE SOFTWARE. if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) { - FT_TRACE1(( "pcf_get_bdf_property:" )); - FT_TRACE1(( " too large integer 0x%x is truncated\n" )); + FT_TRACE2(( "pcf_get_bdf_property:" + " too large integer 0x%lx is truncated\n", + prop->value.l )); } /* @@ -627,13 +612,16 @@ THE SOFTWARE. } - static FT_Error - pcf_get_charset_id( PCF_Face face, + FT_CALLBACK_DEF( FT_Error ) + pcf_get_charset_id( FT_Face face, /* PCF_Face */ const char* *acharset_encoding, const char* *acharset_registry ) { - *acharset_encoding = face->charset_encoding; - *acharset_registry = face->charset_registry; + PCF_Face pcfface = (PCF_Face)face; + + + *acharset_encoding = pcfface->charset_encoding; + *acharset_registry = pcfface->charset_registry; return FT_Err_Ok; } @@ -650,7 +638,7 @@ THE SOFTWARE. * PROPERTY SERVICE * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) pcf_property_set( FT_Module module, /* PCF_Driver */ const char* property_name, const void* value, @@ -705,16 +693,16 @@ THE SOFTWARE. #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ - FT_TRACE0(( "pcf_property_set: missing property `%s'\n", + FT_TRACE2(( "pcf_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } - static FT_Error + FT_CALLBACK_DEF( FT_Error ) pcf_property_get( FT_Module module, /* PCF_Driver */ const char* property_name, - const void* value ) + void* value ) { #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES @@ -743,7 +731,7 @@ THE SOFTWARE. #endif /* !PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ - FT_TRACE0(( "pcf_property_get: missing property `%s'\n", + FT_TRACE2(( "pcf_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } diff --git a/src/thirdparty/freetype2/src/pcf/pcfdrivr.h b/src/thirdparty/freetype2/src/pcf/pcfdrivr.h index 73db0823d..d46539374 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfdrivr.h +++ b/src/thirdparty/freetype2/src/pcf/pcfdrivr.h @@ -28,8 +28,7 @@ THE SOFTWARE. #ifndef PCFDRIVR_H_ #define PCFDRIVR_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pcf/pcferror.h b/src/thirdparty/freetype2/src/pcf/pcferror.h index 2e69d1d21..8b9e9902a 100644 --- a/src/thirdparty/freetype2/src/pcf/pcferror.h +++ b/src/thirdparty/freetype2/src/pcf/pcferror.h @@ -25,7 +25,7 @@ #ifndef PCFERROR_H_ #define PCFERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX PCF_Err_ #define FT_ERR_BASE FT_Mod_Err_PCF -#include FT_ERRORS_H +#include #endif /* PCFERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/pcf/pcfread.c b/src/thirdparty/freetype2/src/pcf/pcfread.c index 2ffe22d71..9c250c846 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfread.c +++ b/src/thirdparty/freetype2/src/pcf/pcfread.c @@ -25,11 +25,10 @@ THE SOFTWARE. */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_OBJECTS_H +#include +#include +#include #include "pcf.h" #include "pcfread.h" @@ -122,13 +121,13 @@ THE SOFTWARE. toc->count > 9 ) { FT_TRACE0(( "pcf_read_TOC: adjusting number of tables" - " (from %d to %d)\n", + " (from %lu to %lu)\n", toc->count, FT_MIN( stream->size >> 4, 9 ) )); toc->count = FT_MIN( stream->size >> 4, 9 ); } - if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) + if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) ) return error; tables = face->toc.tables; @@ -232,18 +231,18 @@ THE SOFTWARE. FT_TRACE4(( "pcf_read_TOC:\n" )); - FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); + FT_TRACE4(( " number of tables: %lu\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 ) ) + if ( tables[i].type == 1UL << j ) name = tableNames[j]; - FT_TRACE4(( " %d: type=%s, format=0x%X," - " size=%ld (0x%lX), offset=%ld (0x%lX)\n", + FT_TRACE4(( " %u: type=%s, format=0x%lX," + " size=%lu (0x%lX), offset=%lu (0x%lX)\n", i, name, tables[i].format, tables[i].size, tables[i].size, @@ -502,8 +501,8 @@ THE SOFTWARE. if ( FT_READ_ULONG_LE( format ) ) goto Bail; - FT_TRACE4(( "pcf_get_properties:\n" - " format: 0x%lX (%s)\n", + FT_TRACE4(( "pcf_get_properties:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", format, PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); @@ -517,7 +516,7 @@ THE SOFTWARE. if ( error ) goto Bail; - FT_TRACE4(( " number of properties: %ld\n", orig_nprops )); + FT_TRACE4(( " number of properties: %lu\n", orig_nprops )); /* rough estimate */ if ( orig_nprops > size / PCF_PROPERTY_SIZE ) @@ -541,7 +540,7 @@ THE SOFTWARE. face->nprops = (int)nprops; - if ( FT_NEW_ARRAY( props, nprops ) ) + if ( FT_QNEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) @@ -589,7 +588,7 @@ THE SOFTWARE. if ( error ) goto Bail; - FT_TRACE4(( " string size: %ld\n", string_size )); + FT_TRACE4(( " string size: %lu\n", string_size )); /* rough estimate */ if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE ) @@ -608,13 +607,13 @@ THE SOFTWARE. } /* allocate one more byte so that we have a final null byte */ - if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) + if ( FT_QALLOC( strings, string_size + 1 ) || + FT_STREAM_READ( strings, string_size ) ) goto Bail; - error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); - if ( error ) - goto Bail; + strings[string_size] = '\0'; + /* zero out in case of failure */ if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; @@ -661,7 +660,7 @@ THE SOFTWARE. { properties[i].value.l = props[i].value; - FT_TRACE4(( " %d\n", properties[i].value.l )); + FT_TRACE4(( " %ld\n", properties[i].value.l )); } } @@ -698,8 +697,8 @@ THE SOFTWARE. if ( FT_READ_ULONG_LE( format ) ) goto Bail; - FT_TRACE4(( "pcf_get_metrics:\n" - " format: 0x%lX (%s, %s)\n", + FT_TRACE4(( "pcf_get_metrics:\n" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", format, PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ? @@ -726,7 +725,7 @@ THE SOFTWARE. if ( error ) return FT_THROW( Invalid_File_Format ); - FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics )); + FT_TRACE4(( " number of metrics: %lu\n", orig_nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) @@ -768,7 +767,7 @@ THE SOFTWARE. face->nmetrics = nmetrics + 1; - if ( FT_NEW_ARRAY( face->metrics, face->nmetrics ) ) + if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) ) return error; /* we handle glyph index 0 later on */ @@ -777,7 +776,7 @@ THE SOFTWARE. FT_TRACE4(( "\n" )); for ( i = 1; i < face->nmetrics; i++, metrics++ ) { - FT_TRACE5(( " idx %ld:", i )); + FT_TRACE5(( " idx %lu:", i )); error = pcf_get_metric( stream, format, metrics ); metrics->bits = 0; @@ -798,7 +797,7 @@ THE SOFTWARE. metrics->descent = 0; FT_TRACE0(( "pcf_get_metrics:" - " invalid metrics for glyph %d\n", i )); + " invalid metrics for glyph %lu\n", i )); } } @@ -841,17 +840,16 @@ THE SOFTWARE. FT_Stream_ExitFrame( stream ); - FT_TRACE4(( "pcf_get_bitmaps:\n" - " format: 0x%lX\n" - " (%s, %s,\n" - " padding=%d bit%s, scanning=%d bit%s)\n", - format, + FT_TRACE4(( "pcf_get_bitmaps:\n" )); + FT_TRACE4(( " format: 0x%lX\n", format )); + FT_TRACE4(( " (%s, %s,\n", PCF_BYTE_ORDER( format ) == MSBFirst ? "most significant byte first" : "least significant byte first", PCF_BIT_ORDER( format ) == MSBFirst ? "most significant bit first" - : "least significant bit first", + : "least significant bit first" )); + FT_TRACE4(( " padding=%d bit%s, scanning=%d bit%s)\n", 8 << PCF_GLYPH_PAD_INDEX( format ), ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s", 8 << PCF_SCAN_UNIT_INDEX( format ), @@ -860,7 +858,7 @@ THE SOFTWARE. if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return FT_THROW( Invalid_File_Format ); - FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps )); + FT_TRACE4(( " number of bitmaps: %lu\n", orig_nbitmaps )); /* see comment in `pcf_get_metrics' */ if ( orig_nbitmaps > 65534 ) @@ -918,11 +916,11 @@ THE SOFTWARE. sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; - FT_TRACE4(( " %ld-bit padding implies a size of %lu\n", + FT_TRACE4(( " %d-bit padding implies a size of %lu\n", 8 << i, bitmapSizes[i] )); } - FT_TRACE4(( " %lu bitmaps, using %ld-bit padding\n", + FT_TRACE4(( " %lu bitmaps, using %d-bit padding\n", nbitmaps, 8 << PCF_GLYPH_PAD_INDEX( format ) )); FT_TRACE4(( " bitmap size: %lu\n", sizebitmaps )); @@ -1002,8 +1000,8 @@ THE SOFTWARE. if ( FT_READ_ULONG_LE( format ) ) goto Bail; - FT_TRACE4(( "pcf_get_encodings:\n" - " format: 0x%lX (%s)\n", + FT_TRACE4(( "pcf_get_encodings:\n" )); + FT_TRACE4(( " format: 0x%lX (%s)\n", format, PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); @@ -1022,11 +1020,11 @@ THE SOFTWARE. goto Bail; } - FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n" - " firstRow 0x%X, lastRow 0x%X\n" - " defaultChar 0x%X\n", - enc->firstCol, enc->lastCol, - enc->firstRow, enc->lastRow, + FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n", + enc->firstCol, enc->lastCol )); + FT_TRACE4(( " firstRow 0x%X, lastRow 0x%X\n", + enc->firstRow, enc->lastRow )); + FT_TRACE4(( " defaultChar 0x%X\n", enc->defaultChar )); /* sanity checks; we limit numbers of rows and columns to 256 */ @@ -1036,16 +1034,6 @@ THE SOFTWARE. enc->lastRow > 0xFF ) return FT_THROW( Invalid_Table ); - nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) * - (FT_ULong)( enc->lastRow - enc->firstRow + 1 ); - - if ( FT_NEW_ARRAY( enc->offset, nencoding ) ) - goto Bail; - - error = FT_Stream_EnterFrame( stream, 2 * nencoding ); - if ( error ) - goto Exit; - FT_TRACE5(( "\n" )); defaultCharRow = enc->defaultChar >> 8; @@ -1066,6 +1054,13 @@ THE SOFTWARE. defaultCharCol = enc->firstCol; } + nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) * + (FT_ULong)( enc->lastRow - enc->firstRow + 1 ); + + error = FT_Stream_EnterFrame( stream, 2 * nencoding ); + if ( error ) + goto Bail; + /* * FreeType mandates that glyph index 0 is the `undefined glyph', which * PCF calls the `default character'. However, FreeType needs glyph @@ -1089,8 +1084,8 @@ THE SOFTWARE. if ( defaultCharEncodingOffset == 0xFFFF ) { FT_TRACE0(( "pcf_get_encodings:" - " No glyph for default character,\n" - " " + " No glyph for default character,\n" )); + FT_TRACE0(( " " " setting it to the first glyph of the font\n" )); defaultCharEncodingOffset = 1; } @@ -1101,8 +1096,8 @@ THE SOFTWARE. if ( defaultCharEncodingOffset >= face->nmetrics ) { FT_TRACE0(( "pcf_get_encodings:" - " Invalid glyph index for default character,\n" - " " + " Invalid glyph index for default character,\n" )); + FT_TRACE0(( " " " setting it to the first glyph of the font\n" )); defaultCharEncodingOffset = 1; } @@ -1111,6 +1106,9 @@ THE SOFTWARE. /* copy metrics of default character to index 0 */ face->metrics[0] = face->metrics[defaultCharEncodingOffset]; + if ( FT_QNEW_ARRAY( enc->offset, nencoding ) ) + goto Bail; + /* now loop over all values */ offset = enc->offset; for ( i = enc->firstRow; i <= enc->lastRow; i++ ) @@ -1133,11 +1131,6 @@ THE SOFTWARE. } FT_Stream_ExitFrame( stream ); - return error; - - Exit: - FT_FREE( enc->offset ); - Bail: return error; } @@ -1209,10 +1202,10 @@ THE SOFTWARE. if ( FT_READ_ULONG_LE( format ) ) goto Bail; - FT_TRACE4(( "pcf_get_accel%s:\n" - " format: 0x%lX (%s, %s)\n", + FT_TRACE4(( "pcf_get_accel%s:\n", type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)" - : "", + : "" )); + FT_TRACE4(( " format: 0x%lX (%s, %s)\n", format, PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ? @@ -1234,16 +1227,16 @@ THE SOFTWARE. } FT_TRACE5(( " noOverlap=%s, constantMetrics=%s," - " terminalFont=%s, constantWidth=%s\n" - " inkInside=%s, inkMetrics=%s, drawDirection=%s\n" - " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", + " terminalFont=%s, constantWidth=%s\n", accel->noOverlap ? "yes" : "no", accel->constantMetrics ? "yes" : "no", accel->terminalFont ? "yes" : "no", - accel->constantWidth ? "yes" : "no", + accel->constantWidth ? "yes" : "no" )); + FT_TRACE5(( " inkInside=%s, inkMetrics=%s, drawDirection=%s\n", accel->inkInside ? "yes" : "no", accel->inkMetrics ? "yes" : "no", - accel->drawDirection ? "RTL" : "LTR", + accel->drawDirection ? "RTL" : "LTR" )); + FT_TRACE5(( " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", accel->fontAscent, accel->fontDescent, accel->maxOverlap )); @@ -1252,13 +1245,13 @@ THE SOFTWARE. if ( FT_ABS( accel->fontAscent ) > 0x7FFF ) { accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF; - FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %d\n", + FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n", accel->fontAscent )); } if ( FT_ABS( accel->fontDescent ) > 0x7FFF ) { accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF; - FT_TRACE0(( "pfc_get_accel: clamping font descent to value %d\n", + FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n", accel->fontDescent )); } @@ -1370,7 +1363,7 @@ THE SOFTWARE. char* s; - if ( FT_ALLOC( face->style_name, len ) ) + if ( FT_QALLOC( face->style_name, len ) ) return error; s = face->style_name; @@ -1534,7 +1527,7 @@ THE SOFTWARE. { l += ft_strlen( foundry_prop->value.atom ) + 1; - if ( FT_NEW_ARRAY( root->family_name, l ) ) + if ( FT_QALLOC( root->family_name, l ) ) goto Exit; ft_strcpy( root->family_name, foundry_prop->value.atom ); @@ -1543,7 +1536,7 @@ THE SOFTWARE. } else { - if ( FT_NEW_ARRAY( root->family_name, l ) ) + if ( FT_QALLOC( root->family_name, l ) ) goto Exit; ft_strcpy( root->family_name, prop->value.atom ); @@ -1567,7 +1560,7 @@ THE SOFTWARE. root->num_glyphs = (FT_Long)face->nmetrics; root->num_fixed_sizes = 1; - if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + if ( FT_NEW( root->available_sizes ) ) goto Exit; { @@ -1575,8 +1568,6 @@ THE SOFTWARE. FT_Short resolution_x = 0, resolution_y = 0; - FT_ZERO( bsize ); - /* for simplicity, we take absolute values of integer properties */ #if 0 @@ -1617,7 +1608,7 @@ THE SOFTWARE. else { /* this is a heuristical value */ - bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); + bsize->width = ( bsize->height * 2 + 1 ) / 3; } prop = pcf_find_property( face, "POINT_SIZE" ); @@ -1631,7 +1622,7 @@ THE SOFTWARE. if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */ { bsize->size = 0x7FFF; - FT_TRACE0(( "pcf_load_font: clamping point size to value %d\n", + FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n", bsize->size )); } else @@ -1650,7 +1641,7 @@ THE SOFTWARE. if ( FT_ABS( prop->value.l ) > 0x7FFF ) { bsize->y_ppem = 0x7FFF << 6; - FT_TRACE0(( "pcf_load_font: clamping pixel size to value %d\n", + FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n", bsize->y_ppem )); } else diff --git a/src/thirdparty/freetype2/src/pcf/pcfread.h b/src/thirdparty/freetype2/src/pcf/pcfread.h index bed30e503..a54648fbf 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfread.h +++ b/src/thirdparty/freetype2/src/pcf/pcfread.h @@ -29,7 +29,6 @@ THE SOFTWARE. #define PCFREAD_H_ -#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pcf/pcfutil.c b/src/thirdparty/freetype2/src/pcf/pcfutil.c index 045c42d60..cd26c77ca 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfutil.c +++ b/src/thirdparty/freetype2/src/pcf/pcfutil.c @@ -32,7 +32,6 @@ in this Software without prior written authorization from The Open Group. /* Modified for use with FreeType */ -#include #include "pcfutil.h" @@ -58,6 +57,34 @@ in this Software without prior written authorization from The Open Group. } +#if ( defined( __clang_major__ ) && __clang_major__ >= 5 ) || \ + ( defined( __GNUC__ ) && \ + ( __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 ) ) ) + +#define BSWAP16( x ) __builtin_bswap16( x ) +#define BSWAP32( x ) __builtin_bswap32( x ) + +#elif defined( _MSC_VER ) && _MSC_VER >= 1300 + +#pragma intrinsic( _byteswap_ushort ) +#pragma intrinsic( _byteswap_ulong ) + +#define BSWAP16( x ) _byteswap_ushort( x ) +#define BSWAP32( x ) _byteswap_ulong( x ) + +#else + +#define BSWAP16( x ) \ + (FT_UInt16)( ( ( ( x ) >> 8 ) & 0xff ) | \ + ( ( ( x ) & 0xff ) << 8 ) ) +#define BSWAP32( x ) \ + (FT_UInt32)( ( ( ( x ) & 0xff000000u ) >> 24 ) | \ + ( ( ( x ) & 0x00ff0000u ) >> 8 ) | \ + ( ( ( x ) & 0x0000ff00u ) << 8 ) | \ + ( ( ( x ) & 0x000000ffu ) << 24 ) ) + +#endif + /* * Invert byte order within each 16-bits of an array. */ @@ -66,15 +93,11 @@ in this Software without prior written authorization from The Open Group. TwoByteSwap( unsigned char* buf, size_t nbytes ) { - for ( ; nbytes >= 2; nbytes -= 2, buf += 2 ) - { - unsigned char c; + FT_UInt16* b = (FT_UInt16*)buf; - c = buf[0]; - buf[0] = buf[1]; - buf[1] = c; - } + for ( ; nbytes >= 2; nbytes -= 2, b++ ) + *b = BSWAP16( *b ); } /* @@ -85,19 +108,11 @@ in this Software without prior written authorization from The Open Group. FourByteSwap( unsigned char* buf, size_t nbytes ) { - for ( ; nbytes >= 4; nbytes -= 4, buf += 4 ) - { - unsigned char c; + FT_UInt32* b = (FT_UInt32*)buf; - c = buf[0]; - buf[0] = buf[3]; - buf[3] = c; - - c = buf[1]; - buf[1] = buf[2]; - buf[2] = c; - } + for ( ; nbytes >= 4; nbytes -= 4, b++ ) + *b = BSWAP32( *b ); } diff --git a/src/thirdparty/freetype2/src/pcf/pcfutil.h b/src/thirdparty/freetype2/src/pcf/pcfutil.h index be986e756..a197c1559 100644 --- a/src/thirdparty/freetype2/src/pcf/pcfutil.h +++ b/src/thirdparty/freetype2/src/pcf/pcfutil.h @@ -31,7 +31,7 @@ THE SOFTWARE. #include #include FT_CONFIG_CONFIG_H - +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pfr/pfrcmap.c b/src/thirdparty/freetype2/src/pfr/pfrcmap.c index bfa1b9ea0..489b1a5dd 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrcmap.c +++ b/src/thirdparty/freetype2/src/pfr/pfrcmap.c @@ -4,7 +4,7 @@ * * FreeType PFR cmap handling (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,8 +16,7 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include #include "pfrcmap.h" #include "pfrobjs.h" @@ -25,17 +24,18 @@ FT_CALLBACK_DEF( FT_Error ) - pfr_cmap_init( PFR_CMap cmap, + pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */ FT_Pointer pointer ) { - FT_Error error = FT_Err_Ok; - PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_Error error = FT_Err_Ok; + PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap ); FT_UNUSED( pointer ); - cmap->num_chars = face->phy_font.num_chars; - cmap->chars = face->phy_font.chars; + pfrcmap->num_chars = face->phy_font.num_chars; + pfrcmap->chars = face->phy_font.chars; /* just for safety, check that the character entries are correctly */ /* sorted in increasing character code order */ @@ -43,9 +43,9 @@ FT_UInt n; - for ( n = 1; n < cmap->num_chars; n++ ) + for ( n = 1; n < pfrcmap->num_chars; n++ ) { - if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code ) + if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code ) { error = FT_THROW( Invalid_Table ); goto Exit; @@ -59,29 +59,30 @@ FT_CALLBACK_DEF( void ) - pfr_cmap_done( PFR_CMap cmap ) + pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */ { - cmap->chars = NULL; - cmap->num_chars = 0; + PFR_CMap pfrcmap = (PFR_CMap)cmap; + + + pfrcmap->chars = NULL; + pfrcmap->num_chars = 0; } FT_CALLBACK_DEF( FT_UInt ) - pfr_cmap_char_index( PFR_CMap cmap, + pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */ FT_UInt32 char_code ) { - FT_UInt min = 0; - FT_UInt max = cmap->num_chars; + PFR_CMap pfrcmap = (PFR_CMap)cmap; + FT_UInt min = 0; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; + PFR_Char gchar; while ( min < max ) { - PFR_Char gchar; - FT_UInt mid; - - - mid = min + ( max - min ) / 2; - gchar = cmap->chars + mid; + gchar = pfrcmap->chars + mid; if ( gchar->char_code == char_code ) return mid + 1; @@ -90,15 +91,21 @@ min = mid + 1; else max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; } return 0; } - FT_CALLBACK_DEF( FT_UInt32 ) - pfr_cmap_char_next( PFR_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */ FT_UInt32 *pchar_code ) { + PFR_CMap pfrcmap = (PFR_CMap)cmap; FT_UInt result = 0; FT_UInt32 char_code = *pchar_code + 1; @@ -106,15 +113,14 @@ Restart: { FT_UInt min = 0; - FT_UInt max = cmap->num_chars; - FT_UInt mid; + FT_UInt max = pfrcmap->num_chars; + FT_UInt mid = min + ( max - min ) / 2; PFR_Char gchar; while ( min < max ) { - mid = min + ( ( max - min ) >> 1 ); - gchar = cmap->chars + mid; + gchar = pfrcmap->chars + mid; if ( gchar->char_code == char_code ) { @@ -133,14 +139,19 @@ min = mid + 1; else max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - gchar->char_code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; } /* we didn't find it, but we have a pair just above it */ char_code = 0; - if ( min < cmap->num_chars ) + if ( min < pfrcmap->num_chars ) { - gchar = cmap->chars + min; + gchar = pfrcmap->chars + min; result = min; if ( result != 0 ) { diff --git a/src/thirdparty/freetype2/src/pfr/pfrcmap.h b/src/thirdparty/freetype2/src/pfr/pfrcmap.h index 1e203a051..acf4b508d 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrcmap.h +++ b/src/thirdparty/freetype2/src/pfr/pfrcmap.h @@ -4,7 +4,7 @@ * * FreeType PFR cmap handling (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef PFRCMAP_H_ #define PFRCMAP_H_ -#include -#include FT_INTERNAL_OBJECTS_H +#include #include "pfrtypes.h" diff --git a/src/thirdparty/freetype2/src/pfr/pfrdrivr.c b/src/thirdparty/freetype2/src/pfr/pfrdrivr.c index f67eebf11..268924b50 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrdrivr.c +++ b/src/thirdparty/freetype2/src/pfr/pfrdrivr.c @@ -4,7 +4,7 @@ * * FreeType PFR driver interface (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_SERVICE_PFR_H -#include FT_SERVICE_FONT_FORMAT_H +#include +#include +#include +#include #include "pfrdrivr.h" #include "pfrobjs.h" @@ -28,16 +27,16 @@ FT_CALLBACK_DEF( FT_Error ) - pfr_get_kerning( FT_Face pfrface, /* PFR_Face */ + pfr_get_kerning( FT_Face face, /* 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 pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; - (void)pfr_face_get_kerning( pfrface, left, right, avector ); + (void)pfr_face_get_kerning( face, left, right, avector ); /* convert from metrics to outline units when necessary */ if ( phys->outline_resolution != phys->metrics_resolution ) @@ -63,12 +62,12 @@ */ FT_CALLBACK_DEF( FT_Error ) - pfr_get_advance( FT_Face pfrface, /* PFR_Face */ + pfr_get_advance( FT_Face face, /* PFR_Face */ FT_UInt gindex, FT_Pos *anadvance ) { - PFR_Face face = (PFR_Face)pfrface; - FT_Error error = FT_ERR( Invalid_Argument ); + PFR_Face pfrface = (PFR_Face)face; + FT_Error error = FT_ERR( Invalid_Argument ); *anadvance = 0; @@ -78,9 +77,9 @@ gindex--; - if ( face ) + if ( pfrface ) { - PFR_PhyFont phys = &face->phy_font; + PFR_PhyFont phys = &pfrface->phy_font; if ( gindex < phys->num_chars ) @@ -96,16 +95,16 @@ FT_CALLBACK_DEF( FT_Error ) - pfr_get_metrics( FT_Face pfrface, /* PFR_Face */ + pfr_get_metrics( FT_Face face, /* 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; + PFR_Face pfrface = (PFR_Face)face; + PFR_PhyFont phys = &pfrface->phy_font; FT_Fixed x_scale, y_scale; - FT_Size size = face->root.size; + FT_Size size = pfrface->root.size; if ( anoutline_resolution ) diff --git a/src/thirdparty/freetype2/src/pfr/pfrdrivr.h b/src/thirdparty/freetype2/src/pfr/pfrdrivr.h index 33b7b9413..61aadb973 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrdrivr.h +++ b/src/thirdparty/freetype2/src/pfr/pfrdrivr.h @@ -4,7 +4,7 @@ * * High-level Type PFR driver interface (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define PFRDRIVR_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pfr/pfrerror.h b/src/thirdparty/freetype2/src/pfr/pfrerror.h index 4829cfc00..479e3728f 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrerror.h +++ b/src/thirdparty/freetype2/src/pfr/pfrerror.h @@ -4,7 +4,7 @@ * * PFR error codes (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef PFRERROR_H_ #define PFRERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX PFR_Err_ #define FT_ERR_BASE FT_Mod_Err_PFR -#include FT_ERRORS_H +#include #endif /* PFRERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/pfr/pfrgload.c b/src/thirdparty/freetype2/src/pfr/pfrgload.c index 6ef5856a8..a694ba181 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrgload.c +++ b/src/thirdparty/freetype2/src/pfr/pfrgload.c @@ -4,7 +4,7 @@ * * FreeType PFR glyph loader (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,7 @@ #include "pfrgload.h" #include "pfrsbit.h" #include "pfrload.h" /* for macro definitions */ -#include FT_INTERNAL_DEBUG_H +#include #include "pfrerror.h" @@ -42,8 +42,7 @@ { FT_ZERO( glyph ); - glyph->loader = loader; - glyph->path_begun = 0; + glyph->loader = loader; FT_GlyphLoader_Rewind( loader ); } @@ -109,7 +108,7 @@ /* don't add empty contours */ if ( last >= first ) - outline->contours[outline->n_contours++] = (short)last; + outline->contours[outline->n_contours++] = (FT_UShort)last; glyph->path_begun = 0; } @@ -179,8 +178,8 @@ 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; + FT_Vector* vec = outline->points + outline->n_points; + FT_Byte* tag = outline->tags + outline->n_points; vec[0] = *control1; @@ -190,7 +189,7 @@ tag[1] = FT_CURVE_TAG_CUBIC; tag[2] = FT_CURVE_TAG_ON; - outline->n_points = (FT_Short)( outline->n_points + 3 ); + outline->n_points += 3; } Exit: @@ -389,7 +388,7 @@ break; case 2: /* horizontal line to */ - FT_TRACE6(( "- horizontal line to cx.%d", format_low )); + FT_TRACE6(( "- horizontal line to cx.%u", format_low )); if ( format_low >= x_count ) goto Failure; pos[0].x = glyph->x_control[format_low]; @@ -399,7 +398,7 @@ break; case 3: /* vertical line to */ - FT_TRACE6(( "- vertical line to cy.%d", format_low )); + FT_TRACE6(( "- vertical line to cy.%u", format_low )); if ( format_low >= y_count ) goto Failure; pos[0].x = pos[3].x; @@ -409,7 +408,7 @@ break; case 6: /* horizontal to vertical curve */ - FT_TRACE6(( "- hv curve " )); + FT_TRACE6(( "- hv curve" )); args_format = 0xB8E; args_count = 3; break; @@ -445,13 +444,13 @@ if ( idx >= x_count ) goto Failure; cur->x = glyph->x_control[idx]; - FT_TRACE7(( " cx#%d", idx )); + FT_TRACE7(( " cx#%u", idx )); break; case 1: /* 16-bit absolute value */ PFR_CHECK( 2 ); cur->x = PFR_NEXT_SHORT( p ); - FT_TRACE7(( " x.%d", cur->x )); + FT_TRACE7(( " x.%ld", cur->x )); break; case 2: /* 8-bit delta */ @@ -475,13 +474,13 @@ if ( idx >= y_count ) goto Failure; cur->y = glyph->y_control[idx]; - FT_TRACE7(( " cy#%d", idx )); + FT_TRACE7(( " cy#%u", idx )); break; case 1: /* 16-bit absolute value */ PFR_CHECK( 2 ); cur->y = PFR_NEXT_SHORT( p ); - FT_TRACE7(( " y.%d", cur->y )); + FT_TRACE7(( " y.%ld", cur->y )); break; case 2: /* 8-bit delta */ @@ -561,8 +560,7 @@ FT_Byte* limit ) { FT_Error error = FT_Err_Ok; - FT_GlyphLoader loader = glyph->loader; - FT_Memory memory = loader->memory; + FT_Memory memory = glyph->loader->memory; PFR_SubGlyph subglyph; FT_UInt flags, i, count, org_count; FT_Int x_pos, y_pos; @@ -756,7 +754,7 @@ count = glyph->num_subs - old_count; - FT_TRACE4(( "compound glyph with %d element%s (offset %lu):\n", + FT_TRACE4(( "compound glyph with %u element%s (offset %lu):\n", count, count == 1 ? "" : "s", offset )); @@ -768,7 +766,7 @@ PFR_SubGlyph subglyph; - FT_TRACE4(( " subglyph %d:\n", n )); + FT_TRACE4(( " subglyph %u:\n", n )); subglyph = glyph->subs + old_count + n; old_points = base->n_points; @@ -812,7 +810,7 @@ /* proceed to next sub-glyph */ } - FT_TRACE4(( "end compound glyph with %d element%s\n", + FT_TRACE4(( "end compound glyph with %u element%s\n", count, count == 1 ? "" : "s" )); } diff --git a/src/thirdparty/freetype2/src/pfr/pfrgload.h b/src/thirdparty/freetype2/src/pfr/pfrgload.h index d0e1420b6..5886ed364 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrgload.h +++ b/src/thirdparty/freetype2/src/pfr/pfrgload.h @@ -4,7 +4,7 @@ * * FreeType PFR glyph loader (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/pfr/pfrload.c b/src/thirdparty/freetype2/src/pfr/pfrload.c index ccf0b7e1f..07867b45d 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrload.c +++ b/src/thirdparty/freetype2/src/pfr/pfrload.c @@ -4,7 +4,7 @@ * * FreeType PFR loader (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,8 +17,8 @@ #include "pfrload.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H +#include +#include #include "pfrerror.h" @@ -268,9 +268,7 @@ header->version > 4 || header->header_size < 58 || header->signature2 != 0x0D0A ) /* CR/LF */ - { result = 0; - } return result; } @@ -406,11 +404,9 @@ } 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 ) { @@ -453,15 +449,16 @@ /* 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 ) + pfr_extra_item_load_bitmap_info( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) { - FT_Memory memory = phy_font->memory; - PFR_Strike strike; - FT_UInt flags0; - FT_UInt n, count, size1; - FT_Error error = FT_Err_Ok; + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Memory memory = phy_font->memory; + PFR_Strike strike; + FT_UInt flags0; + FT_UInt n, count, size1; + FT_Error error = FT_Err_Ok; PFR_CHECK( 5 ); @@ -553,19 +550,20 @@ * family. */ FT_CALLBACK_DEF( FT_Error ) - pfr_extra_item_load_font_id( FT_Byte* p, - FT_Byte* limit, - PFR_PhyFont phy_font ) + pfr_extra_item_load_font_id( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) { - FT_Error error = FT_Err_Ok; - FT_Memory memory = phy_font->memory; - FT_UInt len = (FT_UInt)( limit - p ); + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; + FT_UInt len = (FT_UInt)( limit - p ); if ( phy_font->font_id ) goto Exit; - if ( FT_ALLOC( phy_font->font_id, len + 1 ) ) + if ( FT_QALLOC( phy_font->font_id, len + 1 ) ) goto Exit; /* copy font ID name, and terminate it for safety */ @@ -579,14 +577,15 @@ /* 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 ) + pfr_extra_item_load_stem_snaps( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) { - FT_UInt count, num_vert, num_horz; - FT_Int* snaps = NULL; - FT_Error error = FT_Err_Ok; - FT_Memory memory = phy_font->memory; + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; + FT_UInt count, num_vert, num_horz; + FT_Int* snaps = NULL; + FT_Error error = FT_Err_Ok; + FT_Memory memory = phy_font->memory; if ( phy_font->vertical.stem_snaps ) @@ -601,10 +600,10 @@ PFR_CHECK( count * 2 ); - if ( FT_NEW_ARRAY( snaps, count ) ) + if ( FT_QNEW_ARRAY( snaps, count ) ) goto Exit; - phy_font->vertical.stem_snaps = snaps; + phy_font->vertical.stem_snaps = snaps; phy_font->horizontal.stem_snaps = snaps + num_vert; for ( ; count > 0; count--, snaps++ ) @@ -621,13 +620,13 @@ } - /* 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_extra_item_load_kerning_pairs( FT_Byte* p, + FT_Byte* limit, + void* phy_font_ ) { + PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_; PFR_KernItem item = NULL; FT_Error error = FT_Err_Ok; FT_Memory memory = phy_font->memory; @@ -720,10 +719,10 @@ 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 }, + { 1, pfr_extra_item_load_bitmap_info }, + { 2, pfr_extra_item_load_font_id }, + { 3, pfr_extra_item_load_stem_snaps }, + { 4, pfr_extra_item_load_kerning_pairs }, { 0, NULL } }; @@ -761,7 +760,7 @@ if ( ok ) { - if ( FT_ALLOC( result, len + 1 ) ) + if ( FT_QALLOC( result, len + 1 ) ) goto Exit; FT_MEM_COPY( result, p, len ); @@ -857,8 +856,16 @@ phy_font->bbox.yMax = PFR_NEXT_SHORT( p ); phy_font->flags = flags = PFR_NEXT_BYTE( p ); + if ( !phy_font->outline_resolution || + !phy_font->metrics_resolution ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: invalid resolution\n" )); + goto Fail; + } + /* get the standard advance for non-proportional fonts */ - if ( !(flags & PFR_PHY_PROPORTIONAL) ) + if ( !( flags & PFR_PHY_PROPORTIONAL ) ) { PFR_CHECK( 2 ); phy_font->standard_advance = PFR_NEXT_SHORT( p ); @@ -869,14 +876,13 @@ { 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. */ + /* guessed by looking at the content of a few 'PFR0' fonts. */ PFR_CHECK( 3 ); num_aux = PFR_NEXT_ULONG( p ); @@ -953,7 +959,7 @@ PFR_CHECK( count * 2 ); - if ( FT_NEW_ARRAY( phy_font->blue_values, count ) ) + if ( FT_QNEW_ARRAY( phy_font->blue_values, count ) ) goto Fail; for ( n = 0; n < count; n++ ) @@ -975,6 +981,13 @@ phy_font->num_chars = count = PFR_NEXT_USHORT( p ); phy_font->chars_offset = offset + (FT_Offset)( p - stream->cursor ); + if ( !phy_font->num_chars ) + { + error = FT_THROW( Invalid_Table ); + FT_ERROR(( "pfr_phy_font_load: no glyphs\n" )); + goto Fail; + } + Size = 1 + 1 + 2; if ( flags & PFR_PHY_2BYTE_CHARCODE ) Size += 1; @@ -993,7 +1006,7 @@ PFR_CHECK_SIZE( count * Size ); - if ( FT_NEW_ARRAY( phy_font->chars, count ) ) + if ( FT_QNEW_ARRAY( phy_font->chars, count ) ) goto Fail; for ( n = 0; n < count; n++ ) diff --git a/src/thirdparty/freetype2/src/pfr/pfrload.h b/src/thirdparty/freetype2/src/pfr/pfrload.h index 2e7ffd012..f530a0a58 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrload.h +++ b/src/thirdparty/freetype2/src/pfr/pfrload.h @@ -4,7 +4,7 @@ * * FreeType PFR loader (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,7 @@ #define PFRLOAD_H_ #include "pfrobjs.h" -#include FT_INTERNAL_STREAM_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pfr/pfrobjs.c b/src/thirdparty/freetype2/src/pfr/pfrobjs.c index 9765f95c2..39ad3cc7d 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrobjs.c +++ b/src/thirdparty/freetype2/src/pfr/pfrobjs.c @@ -4,7 +4,7 @@ * * FreeType PFR object methods (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,10 +21,10 @@ #include "pfrgload.h" #include "pfrcmap.h" #include "pfrsbit.h" -#include FT_OUTLINE_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include +#include #include "pfrerror.h" @@ -50,14 +50,14 @@ if ( !face ) return; - memory = pfrface->driver->root.memory; + memory = pfrface->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 ) ); + pfr_phy_font_done( &face->phy_font, memory ); /* no need to finalize the logical font or the header */ FT_FREE( pfrface->available_sizes ); @@ -83,7 +83,11 @@ /* load the header and check it */ error = pfr_header_load( &face->header, stream ); if ( error ) + { + FT_TRACE2(( " not a PFR font\n" )); + error = FT_THROW( Unknown_File_Format ); goto Exit; + } if ( !pfr_header_check( &face->header ) ) { @@ -126,14 +130,14 @@ if ( error ) goto Exit; - /* now load the physical font descriptor */ + /* 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 */ + /* set up all root face fields */ { PFR_PhyFont phy_font = &face->phy_font; @@ -156,7 +160,7 @@ if ( nn == phy_font->num_chars ) { if ( phy_font->num_strikes > 0 ) - pfrface->face_flags = 0; /* not scalable */ + pfrface->face_flags &= ~FT_FACE_FLAG_SCALABLE; else { FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); @@ -166,7 +170,7 @@ } } - if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) + if ( !( phy_font->flags & PFR_PHY_PROPORTIONAL ) ) pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; if ( phy_font->flags & PFR_PHY_VERTICAL ) @@ -203,17 +207,17 @@ 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); + 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; + FT_Memory memory = pfrface->memory; - if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) + if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) ) goto Exit; size = pfrface->available_sizes; @@ -322,7 +326,7 @@ FT_ULong gps_offset; - FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); + FT_TRACE1(( "pfr_slot_load: glyph index %u\n", gindex )); if ( gindex > 0 ) gindex--; @@ -334,7 +338,7 @@ } /* try to load an embedded bitmap */ - if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) + if ( !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) ) { error = pfr_slot_load_bitmap( slot, @@ -351,11 +355,8 @@ 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; + gchar = face->phy_font.chars + gindex; + 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, @@ -367,10 +368,9 @@ FT_Glyph_Metrics* metrics = &pfrslot->metrics; FT_Pos advance; FT_UInt em_metrics, em_outline; - FT_Bool scaling; - scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); + pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; /* copy outline data */ *outline = slot->glyph.loader->base.outline; @@ -425,7 +425,7 @@ #endif /* scale when needed */ - if ( scaling ) + if ( !( load_flags & FT_LOAD_NO_SCALE ) ) { FT_Int n; FT_Fixed x_scale = pfrsize->metrics.x_scale; @@ -482,17 +482,16 @@ kerning->x = 0; kerning->y = 0; - if ( glyph1 > 0 ) - glyph1--; + /* PFR indexing skips .notdef, which becomes UINT_MAX */ + glyph1--; + glyph2--; - if ( glyph2 > 0 ) - glyph2--; - - /* convert glyph indices to character codes */ - if ( glyph1 > phy_font->num_chars || - glyph2 > phy_font->num_chars ) + /* check the array bounds, .notdef is automatically out */ + if ( glyph1 >= phy_font->num_chars || + glyph2 >= phy_font->num_chars ) goto Exit; + /* convert glyph indices to character codes */ code1 = phy_font->chars[glyph1].char_code; code2 = phy_font->chars[glyph2].char_code; pair = PFR_KERN_INDEX( code1, code2 ); diff --git a/src/thirdparty/freetype2/src/pfr/pfrobjs.h b/src/thirdparty/freetype2/src/pfr/pfrobjs.h index 39cffd07c..850bf5b4a 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrobjs.h +++ b/src/thirdparty/freetype2/src/pfr/pfrobjs.h @@ -4,7 +4,7 @@ * * FreeType PFR object methods (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/pfr/pfrsbit.c b/src/thirdparty/freetype2/src/pfr/pfrsbit.c index 00a961645..08db4c459 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrsbit.c +++ b/src/thirdparty/freetype2/src/pfr/pfrsbit.c @@ -4,7 +4,7 @@ * * FreeType PFR bitmap loader (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,8 +18,8 @@ #include "pfrsbit.h" #include "pfrload.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H +#include +#include #include "pfrerror.h" @@ -282,7 +282,7 @@ FT_ULong* found_offset, FT_ULong* found_size ) { - FT_UInt min, max, char_len; + FT_UInt min, max, mid, char_len; FT_Bool two = FT_BOOL( *flags & PFR_BITMAP_2BYTE_CHARCODE ); FT_Byte* buff; @@ -310,8 +310,8 @@ if ( lim > limit ) { FT_TRACE0(( "pfr_lookup_bitmap_data:" - " number of bitmap records too large,\n" - " " + " number of bitmap records too large,\n" )); + FT_TRACE0(( " " " thus ignoring all bitmaps in this strike\n" )); *flags &= ~PFR_BITMAP_VALID_CHARCODES; } @@ -328,8 +328,8 @@ if ( (FT_Long)code <= prev_code ) { FT_TRACE0(( "pfr_lookup_bitmap_data:" - " bitmap records are not sorted,\n" - " " + " bitmap records are not sorted,\n" )); + FT_TRACE0(( " " " thus ignoring all bitmaps in this strike\n" )); *flags &= ~PFR_BITMAP_VALID_CHARCODES; break; @@ -349,14 +349,14 @@ min = 0; max = count; + mid = min + ( max - min ) / 2; /* binary search */ while ( min < max ) { - FT_UInt mid, code; + FT_UInt code; - mid = ( min + max ) >> 1; buff = base + mid * char_len; if ( two ) @@ -370,6 +370,11 @@ min = mid + 1; else goto Found_It; + + /* reasonable prediction in a continuous block */ + mid += char_code - code; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; } Fail: @@ -391,7 +396,7 @@ } - /* load bitmap metrics. `*padvance' must be set to the default value */ + /* load bitmap metrics. `*aadvance' must be set to the default value */ /* before calling this function */ /* */ static FT_Error @@ -575,7 +580,7 @@ /*************************************************************************/ /*************************************************************************/ - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) pfr_slot_load_bitmap( PFR_Slot glyph, PFR_Size size, FT_UInt glyph_index, @@ -628,7 +633,7 @@ if ( strike->flags & PFR_BITMAP_3BYTE_OFFSET ) char_len += 1; - /* access data directly in the frame to speed lookups */ + /* access data directly in the frame to speed up lookups */ if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) || FT_FRAME_ENTER( char_len * strike->num_bitmaps ) ) goto Exit; @@ -744,8 +749,8 @@ ypos > FT_INT_MAX - (FT_Long)ysize || ypos + (FT_Long)ysize < FT_INT_MIN ) { - FT_TRACE1(( "pfr_slot_load_bitmap:" )); - FT_TRACE1(( "huge bitmap glyph %dx%d over FT_GlyphSlot\n", + FT_TRACE1(( "pfr_slot_load_bitmap:" + " huge bitmap glyph %ldx%ld over FT_GlyphSlot\n", xpos, ypos )); error = FT_THROW( Invalid_Pixel_Size ); } diff --git a/src/thirdparty/freetype2/src/pfr/pfrsbit.h b/src/thirdparty/freetype2/src/pfr/pfrsbit.h index 6568b9094..c5c27e36b 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrsbit.h +++ b/src/thirdparty/freetype2/src/pfr/pfrsbit.h @@ -4,7 +4,7 @@ * * FreeType PFR bitmap loader (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/pfr/pfrtypes.h b/src/thirdparty/freetype2/src/pfr/pfrtypes.h index 6a5f9d571..83461cb16 100644 --- a/src/thirdparty/freetype2/src/pfr/pfrtypes.h +++ b/src/thirdparty/freetype2/src/pfr/pfrtypes.h @@ -4,7 +4,7 @@ * * FreeType PFR data structures (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,8 +19,7 @@ #ifndef PFRTYPES_H_ #define PFRTYPES_H_ -#include -#include FT_INTERNAL_OBJECTS_H +#include FT_BEGIN_HEADER @@ -110,7 +109,7 @@ FT_BEGIN_HEADER #define PFR_BITMAP_2BYTE_SIZE 0x02U #define PFR_BITMAP_3BYTE_OFFSET 0x04U - /*not part of the specification but used for implementation */ + /* not part of the specification but used for implementation */ #define PFR_BITMAP_CHARCODES_VALIDATED 0x40U #define PFR_BITMAP_VALID_CHARCODES 0x80U diff --git a/src/thirdparty/freetype2/src/psaux/afmparse.c b/src/thirdparty/freetype2/src/psaux/afmparse.c index f78adbba3..b813efde4 100644 --- a/src/thirdparty/freetype2/src/psaux/afmparse.c +++ b/src/thirdparty/freetype2/src/psaux/afmparse.c @@ -4,7 +4,7 @@ * * AFM parser (body). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -15,10 +15,9 @@ * */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include #ifndef T1_CONFIG_OPTION_NO_AFM @@ -28,6 +27,16 @@ #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 afmparse + + /************************************************************************** * * AFM_Stream @@ -554,7 +563,7 @@ } - FT_LOCAL( void ) + FT_LOCAL_DEF( void ) afm_parser_done( AFM_Parser parser ) { FT_Memory memory = parser->memory; @@ -587,21 +596,39 @@ static FT_Error afm_parse_track_kern( AFM_Parser parser ) { - AFM_FontInfo fi = parser->FontInfo; + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; AFM_TrackKern tk; - char* key; - FT_Offset len; - int n = -1; - FT_Int tmp; + + char* key; + FT_Offset len; + int n = -1; + FT_Int tmp; if ( afm_parser_read_int( parser, &tmp ) ) goto Fail; if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" )); goto Fail; + } fi->NumTrackKern = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n", + fi->NumTrackKern, + fi->NumTrackKern == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `TrackKern` */ + /* command is 20 characters (including the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 20 < + fi->NumTrackKern ) + { + FT_ERROR(( "afm_parse_track_kern:" + " number of track kern entries exceeds stream size\n" )); + goto Fail; + } if ( fi->NumTrackKern ) { @@ -624,7 +651,10 @@ n++; if ( n >= (int)fi->NumTrackKern ) - goto Fail; + { + FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" )); + goto Fail; + } tk = fi->TrackKerns + n; @@ -634,7 +664,12 @@ 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 ) + { + FT_ERROR(( "afm_parse_track_kern:" + " insufficient number of parameters for entry %d\n", + n )); goto Fail; + } tk->degree = shared_vals[0].u.i; tk->min_ptsize = shared_vals[1].u.f; @@ -647,7 +682,19 @@ case AFM_TOKEN_ENDTRACKKERN: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: - fi->NumTrackKern = (FT_UInt)( n + 1 ); + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumTrackKern ) + { + FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "y" : "ies" )); + fi->NumTrackKern = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n", + tmp, + tmp == 1 ? "y" : "ies" )); return FT_Err_Ok; case AFM_TOKEN_UNKNOWN: @@ -668,7 +715,7 @@ /* compare two kerning pairs */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) afm_compare_kern_pairs( const void* a, const void* b ) { @@ -691,7 +738,8 @@ static FT_Error afm_parse_kern_pairs( AFM_Parser parser ) { - AFM_FontInfo fi = parser->FontInfo; + AFM_FontInfo fi = parser->FontInfo; + AFM_Stream stream = parser->stream; AFM_KernPair kp; char* key; FT_Offset len; @@ -703,9 +751,26 @@ goto Fail; if ( tmp < 0 ) + { + FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" )); goto Fail; + } fi->NumKernPair = (FT_UInt)tmp; + FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n", + fi->NumKernPair, + fi->NumKernPair == 1 ? "" : "s" )); + + /* Rough sanity check: The minimum line length of the `KP`, */ + /* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */ + /* the EOL character). */ + if ( (FT_ULong)( stream->limit - stream->cursor ) / 10 < + fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " number of kern pairs exceeds stream size\n" )); + goto Fail; + } if ( fi->NumKernPair ) { @@ -735,7 +800,10 @@ n++; if ( n >= (int)fi->NumKernPair ) + { + FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" )); goto Fail; + } kp = fi->KernPairs + n; @@ -745,7 +813,12 @@ shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; r = afm_parser_read_vals( parser, shared_vals, 4 ); if ( r < 3 ) + { + FT_ERROR(( "afm_parse_kern_pairs:" + " insufficient number of parameters for entry %d\n", + n )); goto Fail; + } /* index values can't be negative */ kp->index1 = shared_vals[0].u.u; @@ -767,7 +840,20 @@ case AFM_TOKEN_ENDKERNPAIRS: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: - fi->NumKernPair = (FT_UInt)( n + 1 ); + tmp = n + 1; + if ( (FT_UInt)tmp != fi->NumKernPair ) + { + FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n", + tmp == 0 ? "" : "only ", + tmp, + tmp == 1 ? "" : "s" )); + fi->NumKernPair = (FT_UInt)tmp; + } + else + FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n", + tmp, + tmp == 1 ? "" : "s" )); + ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), afm_compare_kern_pairs ); @@ -793,22 +879,43 @@ char* key; FT_Offset len; + int have_trackkern = 0; + int have_kernpairs = 0; + while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) { switch ( afm_tokenize( key, len ) ) { case AFM_TOKEN_STARTTRACKKERN: + if ( have_trackkern ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal track kern section\n" )); + goto Fail; + } + error = afm_parse_track_kern( parser ); if ( error ) return error; + + have_trackkern = 1; break; case AFM_TOKEN_STARTKERNPAIRS: case AFM_TOKEN_STARTKERNPAIRS0: + if ( have_kernpairs ) + { + FT_ERROR(( "afm_parse_kern_data:" + " invalid second horizontal kern pair section\n" )); + goto Fail; + } + error = afm_parse_kern_pairs( parser ); if ( error ) return error; + + have_kernpairs = 1; break; case AFM_TOKEN_ENDKERNDATA: @@ -954,7 +1061,7 @@ if ( error ) goto Fail; /* we only support kern data, so ... */ - /* fall through */ + FALL_THROUGH; case AFM_TOKEN_ENDFONTMETRICS: return FT_Err_Ok; @@ -979,7 +1086,7 @@ #else /* T1_CONFIG_OPTION_NO_AFM */ /* ANSI C doesn't like empty source files */ - typedef int _afm_parse_dummy; + typedef int afm_parse_dummy_; #endif /* T1_CONFIG_OPTION_NO_AFM */ diff --git a/src/thirdparty/freetype2/src/psaux/afmparse.h b/src/thirdparty/freetype2/src/psaux/afmparse.h index 2ceb77553..add859771 100644 --- a/src/thirdparty/freetype2/src/psaux/afmparse.h +++ b/src/thirdparty/freetype2/src/psaux/afmparse.h @@ -4,7 +4,7 @@ * * AFM parser (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define AFMPARSE_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/cffdecode.c b/src/thirdparty/freetype2/src/psaux/cffdecode.c index 17cccf818..17bdd23c7 100644 --- a/src/thirdparty/freetype2/src/psaux/cffdecode.c +++ b/src/thirdparty/freetype2/src/psaux/cffdecode.c @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (body). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,11 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_SERVICE_H -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include +#include +#include +#include +#include #include "cffdecode.h" #include "psobjs.h" @@ -249,7 +249,7 @@ else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - CFF_Font cff = (CFF_Font)(face->extra.data); + CFF_Font cff = (CFF_Font)( face->extra.data ); bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar ); @@ -330,7 +330,7 @@ builder->left_bearing.x = 0; builder->left_bearing.y = 0; - builder->pos_x = adx - asb; + builder->pos_x = SUB_LONG( adx, asb ); builder->pos_y = ady; /* Now load `achar' on top of the base outline. */ @@ -530,6 +530,9 @@ builder->path_begun = 0; + if ( !charstring_base ) + return FT_Err_Ok; + zone->base = charstring_base; limit = zone->limit = charstring_base + charstring_len; ip = zone->cursor = zone->base; @@ -1750,22 +1753,9 @@ /* without upper limit the loop below might not finish */ if ( args[0] > 0x7FFFFFFFL ) - args[0] = 46341; + args[0] = 0xB504F4L; /* sqrt( 32768.0044 ) */ else if ( args[0] > 0 ) - { - FT_Fixed root = args[0]; - FT_Fixed new_root; - - - for (;;) - { - new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1; - if ( new_root == root ) - break; - root = new_root; - } - args[0] = new_root; - } + args[0] = (FT_Fixed)FT_SqrtFixed( args[0] ); else args[0] = 0; args++; @@ -1869,7 +1859,7 @@ case cff_op_put: { FT_Fixed val = args[0]; - FT_Int idx = (FT_Int)( args[1] >> 16 ); + FT_UInt idx = (FT_UInt)( args[1] >> 16 ); FT_TRACE4(( " put\n" )); @@ -1878,20 +1868,20 @@ /* didn't give a hard-coded size limit of the temporary */ /* storage array; instead, an argument of the */ /* `MultipleMaster' operator set the size */ - if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + if ( idx < CFF_MAX_TRANS_ELEMENTS ) decoder->buildchar[idx] = val; } break; case cff_op_get: { - FT_Int idx = (FT_Int)( args[0] >> 16 ); + FT_UInt idx = (FT_UInt)( args[0] >> 16 ); FT_Fixed val = 0; FT_TRACE4(( " get\n" )); - if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS ) + if ( idx < CFF_MAX_TRANS_ELEMENTS ) val = decoder->buildchar[idx]; args[0] = val; @@ -1912,9 +1902,9 @@ /* this operator was removed from the Type2 specification */ /* in version 16-March-2000 */ { - FT_Int reg_idx = (FT_Int)args[0]; - FT_Int idx = (FT_Int)args[1]; - FT_Int count = (FT_Int)args[2]; + FT_UInt reg_idx = (FT_UInt)args[0]; + FT_UInt idx = (FT_UInt)args[1]; + FT_UInt count = (FT_UInt)args[2]; FT_TRACE4(( " load\n" )); @@ -1922,11 +1912,11 @@ /* since we currently don't handle interpolation of multiple */ /* master fonts, we store a vector [1 0 0 ...] in the */ /* temporary storage array regardless of the Registry index */ - if ( reg_idx >= 0 && reg_idx <= 2 && - idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS && - count >= 0 && count <= num_axes ) + if ( reg_idx <= 2 && + idx < CFF_MAX_TRANS_ELEMENTS && + count <= num_axes ) { - FT_Int end, i; + FT_UInt end, i; end = FT_MIN( idx + count, CFF_MAX_TRANS_ELEMENTS ); @@ -2151,7 +2141,7 @@ decoder->locals_bias ); - FT_TRACE4(( " callsubr (idx %d, entering level %d)\n", + FT_TRACE4(( " callsubr (idx %u, entering level %td)\n", idx, zone - decoder->zones + 1 )); @@ -2195,7 +2185,7 @@ decoder->globals_bias ); - FT_TRACE4(( " callgsubr (idx %d, entering level %d)\n", + FT_TRACE4(( " callgsubr (idx %u, entering level %td)\n", idx, zone - decoder->zones + 1 )); @@ -2234,7 +2224,7 @@ break; case cff_op_return: - FT_TRACE4(( " return (leaving level %d)\n", + FT_TRACE4(( " return (leaving level %td)\n", decoder->zone - decoder->zones )); if ( decoder->zone <= decoder->zones ) @@ -2269,7 +2259,8 @@ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); Fail: return error; diff --git a/src/thirdparty/freetype2/src/psaux/cffdecode.h b/src/thirdparty/freetype2/src/psaux/cffdecode.h index a6691979f..e72ec043b 100644 --- a/src/thirdparty/freetype2/src/psaux/cffdecode.h +++ b/src/thirdparty/freetype2/src/psaux/cffdecode.h @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (specification). * - * Copyright (C) 2017-2019 by + * Copyright (C) 2017-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define CFFDECODE_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/psarrst.c b/src/thirdparty/freetype2/src/psaux/psarrst.c index 011803b41..70313d283 100644 --- a/src/thirdparty/freetype2/src/psaux/psarrst.c +++ b/src/thirdparty/freetype2/src/psaux/psarrst.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psglue.h" #include "psarrst.h" @@ -65,7 +65,6 @@ arrstack->error = error; arrstack->sizeItem = sizeItem; arrstack->allocated = 0; - arrstack->chunk = 10; /* chunks of 10 items */ arrstack->count = 0; arrstack->totalSize = 0; arrstack->ptr = NULL; @@ -110,7 +109,7 @@ FT_ASSERT( newSize > 0 ); /* avoid realloc with zero size */ - if ( !FT_REALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) + if ( !FT_QREALLOC( arrstack->ptr, arrstack->totalSize, newSize ) ) { arrstack->allocated = numElements; arrstack->totalSize = newSize; @@ -216,9 +215,9 @@ if ( arrstack->count == arrstack->allocated ) { - /* grow the buffer by one chunk */ + /* increase the buffer size */ if ( !cf2_arrstack_setNumElements( - arrstack, arrstack->allocated + arrstack->chunk ) ) + arrstack, arrstack->allocated * 2 + 16 ) ) { /* on error, ignore the push */ return; diff --git a/src/thirdparty/freetype2/src/psaux/psarrst.h b/src/thirdparty/freetype2/src/psaux/psarrst.h index 098617b25..31e5330cc 100644 --- a/src/thirdparty/freetype2/src/psaux/psarrst.h +++ b/src/thirdparty/freetype2/src/psaux/psarrst.h @@ -55,7 +55,6 @@ FT_BEGIN_HEADER size_t sizeItem; /* bytes per element */ size_t allocated; /* items allocated */ - size_t chunk; /* allocation increment in items */ size_t count; /* number of elements allocated */ size_t totalSize; /* total bytes allocated */ diff --git a/src/thirdparty/freetype2/src/psaux/psauxerr.h b/src/thirdparty/freetype2/src/psaux/psauxerr.h index 523e1886c..0d7fe2b61 100644 --- a/src/thirdparty/freetype2/src/psaux/psauxerr.h +++ b/src/thirdparty/freetype2/src/psaux/psauxerr.h @@ -4,7 +4,7 @@ * * PS auxiliary module error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef PSAUXERR_H_ #define PSAUXERR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX PSaux_Err_ #define FT_ERR_BASE FT_Mod_Err_PSaux -#include FT_ERRORS_H +#include #endif /* PSAUXERR_H_ */ diff --git a/src/thirdparty/freetype2/src/psaux/psauxmod.c b/src/thirdparty/freetype2/src/psaux/psauxmod.c index 5df8e6905..942804190 100644 --- a/src/thirdparty/freetype2/src/psaux/psauxmod.c +++ b/src/thirdparty/freetype2/src/psaux/psauxmod.c @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,7 +16,6 @@ */ -#include #include "psauxmod.h" #include "psobjs.h" #include "t1decode.h" @@ -171,9 +170,9 @@ }; - FT_CALLBACK_TABLE_DEF - const FT_Module_Class psaux_module_class = - { + FT_DEFINE_MODULE( + psaux_module_class, + 0, sizeof ( FT_ModuleRec ), "psaux", @@ -185,7 +184,7 @@ (FT_Module_Constructor)NULL, /* module_init */ (FT_Module_Destructor) NULL, /* module_done */ (FT_Module_Requester) NULL /* get_interface */ - }; + ) /* END */ diff --git a/src/thirdparty/freetype2/src/psaux/psauxmod.h b/src/thirdparty/freetype2/src/psaux/psauxmod.h index a0eda0bfc..4a5ebc1b6 100644 --- a/src/thirdparty/freetype2/src/psaux/psauxmod.h +++ b/src/thirdparty/freetype2/src/psaux/psauxmod.h @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define PSAUXMOD_H_ -#include -#include FT_MODULE_H +#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_BEGIN_HEADER @@ -35,8 +34,19 @@ FT_BEGIN_HEADER FT_CALLBACK_TABLE const PS_Builder_FuncsRec ps_builder_funcs; +#ifndef T1_CONFIG_OPTION_NO_AFM + FT_CALLBACK_TABLE + const AFM_Parser_FuncsRec afm_parser_funcs; +#endif - FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class; + FT_CALLBACK_TABLE + const T1_CMap_ClassesRec t1_cmap_classes; + + FT_CALLBACK_TABLE + const CFF_Decoder_FuncsRec cff_decoder_funcs; + + + FT_DECLARE_MODULE( psaux_module_class ) FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/psblues.c b/src/thirdparty/freetype2/src/psaux/psblues.c index 89738ce47..213b943b4 100644 --- a/src/thirdparty/freetype2/src/psaux/psblues.c +++ b/src/thirdparty/freetype2/src/psaux/psblues.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psblues.h" #include "pshints.h" @@ -54,14 +54,6 @@ #define FT_COMPONENT cf2blues - /* - * For blue values, the FreeType parser produces an array of integers, - * while the Adobe CFF engine produces an array of fixed. - * Define a macro to convert FreeType to fixed. - */ -#define cf2_blueToFixed( x ) cf2_intToFixed( x ) - - FT_LOCAL_DEF( void ) cf2_blues_init( CF2_Blues blues, CF2_Font font ) @@ -78,10 +70,10 @@ size_t numFamilyBlues; size_t numFamilyOtherBlues; - FT_Pos* blueValues; - FT_Pos* otherBlues; - FT_Pos* familyBlues; - FT_Pos* familyOtherBlues; + FT_Fixed* blueValues; + FT_Fixed* otherBlues; + FT_Fixed* familyBlues; + FT_Fixed* familyOtherBlues; size_t i; CF2_Fixed emBoxBottom, emBoxTop; @@ -138,13 +130,13 @@ emBoxTop = CF2_ICF_Top; } - if ( cf2_getLanguageGroup( decoder ) == 1 && - ( numBlueValues == 0 || - ( numBlueValues == 4 && - cf2_blueToFixed( blueValues[0] ) < emBoxBottom && - cf2_blueToFixed( blueValues[1] ) < emBoxBottom && - cf2_blueToFixed( blueValues[2] ) > emBoxTop && - cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) + if ( cf2_getLanguageGroup( decoder ) == 1 && + ( numBlueValues == 0 || + ( numBlueValues == 4 && + blueValues[0] < emBoxBottom && + blueValues[1] < emBoxBottom && + blueValues[2] > emBoxTop && + blueValues[3] > emBoxTop ) ) ) { /* * Construct hint edges suitable for synthetic ghost hints at top @@ -189,10 +181,8 @@ /* bottom zones */ for ( i = 0; i < numBlueValues; i += 2 ) { - blues->zone[blues->count].csBottomEdge = - cf2_blueToFixed( blueValues[i] ); - blues->zone[blues->count].csTopEdge = - cf2_blueToFixed( blueValues[i + 1] ); + blues->zone[blues->count].csBottomEdge = blueValues[i]; + blues->zone[blues->count].csTopEdge = blueValues[i + 1]; zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, blues->zone[blues->count].csBottomEdge ); @@ -238,10 +228,8 @@ for ( i = 0; i < numOtherBlues; i += 2 ) { - blues->zone[blues->count].csBottomEdge = - cf2_blueToFixed( otherBlues[i] ); - blues->zone[blues->count].csTopEdge = - cf2_blueToFixed( otherBlues[i + 1] ); + blues->zone[blues->count].csBottomEdge = otherBlues[i]; + blues->zone[blues->count].csTopEdge = otherBlues[i + 1]; zoneHeight = SUB_INT32( blues->zone[blues->count].csTopEdge, blues->zone[blues->count].csBottomEdge ); @@ -299,7 +287,7 @@ for ( j = 0; j < numFamilyOtherBlues; j += 2 ) { /* top edge */ - flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); + flatFamilyEdge = familyOtherBlues[j + 1]; diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); @@ -317,7 +305,7 @@ if ( numFamilyBlues >= 2 ) { /* top edge */ - flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); + flatFamilyEdge = familyBlues[1]; diff = cf2_fixedAbs( SUB_INT32( flatEdge, flatFamilyEdge ) ); @@ -337,7 +325,7 @@ for ( j = 2; j < numFamilyBlues; j += 2 ) { /* bottom edge */ - flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); + flatFamilyEdge = familyBlues[j]; /* adjust edges of top zone upward by twice darkening amount */ flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ @@ -506,7 +494,8 @@ /* guarantee minimum of 1 pixel overshoot */ dsNew = FT_MIN( cf2_fixedRound( bottomHintEdge->dsCoord ), - blues->zone[i].dsFlatEdge - cf2_intToFixed( 1 ) ); + SUB_INT32( blues->zone[i].dsFlatEdge, + cf2_intToFixed( 1 ) ) ); } else diff --git a/src/thirdparty/freetype2/src/psaux/psconv.c b/src/thirdparty/freetype2/src/psaux/psconv.c index c88761681..4567d3f3c 100644 --- a/src/thirdparty/freetype2/src/psaux/psconv.c +++ b/src/thirdparty/freetype2/src/psaux/psconv.c @@ -4,7 +4,7 @@ * * Some convenience conversions (body). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,9 +16,8 @@ */ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_DEBUG_H +#include +#include #include "psconv.h" #include "psauxerr.h" @@ -536,11 +535,11 @@ if ( r & 1 ) { - *buffer = (FT_Byte)(*buffer + c); + *buffer = (FT_Byte)( *buffer + c ); buffer++; } else - *buffer = (FT_Byte)(c << 4); + *buffer = (FT_Byte)( c << 4 ); r++; } @@ -573,8 +572,8 @@ if ( p >= limit ) return 0; - if ( n > (FT_UInt)(limit - p) ) - n = (FT_UInt)(limit - p); + if ( n > (FT_UInt)( limit - p ) ) + n = (FT_UInt)( limit - p ); for ( r = 0; r < n; r++ ) { diff --git a/src/thirdparty/freetype2/src/psaux/psconv.h b/src/thirdparty/freetype2/src/psaux/psconv.h index 6b24bf6fc..63735af41 100644 --- a/src/thirdparty/freetype2/src/psaux/psconv.h +++ b/src/thirdparty/freetype2/src/psaux/psconv.h @@ -4,7 +4,7 @@ * * Some convenience conversions (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define PSCONV_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/pserror.h b/src/thirdparty/freetype2/src/psaux/pserror.h index b2156b331..5738853fa 100644 --- a/src/thirdparty/freetype2/src/psaux/pserror.h +++ b/src/thirdparty/freetype2/src/psaux/pserror.h @@ -40,7 +40,7 @@ #define PSERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -49,7 +49,8 @@ #define FT_ERR_BASE FT_Mod_Err_CF2 -#include FT_ERRORS_H +#include +#include #include "psft.h" diff --git a/src/thirdparty/freetype2/src/psaux/psfixed.h b/src/thirdparty/freetype2/src/psaux/psfixed.h index 7dff9ef1b..299d07637 100644 --- a/src/thirdparty/freetype2/src/psaux/psfixed.h +++ b/src/thirdparty/freetype2/src/psaux/psfixed.h @@ -2,7 +2,7 @@ * * psfixed.h * - * Adobe's code for Fixed Point Mathematics (specification only). + * Adobe's code for Fixed-Point Mathematics (specification only). * * Copyright 2007-2013 Adobe Systems Incorporated. * @@ -43,10 +43,10 @@ FT_BEGIN_HEADER - /* rasterizer integer and fixed point arithmetic must be 32-bit */ + /* rasterizer integer and fixed-point arithmetic must be 32-bit */ #define CF2_Fixed CF2_F16Dot16 - typedef FT_Int32 CF2_Frac; /* 2.30 fixed point */ + typedef FT_Int32 CF2_Frac; /* 2.30 fixed-point */ #define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL ) diff --git a/src/thirdparty/freetype2/src/psaux/psfont.c b/src/thirdparty/freetype2/src/psaux/psfont.c index 00e421081..0db1f0c5b 100644 --- a/src/thirdparty/freetype2/src/psaux/psfont.c +++ b/src/thirdparty/freetype2/src/psaux/psfont.c @@ -36,8 +36,7 @@ */ -#include -#include FT_INTERNAL_CALC_H +#include #include "psft.h" diff --git a/src/thirdparty/freetype2/src/psaux/psfont.h b/src/thirdparty/freetype2/src/psaux/psfont.h index 8fbacbb6e..836fce4e4 100644 --- a/src/thirdparty/freetype2/src/psaux/psfont.h +++ b/src/thirdparty/freetype2/src/psaux/psfont.h @@ -40,7 +40,7 @@ #define PSFONT_H_ -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include #include "psft.h" #include "psblues.h" diff --git a/src/thirdparty/freetype2/src/psaux/psft.c b/src/thirdparty/freetype2/src/psaux/psft.c index 54be46834..fd0abe171 100644 --- a/src/thirdparty/freetype2/src/psaux/psft.c +++ b/src/thirdparty/freetype2/src/psaux/psft.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psfont.h" #include "pserror.h" @@ -45,11 +45,11 @@ #include "cffdecode.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H +#include +#include #endif -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include #define CF2_MAX_SIZE cf2_intToFixed( 2000 ) /* max ppem */ @@ -68,11 +68,10 @@ CF2_Fixed maxScale; - FT_ASSERT( unitsPerEm > 0 ); - if ( transform->a <= 0 || transform->d <= 0 ) return FT_THROW( Invalid_Size_Handle ); + FT_ASSERT( unitsPerEm > 0 ); FT_ASSERT( transform->b == 0 && transform->c == 0 ); FT_ASSERT( transform->tx == 0 && transform->ty == 0 ); @@ -297,7 +296,6 @@ cf2_getUnitsPerEm( PS_Decoder* decoder ) { FT_ASSERT( decoder && decoder->builder.face ); - FT_ASSERT( decoder->builder.face->units_per_EM ); return decoder->builder.face->units_per_EM; } @@ -313,7 +311,7 @@ FT_Error error = FT_Err_Ok; CF2_Font font; - FT_Bool is_t1 = decoder->builder.is_t1; + FT_Bool is_t1 = decoder->builder.is_t1; FT_ASSERT( decoder && @@ -385,7 +383,7 @@ FT_ZERO( &buf ); buf.start = buf.ptr = charstring_base; - buf.end = charstring_base + charstring_len; + buf.end = FT_OFFSET( charstring_base, charstring_len ); FT_ZERO( &transform ); @@ -568,12 +566,12 @@ FT_LOCAL_DEF( void ) cf2_getBlueValues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_blue_values; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.blue_values; } @@ -581,12 +579,12 @@ FT_LOCAL_DEF( void ) cf2_getOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_other_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.other_blues; } @@ -594,12 +592,12 @@ FT_LOCAL_DEF( void ) cf2_getFamilyBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_family_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.family_blues; } @@ -607,12 +605,12 @@ FT_LOCAL_DEF( void ) cf2_getFamilyOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ) + FT_Fixed* *data ) { FT_ASSERT( decoder && decoder->current_subfont ); *count = decoder->current_subfont->private_dict.num_family_other_blues; - *data = (FT_Pos*) + *data = (FT_Fixed*) &decoder->current_subfont->private_dict.family_other_blues; } @@ -697,7 +695,7 @@ FT_ASSERT( charstring + len >= charstring ); buf->start = charstring; - buf->end = charstring + len; + buf->end = FT_OFFSET( charstring, len ); buf->ptr = buf->start; return FT_Err_Ok; @@ -742,13 +740,13 @@ /* For ordinary fonts get the character data stored in the face record. */ { glyph_data.pointer = type1->charstrings[glyph_index]; - glyph_data.length = (FT_Int)type1->charstrings_len[glyph_index]; + glyph_data.length = type1->charstrings_len[glyph_index]; } if ( !error ) { FT_Byte* charstring_base = (FT_Byte*)glyph_data.pointer; - FT_ULong charstring_len = (FT_ULong)glyph_data.length; + FT_ULong charstring_len = glyph_data.length; FT_ASSERT( charstring_base + charstring_len >= charstring_base ); @@ -778,7 +776,7 @@ face = (T1_Face)decoder->builder.face; data.pointer = buf->start; - data.length = (FT_Int)( buf->end - buf->start ); + data.length = (FT_UInt)( buf->end - buf->start ); if ( face->root.internal->incremental_interface ) face->root.internal->incremental_interface->funcs->free_glyph_data( @@ -820,7 +818,7 @@ /* The CID driver stores subroutines with seed bytes. This */ /* case is taken care of when decoder->subrs_len == 0. */ if ( decoder->locals_len ) - buf->end = buf->start + decoder->locals_len[idx]; + buf->end = FT_OFFSET( buf->start, decoder->locals_len[idx] ); else { /* We are using subroutines from a CID font. We must adjust */ diff --git a/src/thirdparty/freetype2/src/psaux/psft.h b/src/thirdparty/freetype2/src/psaux/psft.h index 4c930f0d7..d9082f3a2 100644 --- a/src/thirdparty/freetype2/src/psaux/psft.h +++ b/src/thirdparty/freetype2/src/psaux/psft.h @@ -40,17 +40,17 @@ #define PSFT_H_ +#include #include "pstypes.h" - /* TODO: disable asserts for now */ #define CF2_NDEBUG -#include FT_SYSTEM_H +#include #include "psglue.h" -#include FT_INTERNAL_POSTSCRIPT_AUX_H /* for PS_Decoder */ +#include /* for PS_Decoder */ FT_BEGIN_HEADER @@ -92,19 +92,19 @@ FT_BEGIN_HEADER FT_LOCAL( void ) cf2_getBlueValues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getFamilyBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( void ) cf2_getFamilyOtherBlues( PS_Decoder* decoder, size_t* count, - FT_Pos* *data ); + FT_Fixed* *data ); FT_LOCAL( CF2_Int ) cf2_getLanguageGroup( PS_Decoder* decoder ); diff --git a/src/thirdparty/freetype2/src/psaux/psglue.h b/src/thirdparty/freetype2/src/psaux/psglue.h index 022aafbfc..63085d71c 100644 --- a/src/thirdparty/freetype2/src/psaux/psglue.h +++ b/src/thirdparty/freetype2/src/psaux/psglue.h @@ -72,7 +72,7 @@ FT_BEGIN_HEADER } CF2_PathOp; - /* a matrix of fixed point values */ + /* a matrix of fixed-point values */ typedef struct CF2_Matrix_ { CF2_F16Dot16 a; diff --git a/src/thirdparty/freetype2/src/psaux/pshints.c b/src/thirdparty/freetype2/src/psaux/pshints.c index 1cbecd2b1..7bd08a9c9 100644 --- a/src/thirdparty/freetype2/src/psaux/pshints.c +++ b/src/thirdparty/freetype2/src/psaux/pshints.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psglue.h" #include "psfont.h" @@ -310,7 +310,7 @@ CF2_Hint hint = &hintmap->edge[i]; - FT_TRACE6(( " %3d %7.2f %7.2f %5d %s%s%s%s\n", + FT_TRACE6(( " %3zu %7.2f %7.2f %5d %s%s%s%s\n", hint->index, hint->csCoord / 65536.0, hint->dsCoord / ( hint->scale * 1.0 ), @@ -412,6 +412,12 @@ { FT_Bool isPair = cf2_hint_isPair( &hintmap->edge[i] ); + /* final amount to move edge or edge pair */ + CF2_Fixed move = 0; + + CF2_Fixed dsCoord_i; + CF2_Fixed dsCoord_j; + /* index of upper edge (same value for ghost hint) */ j = isPair ? i + 1 : i; @@ -422,11 +428,14 @@ FT_ASSERT( cf2_hint_isLocked( &hintmap->edge[i] ) == cf2_hint_isLocked( &hintmap->edge[j] ) ); + dsCoord_i = hintmap->edge[i].dsCoord; + dsCoord_j = hintmap->edge[j].dsCoord; + if ( !cf2_hint_isLocked( &hintmap->edge[i] ) ) { /* hint edge is not locked, we can adjust it */ - CF2_Fixed fracDown = cf2_fixedFraction( hintmap->edge[i].dsCoord ); - CF2_Fixed fracUp = cf2_fixedFraction( hintmap->edge[j].dsCoord ); + CF2_Fixed fracDown = cf2_fixedFraction( dsCoord_i ); + CF2_Fixed fracUp = cf2_fixedFraction( dsCoord_j ); /* calculate all four possibilities; moves down are negative */ CF2_Fixed downMoveDown = 0 - fracDown; @@ -443,9 +452,6 @@ /* smallest move down */ CF2_Fixed moveDown = FT_MAX( downMoveDown, upMoveDown ); - /* final amount to move edge or edge pair */ - CF2_Fixed move; - CF2_Fixed downMinCounter = CF2_MIN_COUNTER; CF2_Fixed upMinCounter = CF2_MIN_COUNTER; FT_Bool saveEdge = FALSE; @@ -467,16 +473,14 @@ /* is there room to move up? */ /* there is if we are at top of array or the next edge is at or */ /* beyond proposed move up? */ - if ( j >= hintmap->count - 1 || + if ( j >= hintmap->count - 1 || hintmap->edge[j + 1].dsCoord >= - ADD_INT32( hintmap->edge[j].dsCoord, - moveUp + upMinCounter ) ) + ADD_INT32( dsCoord_j, moveUp + upMinCounter ) ) { /* there is room to move up; is there also room to move down? */ - if ( i == 0 || + if ( i == 0 || hintmap->edge[i - 1].dsCoord <= - ADD_INT32( hintmap->edge[i].dsCoord, - moveDown - downMinCounter ) ) + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) { /* move smaller absolute amount */ move = ( -moveDown < moveUp ) ? moveDown : moveUp; /* optimum */ @@ -487,10 +491,9 @@ else { /* is there room to move down? */ - if ( i == 0 || + if ( i == 0 || hintmap->edge[i - 1].dsCoord <= - ADD_INT32( hintmap->edge[i].dsCoord, - moveDown - downMinCounter ) ) + ADD_INT32( dsCoord_i, moveDown - downMinCounter ) ) { move = moveDown; /* true if non-optimum move */ @@ -524,17 +527,21 @@ } /* move the edge(s) */ - hintmap->edge[i].dsCoord = ADD_INT32( hintmap->edge[i].dsCoord, - move ); + hintmap->edge[i].dsCoord = ADD_INT32( dsCoord_i, move ); if ( isPair ) - hintmap->edge[j].dsCoord = ADD_INT32( hintmap->edge[j].dsCoord, - move ); + hintmap->edge[j].dsCoord = ADD_INT32( dsCoord_j, move ); } - /* assert there are no overlaps in device space */ + /* assert there are no overlaps in device space; */ + /* ignore tests if there was overflow (that is, if */ + /* operands have the same sign but the sum does not) */ FT_ASSERT( i == 0 || + ( ( dsCoord_i ^ move ) >= 0 && + ( dsCoord_i ^ hintmap->edge[i].dsCoord ) < 0 ) || hintmap->edge[i - 1].dsCoord <= hintmap->edge[i].dsCoord ); FT_ASSERT( i < j || + ( ( dsCoord_j ^ move ) >= 0 && + ( dsCoord_j ^ hintmap->edge[j].dsCoord ) < 0 ) || hintmap->edge[i].dsCoord <= hintmap->edge[j].dsCoord ); /* adjust the scales, avoiding divide by zero */ @@ -686,8 +693,10 @@ CF2_Fixed midpoint = cf2_hintmap_map( hintmap->initialHintMap, - ADD_INT32( secondHintEdge->csCoord, - firstHintEdge->csCoord ) / 2 ); + ADD_INT32( + firstHintEdge->csCoord, + SUB_INT32 ( secondHintEdge->csCoord, + firstHintEdge->csCoord ) / 2 ) ); CF2_Fixed halfWidth = FT_MulFix( SUB_INT32( secondHintEdge->csCoord, firstHintEdge->csCoord ) / 2, @@ -1022,10 +1031,17 @@ } } - FT_TRACE6(( "%s\n", initialMap ? "flags: [p]air [g]host [t]op" - " [b]ottom [L]ocked [S]ynthetic\n" - "Initial hintmap" - : "Hints:" )); +#ifdef FT_DEBUG_LEVEL_TRACE + if ( initialMap ) + { + FT_TRACE6(( "flags: [p]air [g]host [t]op" + " [b]ottom [L]ocked [S]ynthetic\n" )); + FT_TRACE6(( "Initial hintmap:\n" )); + } + else + FT_TRACE6(( "Hints:\n" )); +#endif + cf2_hintmap_dump( hintmap ); /* @@ -1040,7 +1056,7 @@ /* adjust positions of hint edges that are not locked to blue zones */ cf2_hintmap_adjustHints( hintmap ); - FT_TRACE6(( "(adjusted)\n" )); + FT_TRACE6(( "Hints adjusted:\n" )); cf2_hintmap_dump( hintmap ); /* save the position of all hints that were used in this hint map; */ diff --git a/src/thirdparty/freetype2/src/psaux/psintrp.c b/src/thirdparty/freetype2/src/psaux/psintrp.c index e2f3accdd..7e3475e6f 100644 --- a/src/thirdparty/freetype2/src/psaux/psintrp.c +++ b/src/thirdparty/freetype2/src/psaux/psintrp.c @@ -37,8 +37,9 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H -#include FT_SERVICE_CFF_TABLE_LOAD_H +#include +#include +#include #include "psglue.h" #include "psfont.h" @@ -428,6 +429,8 @@ base = cf2_stack_count( opStack ) - numOperands; delta = base + numBlends; + FT_TRACE6(( " (" )); + for ( i = 0; i < numBlends; i++ ) { const CF2_Fixed* weight = &blend->BV[1]; @@ -442,10 +445,14 @@ cf2_stack_getReal( opStack, delta++ ) ) ); + FT_TRACE6(( "%f ", (double)sum / 65536 )); + /* store blended result */ cf2_stack_setReal( opStack, i + base, sum ); } + FT_TRACE6(( "blended)\n" )); + /* leave only `numBlends' results on stack */ cf2_stack_pop( opStack, numOperands - numBlends ); } @@ -469,7 +476,7 @@ */ FT_LOCAL_DEF( void ) cf2_interpT2CharString( CF2_Font font, - CF2_Buffer buf, + const CF2_Buffer buf, CF2_OutlineCallbacks callbacks, const FT_Vector* translation, FT_Bool doingSeac, @@ -611,7 +618,7 @@ /* Our copy of it does not change that requirement. */ cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 ); - charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); + charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack ); /* catch errors so far */ if ( *error ) @@ -734,7 +741,7 @@ FT_UInt numBlends; - FT_TRACE4(( " blend\n" )); + FT_TRACE4(( " blend" )); if ( !font->isCFF2 ) break; /* clear stack & ignore */ @@ -1340,9 +1347,9 @@ if ( decoder->glyph_names == 0 ) #endif /* FT_CONFIG_OPTION_INCREMENTAL */ { - FT_ERROR(( - "cf2_interpT2CharString: (Type 1 seac)" - " glyph names table not available in this font\n" )); + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) glyph names table" + " not available in this font\n" )); lastError = FT_THROW( Invalid_Glyph_Format ); goto exit; } @@ -1368,9 +1375,9 @@ if ( bchar_index < 0 || achar_index < 0 ) { - FT_ERROR(( - "cf2_interpT2CharString: (Type 1 seac)" - " invalid seac character code arguments\n" )); + FT_ERROR(( "cf2_interpT2CharString:\n" )); + FT_ERROR(( " (Type 1 seac) invalid" + " seac character code arguments\n" )); lastError = FT_THROW( Invalid_Glyph_Format ); goto exit; } @@ -1433,6 +1440,13 @@ lastError = error2; /* pass FreeType error through */ goto exit; } + + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + cf2_interpT2CharString( font, &component, callbacks, @@ -1443,11 +1457,14 @@ &dummyWidth ); cf2_freeT1SeacComponent( decoder, &component ); - /* save the left bearing and width of the base */ - /* character as they will be erased by the next load */ + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ - left_bearing = *decoder->builder.left_bearing; - advance = *decoder->builder.advance; + if ( !haveWidth ) + { + left_bearing = *decoder->builder.left_bearing; + advance = *decoder->builder.advance; + } decoder->builder.left_bearing->x = 0; decoder->builder.left_bearing->y = 0; @@ -1473,8 +1490,8 @@ &dummyWidth ); cf2_freeT1SeacComponent( decoder, &component ); - /* restore the left side bearing and */ - /* advance width of the base character */ + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ *decoder->builder.left_bearing = left_bearing; *decoder->builder.advance = advance; @@ -1660,7 +1677,13 @@ */ count = cf2_stack_count( opStack ); - FT_ASSERT( (CF2_UInt)arg_cnt <= count ); + if ( (CF2_UInt)arg_cnt > count ) + { + FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" + " stack underflow\n" )); + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } opIdx += count - (CF2_UInt)arg_cnt; @@ -1883,24 +1906,25 @@ /* cvi( ) of BuildCharArray with */ /* WeightVector */ { - FT_Int idx; - PS_Blend blend = decoder->blend; + FT_UInt idx; + PS_Blend blend = decoder->blend; + FT_UInt len_buildchar = decoder->len_buildchar; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (FT_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx + blend->num_designs > - decoder->len_buildchar ) + if ( len_buildchar < blend->num_designs || + len_buildchar - blend->num_designs < idx ) goto Unexpected_OtherSubr; - ft_memcpy( &decoder->buildchar[idx], - blend->weight_vector, - blend->num_designs * - sizeof ( blend->weight_vector[0] ) ); + if ( decoder->buildchar && blend->weight_vector ) + ft_memcpy( &decoder->buildchar[idx], + blend->weight_vector, + blend->num_designs * + sizeof ( blend->weight_vector[0] ) ); } break; @@ -1994,17 +2018,16 @@ /* 2 24 callothersubr */ /* ==> set BuildCharArray[cvi( )] = */ { - CF2_Int idx; + CF2_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 2 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; decoder->buildchar[idx] = @@ -2017,17 +2040,16 @@ /* ==> push BuildCharArray[cvi( idx )] */ /* onto T1 stack */ { - CF2_Int idx; + CF2_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx < 0 || - (FT_UInt)idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; cf2_stack_pushFixed( opStack, @@ -2169,29 +2191,29 @@ case cf2_escPUT: { CF2_F16Dot16 val; - CF2_Int idx; + CF2_UInt idx; FT_TRACE4(( " put\n" )); - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); val = cf2_stack_popFixed( opStack ); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + if ( idx < CF2_STORAGE_SIZE ) storage[idx] = val; } continue; /* do not clear the stack */ case cf2_escGET: { - CF2_Int idx; + CF2_UInt idx; FT_TRACE4(( " get\n" )); - idx = cf2_stack_popInt( opStack ); + idx = (CF2_UInt)cf2_stack_popInt( opStack ); - if ( idx >= 0 && idx < CF2_STORAGE_SIZE ) + if ( idx < CF2_STORAGE_SIZE ) cf2_stack_pushFixed( opStack, storage[idx] ); } continue; /* do not clear the stack */ @@ -2260,23 +2282,7 @@ arg = cf2_stack_popFixed( opStack ); if ( arg > 0 ) - { - /* use a start value that doesn't make */ - /* the algorithm's addition overflow */ - FT_Fixed root = arg < 10 ? arg : arg >> 1; - FT_Fixed new_root; - - - /* Babylonian method */ - for (;;) - { - new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1; - if ( new_root == root ) - break; - root = new_root; - } - arg = new_root; - } + arg = (CF2_F16Dot16)FT_SqrtFixed( (FT_UInt32)arg ); else arg = 0; diff --git a/src/thirdparty/freetype2/src/psaux/psintrp.h b/src/thirdparty/freetype2/src/psaux/psintrp.h index 669c09c0a..d8b9342ec 100644 --- a/src/thirdparty/freetype2/src/psaux/psintrp.h +++ b/src/thirdparty/freetype2/src/psaux/psintrp.h @@ -65,7 +65,7 @@ FT_BEGIN_HEADER FT_LOCAL( void ) cf2_interpT2CharString( CF2_Font font, - CF2_Buffer charstring, + const CF2_Buffer buf, CF2_OutlineCallbacks callbacks, const FT_Vector* translation, FT_Bool doingSeac, diff --git a/src/thirdparty/freetype2/src/psaux/psobjs.c b/src/thirdparty/freetype2/src/psaux/psobjs.c index 8bfdb9233..8159fd6ef 100644 --- a/src/thirdparty/freetype2/src/psaux/psobjs.c +++ b/src/thirdparty/freetype2/src/psaux/psobjs.c @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,14 +16,14 @@ */ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H -#include FT_DRIVER_H +#include +#include +#include +#include #include "psobjs.h" #include "psconv.h" +#include "psft.h" #include "psauxerr.h" #include "psauxmod.h" @@ -85,7 +85,6 @@ table->max_elems = count; table->init = 0xDEADBEEFUL; - table->num_elems = 0; table->block = NULL; table->capacity = 0; table->cursor = 0; @@ -100,45 +99,31 @@ } - 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_Offset new_size ) + ps_table_realloc( PS_Table table, + FT_Offset 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; + /* (re)allocate the base block */ + if ( FT_REALLOC( table->block, table->capacity, new_size ) ) return error; - } - /* copy elements and shift offsets */ - if ( old_base ) + /* rebase offsets if necessary */ + if ( old_base && table->block != old_base ) { - FT_MEM_COPY( table->block, old_base, table->capacity ); - shift_elements( table, old_base ); - FT_FREE( old_base ); + FT_Byte** offset = table->elements; + FT_Byte** limit = offset + table->max_elems; + + + for ( ; offset < limit; offset++ ) + { + if ( *offset ) + *offset = table->block + ( *offset - old_base ); + } } table->capacity = new_size; @@ -205,7 +190,7 @@ new_size = FT_PAD_CEIL( new_size, 1024 ); } - error = reallocate_t1_table( table, new_size ); + error = ps_table_realloc( table, new_size ); if ( error ) return error; @@ -214,9 +199,11 @@ } /* add the object to the base block and adjust offset */ - table->elements[idx] = table->block + table->cursor; + table->elements[idx] = FT_OFFSET( table->block, table->cursor ); table->lengths [idx] = length; - FT_MEM_COPY( table->block + table->cursor, object, length ); + /* length == 0 also implies a NULL destination, so skip the copy call */ + if ( length > 0 ) + FT_MEM_COPY( table->block + table->cursor, object, length ); table->cursor += length; return FT_Err_Ok; @@ -235,32 +222,12 @@ * @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 ); + /* no problem if shrinking fails */ + ps_table_realloc( table, table->cursor ); } @@ -270,7 +237,7 @@ FT_Memory memory = table->memory; - if ( (FT_ULong)table->init == 0xDEADBEEFUL ) + if ( table->init == 0xDEADBEEFUL ) { FT_FREE( table->block ); FT_FREE( table->elements ); @@ -493,6 +460,9 @@ case '%': skip_comment( &cur, limit ); break; + + default: + break; } } @@ -553,7 +523,7 @@ if ( *cur == '<' ) /* <...> */ { - if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ + if ( cur + 1 < limit && *( cur + 1 ) == '<' ) /* << */ { cur++; cur++; @@ -596,10 +566,10 @@ if ( cur < limit && cur == parser->cursor ) { FT_ERROR(( "ps_parser_skip_PS_token:" - " current token is `%c' which is self-delimiting\n" - " " - " but invalid at this point\n", + " current token is `%c' which is self-delimiting\n", *cur )); + FT_ERROR(( " " + " but invalid at this point\n" )); error = FT_THROW( Invalid_File_Format ); } @@ -980,7 +950,7 @@ } len = (FT_UInt)( cur - *cursor ); - if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) + if ( cur >= limit || FT_QALLOC( result, len + 1 ) ) return 0; /* now copy the string */ @@ -1099,7 +1069,6 @@ { FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; FT_Long val; - FT_String* string = NULL; skip_spaces( &cur, limit ); @@ -1149,8 +1118,9 @@ case T1_FIELD_TYPE_STRING: case T1_FIELD_TYPE_KEY: { - FT_Memory memory = parser->memory; - FT_UInt len = (FT_UInt)( limit - cur ); + FT_Memory memory = parser->memory; + FT_UInt len = (FT_UInt)( limit - cur ); + FT_String* string = NULL; if ( cur >= limit ) @@ -1176,9 +1146,9 @@ else { FT_ERROR(( "ps_parser_load_field:" - " expected a name or string\n" - " " - " but found token of type %d instead\n", + " expected a name or string\n" )); + FT_ERROR(( " " + " but found token of type %u instead\n", token.type )); error = FT_THROW( Invalid_File_Format ); goto Exit; @@ -1191,10 +1161,9 @@ 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 ) ) + if ( FT_QALLOC( string, len + 1 ) ) goto Exit; FT_MEM_COPY( string, cur, len ); @@ -1233,7 +1202,7 @@ bbox->xMax = FT_RoundFix( temp[2] ); bbox->yMax = FT_RoundFix( temp[3] ); - FT_TRACE4(( " [%d %d %d %d]", + FT_TRACE4(( " [%ld %ld %ld %ld]", bbox->xMin / 65536, bbox->yMin / 65536, bbox->xMax / 65536, @@ -1249,7 +1218,7 @@ FT_UInt i; - if ( FT_NEW_ARRAY( temp, max_objects * 4 ) ) + if ( FT_QNEW_ARRAY( temp, max_objects * 4 ) ) goto Exit; for ( i = 0; i < 4; i++ ) @@ -1259,14 +1228,14 @@ if ( result < 0 || (FT_UInt)result < max_objects ) { FT_ERROR(( "ps_parser_load_field:" - " expected %d integer%s in the %s subarray\n" - " " - " of /FontBBox in the /Blend dictionary\n", + " expected %u integer%s in the %s subarray\n", max_objects, max_objects > 1 ? "s" : "", i == 0 ? "first" : ( i == 1 ? "second" : ( i == 2 ? "third" : "fourth" ) ) )); + FT_ERROR(( " " + " of /FontBBox in the /Blend dictionary\n" )); error = FT_THROW( Invalid_File_Format ); FT_FREE( temp ); @@ -1287,7 +1256,7 @@ bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] ); bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] ); - FT_TRACE4(( " [%d %d %d %d]", + FT_TRACE4(( " [%ld %ld %ld %ld]", bbox->xMin / 65536, bbox->yMin / 65536, bbox->xMax / 65536, @@ -1661,7 +1630,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; point->x = FIXED_TO_INT( x ); @@ -1714,8 +1683,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -1777,7 +1745,7 @@ { 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; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -1797,8 +1765,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -1936,7 +1903,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); @@ -1996,8 +1963,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -2056,7 +2022,7 @@ { 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; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -2076,8 +2042,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -2225,7 +2190,7 @@ if ( builder->load_points ) { FT_Vector* point = outline->points + outline->n_points; - FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; + FT_Byte* control = outline->tags + outline->n_points; #ifdef CFF_CONFIG_OPTION_OLD_ENGINE PS_Driver driver = (PS_Driver)FT_FACE_DRIVER( builder->face ); @@ -2304,8 +2269,7 @@ if ( !error ) { if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; outline->n_contours++; } @@ -2364,7 +2328,7 @@ { 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; + FT_Byte* control = outline->tags + outline->n_points - 1; /* `delete' last point only if it coincides with the first */ @@ -2384,8 +2348,7 @@ outline->n_points--; } else - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + outline->contours[outline->n_contours - 1] = outline->n_points - 1; } } @@ -2500,19 +2463,20 @@ count = cpriv->num_blue_values = priv->num_blue_values; for ( n = 0; n < count; n++ ) - cpriv->blue_values[n] = (FT_Pos)priv->blue_values[n]; + cpriv->blue_values[n] = cf2_intToFixed( priv->blue_values[n] ); count = cpriv->num_other_blues = priv->num_other_blues; for ( n = 0; n < count; n++ ) - cpriv->other_blues[n] = (FT_Pos)priv->other_blues[n]; + cpriv->other_blues[n] = cf2_intToFixed( priv->other_blues[n] ); count = cpriv->num_family_blues = priv->num_family_blues; for ( n = 0; n < count; n++ ) - cpriv->family_blues[n] = (FT_Pos)priv->family_blues[n]; + cpriv->family_blues[n] = cf2_intToFixed( priv->family_blues[n] ); count = cpriv->num_family_other_blues = priv->num_family_other_blues; for ( n = 0; n < count; n++ ) - cpriv->family_other_blues[n] = (FT_Pos)priv->family_other_blues[n]; + cpriv->family_other_blues[n] = + cf2_intToFixed( priv->family_other_blues[n] ); cpriv->blue_scale = priv->blue_scale; cpriv->blue_shift = (FT_Pos)priv->blue_shift; @@ -2577,7 +2541,7 @@ FT_UShort seed ) { PS_Conv_EexecDecode( &buffer, - buffer + length, + FT_OFFSET( buffer, length ), buffer, length, &seed ); diff --git a/src/thirdparty/freetype2/src/psaux/psobjs.h b/src/thirdparty/freetype2/src/psaux/psobjs.h index c44dc450e..277aa1247 100644 --- a/src/thirdparty/freetype2/src/psaux/psobjs.h +++ b/src/thirdparty/freetype2/src/psaux/psobjs.h @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define PSOBJS_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_CFF_OBJECTS_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/psread.c b/src/thirdparty/freetype2/src/psaux/psread.c index 86bfc03c6..7f657f2cd 100644 --- a/src/thirdparty/freetype2/src/psaux/psread.c +++ b/src/thirdparty/freetype2/src/psaux/psread.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psglue.h" diff --git a/src/thirdparty/freetype2/src/psaux/psstack.c b/src/thirdparty/freetype2/src/psaux/psstack.c index 665906800..797486588 100644 --- a/src/thirdparty/freetype2/src/psaux/psstack.c +++ b/src/thirdparty/freetype2/src/psaux/psstack.c @@ -37,7 +37,7 @@ #include "psft.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psglue.h" #include "psfont.h" @@ -54,20 +54,18 @@ FT_Error* e, FT_UInt stackSize ) { - FT_Error error = FT_Err_Ok; /* for FT_NEW */ - + FT_Error error; /* for FT_QNEW */ CF2_Stack stack = NULL; - if ( !FT_NEW( stack ) ) - { - /* initialize the structure; FT_NEW zeroes it */ - stack->memory = memory; - stack->error = e; - } + if ( FT_QNEW( stack ) ) + return NULL; + + stack->memory = memory; + stack->error = e; /* allocate the stack buffer */ - if ( FT_NEW_ARRAY( stack->buffer, stackSize ) ) + if ( FT_QNEW_ARRAY( stack->buffer, stackSize ) ) { FT_FREE( stack ); return NULL; diff --git a/src/thirdparty/freetype2/src/psaux/psstack.h b/src/thirdparty/freetype2/src/psaux/psstack.h index 18cd39bc6..907b42400 100644 --- a/src/thirdparty/freetype2/src/psaux/psstack.h +++ b/src/thirdparty/freetype2/src/psaux/psstack.h @@ -39,6 +39,7 @@ #ifndef PSSTACK_H_ #define PSSTACK_H_ +#include FT_BEGIN_HEADER @@ -48,8 +49,8 @@ FT_BEGIN_HEADER { union { - CF2_Fixed r; /* 16.16 fixed point */ - CF2_Frac f; /* 2.30 fixed point (for font matrix) */ + CF2_Fixed r; /* 16.16 fixed-point */ + CF2_Frac f; /* 2.30 fixed-point (for font matrix) */ CF2_Int i; } u; diff --git a/src/thirdparty/freetype2/src/psaux/pstypes.h b/src/thirdparty/freetype2/src/psaux/pstypes.h index 041287e8d..435ef7e1f 100644 --- a/src/thirdparty/freetype2/src/psaux/pstypes.h +++ b/src/thirdparty/freetype2/src/psaux/pstypes.h @@ -39,8 +39,7 @@ #ifndef PSTYPES_H_ #define PSTYPES_H_ -#include -#include FT_FREETYPE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/t1cmap.c b/src/thirdparty/freetype2/src/psaux/t1cmap.c index d62d2d5c8..66493b681 100644 --- a/src/thirdparty/freetype2/src/psaux/t1cmap.c +++ b/src/thirdparty/freetype2/src/psaux/t1cmap.c @@ -4,7 +4,7 @@ * * Type 1 character map support (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -18,7 +18,7 @@ #include "t1cmap.h" -#include FT_INTERNAL_DEBUG_H +#include #include "psauxerr.h" @@ -50,8 +50,11 @@ FT_CALLBACK_DEF( void ) - t1_cmap_std_done( T1_CMapStd cmap ) + t1_cmap_std_done( FT_CMap cmap_ ) /* T1_CMapStd */ { + T1_CMapStd cmap = (T1_CMapStd)cmap_; + + cmap->num_glyphs = 0; cmap->glyph_names = NULL; cmap->sid_to_string = NULL; @@ -60,10 +63,11 @@ FT_CALLBACK_DEF( FT_UInt ) - t1_cmap_std_char_index( T1_CMapStd cmap, - FT_UInt32 char_code ) + t1_cmap_std_char_index( FT_CMap cmap, /* T1_CMapStd */ + FT_UInt32 char_code ) { - FT_UInt result = 0; + T1_CMapStd t1cmap = (T1_CMapStd)cmap; + FT_UInt result = 0; if ( char_code < 256 ) @@ -73,13 +77,13 @@ /* convert character code to Adobe SID string */ - code = cmap->code_to_sid[char_code]; - glyph_name = cmap->sid_to_string( code ); + code = t1cmap->code_to_sid[char_code]; + glyph_name = t1cmap->sid_to_string( code ); /* look for the corresponding glyph name */ - for ( n = 0; n < cmap->num_glyphs; n++ ) + for ( n = 0; n < t1cmap->num_glyphs; n++ ) { - const char* gname = cmap->glyph_names[n]; + const char* gname = t1cmap->glyph_names[n]; if ( gname && gname[0] == glyph_name[0] && @@ -95,9 +99,9 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - t1_cmap_std_char_next( T1_CMapStd cmap, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_std_char_next( FT_CMap cmap, + FT_UInt32 *pchar_code ) { FT_UInt result = 0; FT_UInt32 char_code = *pchar_code + 1; @@ -120,13 +124,14 @@ FT_CALLBACK_DEF( FT_Error ) - t1_cmap_standard_init( T1_CMapStd cmap, + t1_cmap_standard_init( FT_CMap cmap, /* T1_CMapStd */ FT_Pointer pointer ) { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; FT_UNUSED( pointer ); - t1_cmap_std_init( cmap, 0 ); + t1_cmap_std_init( t1cmap, 0 ); return 0; } @@ -150,13 +155,14 @@ FT_CALLBACK_DEF( FT_Error ) - t1_cmap_expert_init( T1_CMapStd cmap, + t1_cmap_expert_init( FT_CMap cmap, /* T1_CMapStd */ FT_Pointer pointer ) { + T1_CMapStd t1cmap = (T1_CMapStd)cmap; FT_UNUSED( pointer ); - t1_cmap_std_init( cmap, 1 ); + t1_cmap_std_init( t1cmap, 1 ); return 0; } @@ -188,20 +194,21 @@ FT_CALLBACK_DEF( FT_Error ) - t1_cmap_custom_init( T1_CMapCustom cmap, - FT_Pointer pointer ) + t1_cmap_custom_init( FT_CMap cmap, /* T1_CMapCustom */ + FT_Pointer pointer ) { - T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); - T1_Encoding encoding = &face->type1.encoding; + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + T1_Encoding encoding = &face->type1.encoding; FT_UNUSED( pointer ); - cmap->first = (FT_UInt)encoding->code_first; - cmap->count = (FT_UInt)encoding->code_last - cmap->first; - cmap->indices = encoding->char_index; + t1cmap->first = (FT_UInt)encoding->code_first; + t1cmap->count = (FT_UInt)encoding->code_last - t1cmap->first; + t1cmap->indices = encoding->char_index; - FT_ASSERT( cmap->indices ); + FT_ASSERT( t1cmap->indices ); FT_ASSERT( encoding->code_first <= encoding->code_last ); return 0; @@ -209,45 +216,50 @@ FT_CALLBACK_DEF( void ) - t1_cmap_custom_done( T1_CMapCustom cmap ) + t1_cmap_custom_done( FT_CMap cmap ) /* T1_CMapCustom */ { - cmap->indices = NULL; - cmap->first = 0; - cmap->count = 0; + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + + + t1cmap->indices = NULL; + t1cmap->first = 0; + t1cmap->count = 0; } FT_CALLBACK_DEF( FT_UInt ) - t1_cmap_custom_char_index( T1_CMapCustom cmap, - FT_UInt32 char_code ) + t1_cmap_custom_char_index( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 char_code ) { - FT_UInt result = 0; + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; - if ( ( char_code >= cmap->first ) && - ( char_code < ( cmap->first + cmap->count ) ) ) - result = cmap->indices[char_code]; + if ( char_code >= t1cmap->first && + char_code < ( t1cmap->first + t1cmap->count ) ) + result = t1cmap->indices[char_code]; return result; } - FT_CALLBACK_DEF( FT_UInt32 ) - t1_cmap_custom_char_next( T1_CMapCustom cmap, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_custom_char_next( FT_CMap cmap, /* T1_CMapCustom */ + FT_UInt32 *pchar_code ) { - FT_UInt result = 0; - FT_UInt32 char_code = *pchar_code; + T1_CMapCustom t1cmap = (T1_CMapCustom)cmap; + FT_UInt result = 0; + FT_UInt32 char_code = *pchar_code; char_code++; - if ( char_code < cmap->first ) - char_code = cmap->first; + if ( char_code < t1cmap->first ) + char_code = t1cmap->first; - for ( ; char_code < ( cmap->first + cmap->count ); char_code++ ) + for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ ) { - result = cmap->indices[char_code]; + result = t1cmap->indices[char_code]; if ( result != 0 ) goto Exit; } @@ -287,20 +299,24 @@ /*************************************************************************/ FT_CALLBACK_DEF( const char * ) - psaux_get_glyph_name( T1_Face face, + psaux_get_glyph_name( void* face_, FT_UInt idx ) { + T1_Face face = (T1_Face)face_; + + return face->type1.glyph_names[idx]; } FT_CALLBACK_DEF( FT_Error ) - t1_cmap_unicode_init( PS_Unicodes unicodes, - FT_Pointer pointer ) + t1_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) { - 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; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; FT_UNUSED( pointer ); @@ -311,17 +327,18 @@ return psnames->unicodes_init( memory, unicodes, (FT_UInt)face->type1.num_glyphs, - (PS_GetGlyphNameFunc)&psaux_get_glyph_name, + &psaux_get_glyph_name, (PS_FreeGlyphNameFunc)NULL, (FT_Pointer)face ); } FT_CALLBACK_DEF( void ) - t1_cmap_unicode_done( PS_Unicodes unicodes ) + t1_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ { - FT_Face face = FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); FT_FREE( unicodes->maps ); @@ -330,23 +347,25 @@ FT_CALLBACK_DEF( FT_UInt ) - t1_cmap_unicode_char_index( PS_Unicodes unicodes, - FT_UInt32 char_code ) + t1_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) { - T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_index( unicodes, char_code ); } - FT_CALLBACK_DEF( FT_UInt32 ) - t1_cmap_unicode_char_next( PS_Unicodes unicodes, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + t1_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) { - T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + T1_Face face = (T1_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_next( unicodes, pchar_code ); diff --git a/src/thirdparty/freetype2/src/psaux/t1cmap.h b/src/thirdparty/freetype2/src/psaux/t1cmap.h index d325e7b5a..114bfbb04 100644 --- a/src/thirdparty/freetype2/src/psaux/t1cmap.h +++ b/src/thirdparty/freetype2/src/psaux/t1cmap.h @@ -4,7 +4,7 @@ * * Type 1 character map support (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,8 @@ #ifndef T1CMAP_H_ #define T1CMAP_H_ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psaux/t1decode.c b/src/thirdparty/freetype2/src/psaux/t1decode.c index c2b3729b5..c3fb343d4 100644 --- a/src/thirdparty/freetype2/src/psaux/t1decode.c +++ b/src/thirdparty/freetype2/src/psaux/t1decode.c @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,20 +16,22 @@ */ -#include -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H -#include FT_INTERNAL_HASH_H -#include FT_OUTLINE_H +#include +#include +#include +#include +#include #include "t1decode.h" #include "psobjs.h" #include "psauxerr.h" + /* ensure proper sign extension */ -#define Fix2Int( f ) ( (FT_Int)(FT_Short)( (f) >> 16 ) ) +#define Fix2Int( f ) ( (FT_Int) (FT_Short)( (f) >> 16 ) ) +#define Fix2UInt( f ) ( (FT_UInt)(FT_Short)( (f) >> 16 ) ) + /************************************************************************** * @@ -367,6 +369,12 @@ FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */ + /* save the left bearing and width of the SEAC */ + /* glyph as they will be erased by the next load */ + + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + /* the seac operator must not be nested */ decoder->seac = TRUE; error = t1_decoder_parse_glyph( decoder, (FT_UInt)bchar_index ); @@ -374,11 +382,14 @@ if ( error ) goto Exit; - /* save the left bearing and width of the base character */ - /* as they will be erased by the next load. */ + /* If the SEAC glyph doesn't have a (H)SBW of its */ + /* own use the values from the base glyph. */ - left_bearing = decoder->builder.left_bearing; - advance = decoder->builder.advance; + if ( decoder->builder.parse_state != T1_Parse_Have_Width ) + { + left_bearing = decoder->builder.left_bearing; + advance = decoder->builder.advance; + } decoder->builder.left_bearing.x = 0; decoder->builder.left_bearing.y = 0; @@ -396,8 +407,8 @@ if ( error ) goto Exit; - /* restore the left side bearing and */ - /* advance width of the base character */ + /* restore the left side bearing and advance width */ + /* of the SEAC glyph or base character (saved above) */ decoder->builder.left_bearing = left_bearing; decoder->builder.advance = advance; @@ -509,7 +520,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( bol ) { - FT_TRACE5(( " (%d)", decoder->top - decoder->stack )); + FT_TRACE5(( " (%td)", decoder->top - decoder->stack )); bol = FALSE; } #endif @@ -650,10 +661,8 @@ if ( value > 32000 || value < -32000 ) { if ( large_int ) - { FT_ERROR(( "t1_decoder_parse_charstrings:" " no `div' after large integer\n" )); - } else large_int = TRUE; } @@ -1019,16 +1028,16 @@ /* 2 24 callothersubr */ /* ==> set BuildCharArray[cvi( )] = */ { - FT_Int idx; + FT_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 2 || !blend ) goto Unexpected_OtherSubr; - idx = Fix2Int( top[1] ); + idx = Fix2UInt( top[1] ); - if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; decoder->buildchar[idx] = top[0]; @@ -1040,16 +1049,16 @@ /* ==> push BuildCharArray[cvi( idx )] */ /* onto T1 stack */ { - FT_Int idx; + FT_UInt idx; PS_Blend blend = decoder->blend; if ( arg_cnt != 1 || !blend ) goto Unexpected_OtherSubr; - idx = Fix2Int( top[0] ); + idx = Fix2UInt( top[0] ); - if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar ) + if ( idx >= decoder->len_buildchar ) goto Unexpected_OtherSubr; top[0] = decoder->buildchar[idx]; @@ -1156,9 +1165,9 @@ if ( top - decoder->stack != num_args ) FT_TRACE0(( "t1_decoder_parse_charstrings:" " too much operands on the stack" - " (seen %d, expected %d)\n", + " (seen %td, expected %d)\n", top - decoder->stack, num_args )); - break; + break; } #endif /* FT_DEBUG_LEVEL_TRACE */ @@ -1203,7 +1212,7 @@ FT_TRACE4(( "BuildCharArray = [ " )); for ( i = 0; i < decoder->len_buildchar; i++ ) - FT_TRACE4(( "%d ", decoder->buildchar[i] )); + FT_TRACE4(( "%ld ", decoder->buildchar[i] )); FT_TRACE4(( "]\n" )); } @@ -1231,8 +1240,8 @@ FT_UNUSED( orig_y ); - /* the `metrics_only' indicates that we only want to compute */ - /* the glyph's metrics (lsb + advance width), not load the */ + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ /* rest of it; so exit immediately */ if ( builder->metrics_only ) { @@ -1266,8 +1275,8 @@ x = ADD_LONG( builder->pos_x, top[0] ); y = ADD_LONG( 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 */ + /* `metrics_only' indicates that we only want to compute the */ + /* glyph's metrics (lsb + advance width) without loading the */ /* rest of it; so exit immediately */ if ( builder->metrics_only ) { @@ -1624,7 +1633,7 @@ default: FT_ERROR(( "t1_decoder_parse_charstrings:" - " unhandled opcode %d\n", op )); + " unhandled opcode %u\n", op )); goto Syntax_Error; } @@ -1644,7 +1653,8 @@ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); Fail: return error; @@ -1690,6 +1700,7 @@ FT_Byte* ip; FT_Byte* limit; T1_Builder builder = &decoder->builder; + FT_Bool large_int; #ifdef FT_DEBUG_LEVEL_TRACE FT_Bool bol = TRUE; @@ -1707,6 +1718,8 @@ limit = zone->limit = charstring_base + charstring_len; ip = zone->cursor = zone->base; + large_int = FALSE; + /* now, execute loop */ while ( ip < limit ) { @@ -1718,7 +1731,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( bol ) { - FT_TRACE5(( " (%d)", decoder->top - decoder->stack )); + FT_TRACE5(( " (%ld)", decoder->top - decoder->stack )); bol = FALSE; } #endif @@ -1740,8 +1753,6 @@ case 7: case 8: case 9: - case 10: - case 11: case 14: case 15: case 21: @@ -1750,6 +1761,13 @@ case 31: goto No_Width; + case 10: + op = op_callsubr; + break; + case 11: + op = op_return; + break; + case 13: op = op_hsbw; break; @@ -1767,6 +1785,9 @@ case 7: op = op_sbw; break; + case 12: + op = op_div; + break; default: goto No_Width; @@ -1796,13 +1817,19 @@ /* anyway. */ if ( value > 32000 || value < -32000 ) { - FT_ERROR(( "t1_decoder_parse_metrics:" - " large integer found for width\n" )); - goto Syntax_Error; + if ( large_int ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + else + large_int = TRUE; } else { - value = (FT_Int32)( (FT_UInt32)value << 16 ); + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); } break; @@ -1827,7 +1854,8 @@ value = -( ( ( ip[-2] - 251 ) * 256 ) + ip[-1] + 108 ); } - value = (FT_Int32)( (FT_UInt32)value << 16 ); + if ( !large_int ) + value = (FT_Int32)( (FT_UInt32)value << 16 ); } else { @@ -1837,6 +1865,13 @@ } } + if ( large_int && !( op == op_none || op == op_div ) ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " no `div' after large integer\n" )); + goto Syntax_Error; + } + /********************************************************************** * * Push value on stack, or process operator @@ -1851,6 +1886,9 @@ } #ifdef FT_DEBUG_LEVEL_TRACE + if ( large_int ) + FT_TRACE4(( " %d", value )); + else FT_TRACE4(( " %d", value / 65536 )); #endif @@ -1869,11 +1907,21 @@ #ifdef FT_DEBUG_LEVEL_TRACE - if ( top - decoder->stack != num_args ) - FT_TRACE0(( "t1_decoder_parse_metrics:" - " too much operands on the stack" - " (seen %d, expected %d)\n", - top - decoder->stack, num_args )); + switch ( op ) + { + case op_callsubr: + case op_div: + case op_return: + break; + + default: + if ( top - decoder->stack != num_args ) + FT_TRACE0(( "t1_decoder_parse_metrics:" + " too much operands on the stack" + " (seen %ld, expected %d)\n", + top - decoder->stack, num_args )); + break; + } #endif /* FT_DEBUG_LEVEL_TRACE */ @@ -1893,8 +1941,8 @@ builder->advance.y = 0; /* we only want to compute the glyph's metrics */ - /* (lsb + advance width), not load the rest of */ - /* it; so exit immediately */ + /* (lsb + advance width) without loading the */ + /* rest of it; so exit immediately */ FT_TRACE4(( "\n" )); return FT_Err_Ok; @@ -1912,22 +1960,122 @@ builder->advance.y = top[3]; /* we only want to compute the glyph's metrics */ - /* (lsb + advance width), not load the rest of */ - /* it; so exit immediately */ + /* (lsb + advance width), without loading the */ + /* rest of it; so exit immediately */ FT_TRACE4(( "\n" )); return FT_Err_Ok; + case op_div: + FT_TRACE4(( " div" )); + + /* if `large_int' is set, we divide unscaled numbers; */ + /* otherwise, we divide numbers in 16.16 format -- */ + /* in both cases, it is the same operation */ + *top = FT_DivFix( top[0], top[1] ); + top++; + + large_int = FALSE; + break; + + case op_callsubr: + { + FT_Int idx; + + + FT_TRACE4(( " callsubr" )); + + idx = Fix2Int( top[0] ); + + if ( decoder->subrs_hash ) + { + size_t* val = ft_hash_num_lookup( idx, + decoder->subrs_hash ); + + + if ( val ) + idx = *val; + else + idx = -1; + } + + if ( idx < 0 || idx >= decoder->num_subrs ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " invalid subrs index\n" )); + goto Syntax_Error; + } + + if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " 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_metrics:" + " invoking empty subrs\n" )); + goto Syntax_Error; + } + + decoder->zone = zone; + ip = zone->base; + limit = zone->limit; + break; + } + + case op_return: + FT_TRACE4(( " return" )); + + if ( zone <= decoder->zones ) + { + FT_ERROR(( "t1_decoder_parse_metrics:" + " unexpected return\n" )); + goto Syntax_Error; + } + + zone--; + ip = zone->cursor; + limit = zone->limit; + decoder->zone = zone; + break; + default: FT_ERROR(( "t1_decoder_parse_metrics:" " unhandled opcode %d\n", op )); goto Syntax_Error; } + decoder->top = top; + } /* general operator processing */ } /* while ip < limit */ - FT_TRACE4(( "..end..\n\n" )); + FT_TRACE4(( "..end..\n" )); + FT_TRACE4(( "\n" )); No_Width: FT_ERROR(( "t1_decoder_parse_metrics:" diff --git a/src/thirdparty/freetype2/src/psaux/t1decode.h b/src/thirdparty/freetype2/src/psaux/t1decode.h index 1b5d6263d..7b913f55d 100644 --- a/src/thirdparty/freetype2/src/psaux/t1decode.h +++ b/src/thirdparty/freetype2/src/psaux/t1decode.h @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (specification). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define T1DECODE_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pshinter/pshalgo.c b/src/thirdparty/freetype2/src/pshinter/pshalgo.c index 0c5ae6269..ca3070232 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshalgo.c +++ b/src/thirdparty/freetype2/src/pshinter/pshalgo.c @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (body). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H +#include +#include +#include #include "pshalgo.h" #include "pshnterr.h" @@ -101,7 +100,7 @@ if ( idx >= table->max_hints ) { - FT_TRACE0(( "psh_hint_table_record: invalid hint index %d\n", idx )); + FT_TRACE0(( "psh_hint_table_record: invalid hint index %u\n", idx )); return; } @@ -183,13 +182,13 @@ 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 ) ) + if ( FT_QNEW_ARRAY( table->sort, 2 * count ) || + FT_QNEW_ARRAY( table->hints, count ) || + FT_QNEW_ARRAY( table->zones, 2 * count + 1 ) ) goto Exit; table->max_hints = count; - table->sort_global = table->sort + count; + table->sort_global = FT_OFFSET( table->sort, count ); table->num_hints = 0; table->num_zones = 0; table->zone = NULL; @@ -306,17 +305,18 @@ /* now, sort the hints; they are guaranteed to not overlap */ /* so we can compare their "org_pos" field directly */ { - FT_Int i1, i2; + FT_UInt 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++ ) + for ( i1 = 1; i1 < count; i1++ ) { hint1 = sort[i1]; - for ( i2 = i1 - 1; i2 >= 0; i2-- ) + /* this loop stops when i2 wraps around after reaching 0 */ + for ( i2 = i1 - 1; i2 < i1; i2-- ) { hint2 = sort[i2]; @@ -516,7 +516,7 @@ if ( !psh_hint_is_fitted( parent ) ) psh_hint_align( parent, globals, dimension, glyph ); - /* keep original relation between hints, this is, use the */ + /* keep original relation between hints, that 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 ); @@ -870,7 +870,7 @@ return; } -#endif /* DEBUG_HINTER*/ +#endif /* DEBUG_HINTER */ hint = table->hints; count = table->max_hints; @@ -1050,12 +1050,12 @@ } - static int + static PSH_Dir psh_compute_dir( FT_Pos dx, FT_Pos dy ) { - FT_Pos ax, ay; - int result = PSH_DIR_NONE; + FT_Pos ax, ay; + PSH_Dir result = PSH_DIR_NONE; ax = FT_ABS( dx ); @@ -1118,7 +1118,7 @@ FT_UInt n; PSH_Point point = glyph->points; FT_Vector* vec = glyph->outline->points; - char* tags = glyph->outline->tags; + FT_Byte* tags = glyph->outline->tags; for ( n = 0; n < glyph->num_points; n++ ) @@ -1167,12 +1167,12 @@ 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 ) ) + if ( FT_QNEW_ARRAY( glyph->points, outline->n_points ) || + FT_QNEW_ARRAY( glyph->contours, outline->n_contours ) ) goto Exit; - glyph->num_points = (FT_UInt)outline->n_points; - glyph->num_contours = (FT_UInt)outline->n_contours; + glyph->num_points = outline->n_points; + glyph->num_contours = outline->n_contours; { FT_UInt first = 0, next, n; @@ -1186,7 +1186,7 @@ PSH_Point point; - next = (FT_UInt)outline->contours[n] + 1; + next = outline->contours[n] + 1; count = next - first; contour->start = points + first; @@ -1228,28 +1228,29 @@ FT_Pos dxi, dyi, dxo, dyo; + point->flags = 0; if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) ) - point->flags = PSH_POINT_OFF; + psh_point_set_off( point ); 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 ); + point->dir_in = 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 ); + point->dir_out = psh_compute_dir( dxo, dyo ); /* detect smooth points */ - if ( point->flags & PSH_POINT_OFF ) - point->flags |= PSH_POINT_SMOOTH; + if ( psh_point_is_off( point ) ) + psh_point_set_smooth( point ); 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; + psh_point_set_smooth( point ); } } } @@ -1404,16 +1405,13 @@ } - /* 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. */ - + /* the min and max are based on contour orientation and fill rule */ 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_Dir major_dir ) { PSH_Hint* sort = table->sort; FT_UInt num_hints = table->num_hints; @@ -1421,59 +1419,53 @@ for ( ; count > 0; count--, point++ ) { - FT_Int point_dir = 0; - FT_Pos org_u = point->org_u; + PSH_Dir point_dir; + 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; + point_dir = + (PSH_Dir)( ( point->dir_in | point->dir_out ) & major_dir ); - else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) ) - point_dir = point->dir_out; - - if ( point_dir ) + if ( point_dir & ( PSH_DIR_DOWN | PSH_DIR_RIGHT ) ) { - if ( point_dir == major_dir ) + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) { - FT_UInt nn; + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos; - for ( nn = 0; nn < num_hints; nn++ ) + if ( d < threshold && -d < threshold ) { - 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; - } + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MIN; + point->hint = hint; + break; } } - else if ( point_dir == -major_dir ) + } + else if ( point_dir & ( PSH_DIR_UP | PSH_DIR_LEFT ) ) + { + FT_UInt nn; + + + for ( nn = 0; nn < num_hints; nn++ ) { - FT_UInt nn; + PSH_Hint hint = sort[nn]; + FT_Pos d = org_u - hint->org_pos - hint->org_len; - for ( nn = 0; nn < num_hints; nn++ ) + if ( d < threshold && -d < threshold ) { - 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; - } + psh_point_set_strong( point ); + point->flags2 |= PSH_POINT_EDGE_MAX; + point->hint = hint; + break; } } } @@ -1556,8 +1548,9 @@ /* 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 + /* the maximum shift value in font units tuned to distinguish */ + /* between stems and serifs in URW+ font collection */ +#define PSH_STRONG_THRESHOLD_MAXIMUM 12 /* find strong points in a glyph */ @@ -1572,7 +1565,7 @@ 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 major_dir = ( dimension == 0 ) ? PSH_DIR_VERTICAL : PSH_DIR_HORIZONTAL; PSH_Dimension dim = &glyph->globals->dimension[dimension]; FT_Fixed scale = dim->scale_mult; @@ -1657,8 +1650,8 @@ /* check tangents */ - if ( !PSH_DIR_COMPARE( point->dir_in, PSH_DIR_HORIZONTAL ) && - !PSH_DIR_COMPARE( point->dir_out, PSH_DIR_HORIZONTAL ) ) + if ( !( point->dir_in & PSH_DIR_HORIZONTAL ) && + !( point->dir_out & PSH_DIR_HORIZONTAL ) ) continue; /* skip strong points */ @@ -1806,7 +1799,7 @@ FT_Error error; - if ( FT_NEW_ARRAY( strongs, num_strongs ) ) + if ( FT_QNEW_ARRAY( strongs, num_strongs ) ) return; } @@ -2119,14 +2112,17 @@ FT_Fixed old_x_scale = x_scale; FT_Fixed old_y_scale = y_scale; - FT_Fixed scaled; - FT_Fixed fitted; + FT_Fixed scaled = 0; + FT_Fixed fitted = 0; FT_Bool rescale = FALSE; - scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); - fitted = FT_PIX_ROUND( scaled ); + if ( globals->blues.normal_top.count ) + { + scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale ); + fitted = FT_PIX_ROUND( scaled ); + } if ( fitted != 0 && scaled != fitted ) { diff --git a/src/thirdparty/freetype2/src/pshinter/pshalgo.h b/src/thirdparty/freetype2/src/pshinter/pshalgo.h index 6859e95cd..f4aa85405 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshalgo.h +++ b/src/thirdparty/freetype2/src/pshinter/pshalgo.h @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (specification). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -93,21 +93,17 @@ FT_BEGIN_HEADER typedef struct PSH_PointRec_* PSH_Point; typedef struct PSH_ContourRec_* PSH_Contour; - enum + typedef enum PSH_Dir_ { - PSH_DIR_NONE = 4, - PSH_DIR_UP = -1, - PSH_DIR_DOWN = 1, - PSH_DIR_LEFT = -2, - PSH_DIR_RIGHT = 2 - }; + PSH_DIR_NONE = 0, + PSH_DIR_UP = 1, + PSH_DIR_DOWN = 2, + PSH_DIR_VERTICAL = 1 | 2, + PSH_DIR_LEFT = 4, + PSH_DIR_RIGHT = 8, + PSH_DIR_HORIZONTAL = 4 | 8 -#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 ) + } PSH_Dir; /* the following bit-flags are computed once by the glyph */ @@ -160,8 +156,8 @@ FT_BEGIN_HEADER PSH_Contour contour; FT_UInt flags; FT_UInt flags2; - FT_Char dir_in; - FT_Char dir_out; + PSH_Dir dir_in; + PSH_Dir dir_out; PSH_Hint hint; FT_Pos org_u; FT_Pos org_v; @@ -199,10 +195,6 @@ FT_BEGIN_HEADER 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; diff --git a/src/thirdparty/freetype2/src/pshinter/pshglob.c b/src/thirdparty/freetype2/src/pshinter/pshglob.c index b021e6e42..521a5ff6c 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshglob.c +++ b/src/thirdparty/freetype2/src/pshinter/pshglob.c @@ -5,7 +5,7 @@ * PostScript hinter global hinting management (body). * Inspired by the new auto-hinter module. * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -17,10 +17,9 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_CALC_H +#include +#include +#include #include "pshglob.h" #ifdef DEBUG_HINTER @@ -651,7 +650,7 @@ FT_Error error; - if ( !FT_NEW( globals ) ) + if ( !FT_QNEW( globals ) ) { FT_UInt count; FT_Short* read; diff --git a/src/thirdparty/freetype2/src/pshinter/pshglob.h b/src/thirdparty/freetype2/src/pshinter/pshglob.h index 0049d4c0b..555e99fac 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshglob.h +++ b/src/thirdparty/freetype2/src/pshinter/pshglob.h @@ -4,7 +4,7 @@ * * PostScript hinter global hinting management. * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,8 @@ #define PSHGLOB_H_ -#include FT_FREETYPE_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pshinter/pshmod.c b/src/thirdparty/freetype2/src/pshinter/pshmod.c index 2d36ea2a6..c9f4a94fe 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshmod.c +++ b/src/thirdparty/freetype2/src/pshinter/pshmod.c @@ -4,7 +4,7 @@ * * FreeType PostScript hinter module implementation (body). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,10 @@ */ -#include -#include FT_INTERNAL_OBJECTS_H +#include #include "pshrec.h" #include "pshalgo.h" +#include "pshmod.h" /* the Postscript Hinter module structure */ @@ -37,8 +37,11 @@ /* finalize module */ FT_CALLBACK_DEF( void ) - ps_hinter_done( PS_Hinter_Module module ) + ps_hinter_done( FT_Module module_ ) /* PS_Hinter_Module */ { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + + module->t1_funcs.hints = NULL; module->t2_funcs.hints = NULL; @@ -48,8 +51,10 @@ /* initialize module, create hints recorder and the interface */ FT_CALLBACK_DEF( FT_Error ) - ps_hinter_init( PS_Hinter_Module module ) + ps_hinter_init( FT_Module module_ ) /* PS_Hinter_Module */ { + PS_Hinter_Module module = (PS_Hinter_Module)module_; + FT_Memory memory = module->root.memory; void* ph = &module->ps_hints; diff --git a/src/thirdparty/freetype2/src/pshinter/pshmod.h b/src/thirdparty/freetype2/src/pshinter/pshmod.h index ea8771308..de9c398e9 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshmod.h +++ b/src/thirdparty/freetype2/src/pshinter/pshmod.h @@ -4,7 +4,7 @@ * * PostScript hinter module interface (specification). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define PSHMOD_H_ -#include -#include FT_MODULE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/pshinter/pshnterr.h b/src/thirdparty/freetype2/src/pshinter/pshnterr.h index fb9dbca2b..7076664dd 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshnterr.h +++ b/src/thirdparty/freetype2/src/pshinter/pshnterr.h @@ -4,7 +4,7 @@ * * PS Hinter error codes (specification only). * - * Copyright (C) 2003-2019 by + * Copyright (C) 2003-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef PSHNTERR_H_ #define PSHNTERR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX PSH_Err_ #define FT_ERR_BASE FT_Mod_Err_PShinter -#include FT_ERRORS_H +#include #endif /* PSHNTERR_H_ */ diff --git a/src/thirdparty/freetype2/src/pshinter/pshrec.c b/src/thirdparty/freetype2/src/pshinter/pshrec.c index 9dd09efe4..13754313f 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshrec.c +++ b/src/thirdparty/freetype2/src/pshinter/pshrec.c @@ -4,7 +4,7 @@ * * FreeType PostScript hints recorder (body). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_FREETYPE_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H +#include +#include +#include +#include #include "pshrec.h" #include "pshalgo.h" @@ -64,16 +63,14 @@ { FT_UInt old_max = table->max_hints; FT_UInt new_max = count; - FT_Error error = FT_Err_Ok; + FT_Error error; - 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; - } + /* try to grow the table */ + new_max = FT_PAD_CEIL( new_max, 8 ); + if ( !FT_QRENEW_ARRAY( table->hints, old_max, new_max ) ) + table->max_hints = new_max; + return error; } @@ -91,17 +88,14 @@ count = table->num_hints; count++; - if ( count >= table->max_hints ) + 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; + hint = table->hints + count - 1; /* initialized upstream */ table->num_hints = count; @@ -137,14 +131,15 @@ FT_UInt count, FT_Memory memory ) { - FT_UInt old_max = ( mask->max_bits + 7 ) >> 3; - FT_UInt new_max = ( count + 7 ) >> 3; + FT_UInt old_max = mask->max_bits >> 3; + FT_UInt new_max = ( count + 7 ) >> 3; FT_Error error = FT_Err_Ok; if ( new_max > old_max ) { new_max = FT_PAD_CEIL( new_max, 8 ); + /* added bytes are zeroed here */ if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) ) mask->max_bits = new_max * 8; } @@ -155,31 +150,15 @@ /* test a bit value in a given mask */ static FT_Int ps_mask_test_bit( PS_Mask mask, - FT_Int idx ) + FT_UInt idx ) { - if ( (FT_UInt)idx >= mask->num_bits ) + if ( 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_UInt idx ) - { - FT_Byte* p; - - - if ( 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, @@ -270,6 +249,10 @@ mask = table->masks + count - 1; mask->num_bits = 0; mask->end_point = 0; + /* reused mask must be cleared */ + if ( mask->max_bits ) + FT_MEM_ZERO( mask->bytes, mask->max_bits >> 3 ); + table->num_masks = count; Exit: @@ -427,7 +410,7 @@ PS_Mask mask2 = table->masks + index2; FT_UInt count1 = mask1->num_bits; FT_UInt count2 = mask2->num_bits; - FT_Int delta; + FT_UInt delta; if ( count2 > 0 ) @@ -438,15 +421,14 @@ /* if "count2" is greater than "count1", we need to grow the */ - /* first bitset, and clear the highest bits */ + /* first bitset */ 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 ); + mask1->num_bits = count2; } /* merge (unite) the bitsets */ @@ -468,7 +450,7 @@ mask2->end_point = 0; /* number of masks to move */ - delta = (FT_Int)( table->num_masks - 1 - index2 ); + delta = table->num_masks - 1 - index2; if ( delta > 0 ) { /* move to end of table for reuse */ @@ -477,7 +459,7 @@ ft_memmove( mask2, mask2 + 1, - (FT_UInt)delta * sizeof ( PS_MaskRec ) ); + delta * sizeof ( PS_MaskRec ) ); mask2[delta] = dummy; } @@ -485,7 +467,7 @@ table->num_masks--; } else - FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n", + FT_TRACE0(( "ps_mask_table_merge: ignoring invalid indices (%u,%u)\n", index1, index2 )); Exit: @@ -500,23 +482,18 @@ ps_mask_table_merge_all( PS_Mask_Table table, FT_Memory memory ) { - FT_Int index1, index2; + FT_UInt index1, index2; FT_Error error = FT_Err_Ok; - /* both loops go down to 0, thus FT_Int for index1 and index2 */ - for ( index1 = (FT_Int)table->num_masks - 1; index1 > 0; index1-- ) + /* the loops stop when unsigned indices wrap around after 0 */ + for ( index1 = table->num_masks - 1; index1 < table->num_masks; index1-- ) { - for ( index2 = index1 - 1; index2 >= 0; index2-- ) + for ( index2 = index1 - 1; index2 < index1; index2-- ) { - if ( ps_mask_table_test_intersect( table, - (FT_UInt)index1, - (FT_UInt)index2 ) ) + if ( ps_mask_table_test_intersect( table, index1, index2 ) ) { - error = ps_mask_table_merge( table, - (FT_UInt)index2, - (FT_UInt)index1, - memory ); + error = ps_mask_table_merge( table, index2, index1, memory ); if ( error ) goto Exit; @@ -653,7 +630,7 @@ FT_Int pos, FT_Int len, FT_Memory memory, - FT_Int *aindex ) + FT_UInt *aindex ) { FT_Error error = FT_Err_Ok; FT_UInt flags = 0; @@ -671,9 +648,6 @@ len = 0; } - if ( aindex ) - *aindex = -1; - /* now, lookup stem in the current hints table */ { PS_Mask mask; @@ -710,7 +684,7 @@ goto Exit; if ( aindex ) - *aindex = (FT_Int)idx; + *aindex = idx; } Exit: @@ -721,9 +695,9 @@ /* 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_UInt hint1, + FT_UInt hint2, + FT_UInt hint3, FT_Memory memory ) { FT_Error error = FT_Err_Ok; @@ -750,26 +724,17 @@ } /* now, set the bits for our hints in the counter mask */ - if ( hint1 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint1, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint1, memory ); + if ( error ) + goto Exit; - if ( hint2 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint2, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint2, memory ); + if ( error ) + goto Exit; - if ( hint3 >= 0 ) - { - error = ps_mask_set_bit( counter, (FT_UInt)hint3, memory ); - if ( error ) - goto Exit; - } + error = ps_mask_set_bit( counter, hint3, memory ); + if ( error ) + goto Exit; Exit: return error; @@ -800,7 +765,7 @@ /* destroy hints */ - FT_LOCAL( void ) + FT_LOCAL_DEF( void ) ps_hints_done( PS_Hints hints ) { FT_Memory memory = hints->memory; @@ -814,7 +779,7 @@ } - FT_LOCAL( void ) + FT_LOCAL_DEF( void ) ps_hints_init( PS_Hints hints, FT_Memory memory ) { @@ -841,7 +806,7 @@ ps_hints_stem( PS_Hints hints, FT_UInt dimension, FT_Int count, - FT_Long* stems ) + FT_Pos* stems ) { PS_Dimension dim; @@ -852,7 +817,7 @@ /* limit "dimension" to 0..1 */ if ( dimension > 1 ) { - FT_TRACE0(( "ps_hints_stem: invalid dimension (%d) used\n", + FT_TRACE0(( "ps_hints_stem: invalid dimension (%u) used\n", dimension )); dimension = ( dimension != 0 ); } @@ -875,7 +840,7 @@ if ( error ) { FT_ERROR(( "ps_hints_stem: could not add stem" - " (%d,%d) to hints table\n", stems[0], stems[1] )); + " (%ld,%ld) to hints table\n", stems[0], stems[1] )); hints->error = error; return; @@ -886,10 +851,11 @@ /* add one Type1 counter stem to the current hints table */ static void - ps_hints_t1stem3( PS_Hints hints, + ps_hints_t1stem3( T1_Hints hints_, /* PS_Hints */ FT_UInt dimension, FT_Fixed* stems ) { + PS_Hints hints = (PS_Hints)hints_; FT_Error error = FT_Err_Ok; @@ -898,13 +864,13 @@ PS_Dimension dim; FT_Memory memory = hints->memory; FT_Int count; - FT_Int idx[3]; + FT_UInt idx[3]; /* limit "dimension" to 0..1 */ if ( dimension > 1 ) { - FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%d) used\n", + FT_TRACE0(( "ps_hints_t1stem3: invalid dimension (%u) used\n", dimension )); dimension = ( dimension != 0 ); } @@ -949,9 +915,10 @@ /* reset hints (only with Type 1 hints) */ static void - ps_hints_t1reset( PS_Hints hints, + ps_hints_t1reset( T1_Hints hints_, /* PS_Hints */ FT_UInt end_point ) { + PS_Hints hints = (PS_Hints)hints_; FT_Error error = FT_Err_Ok; @@ -988,11 +955,12 @@ /* Type2 "hintmask" operator, add a new hintmask to each direction */ static void - ps_hints_t2mask( PS_Hints hints, + ps_hints_t2mask( T2_Hints hints_, /* PS_Hints */ FT_UInt end_point, FT_UInt bit_count, const FT_Byte* bytes ) { + PS_Hints hints = (PS_Hints)hints_; FT_Error error; @@ -1008,7 +976,7 @@ if ( bit_count != count1 + count2 ) { FT_TRACE0(( "ps_hints_t2mask:" - " called with invalid bitcount %d (instead of %d)\n", + " called with invalid bitcount %u (instead of %u)\n", bit_count, count1 + count2 )); /* simply ignore the operator */ @@ -1034,10 +1002,11 @@ static void - ps_hints_t2counter( PS_Hints hints, + ps_hints_t2counter( T2_Hints hints_, /* PS_Hints */ FT_UInt bit_count, const FT_Byte* bytes ) { + PS_Hints hints = (PS_Hints)hints_; FT_Error error; @@ -1053,7 +1022,7 @@ if ( bit_count != count1 + count2 ) { FT_TRACE0(( "ps_hints_t2counter:" - " called with invalid bitcount %d (instead of %d)\n", + " called with invalid bitcount %u (instead of %u)\n", bit_count, count1 + count2 )); /* simply ignore the operator */ @@ -1122,6 +1091,13 @@ ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 ); } + static FT_Error + t1_hints_close( T1_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + static void t1_hints_stem( T1_Hints hints, FT_UInt dimension, @@ -1137,17 +1113,27 @@ } + static FT_Error + t1_hints_apply( T1_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + FT_LOCAL_DEF( void ) t1_hints_funcs_init( T1_Hints_FuncsRec* funcs ) { FT_ZERO( funcs ); funcs->open = (T1_Hints_OpenFunc) t1_hints_open; - funcs->close = (T1_Hints_CloseFunc) ps_hints_close; + funcs->close = (T1_Hints_CloseFunc) t1_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; + funcs->apply = (T1_Hints_ApplyFunc) t1_hints_apply; } @@ -1166,6 +1152,14 @@ } + static FT_Error + t2_hints_close( T2_Hints hints, + FT_UInt end_point ) + { + return ps_hints_close( (PS_Hints)hints, end_point ); + } + + static void t2_hints_stems( T2_Hints hints, FT_UInt dimension, @@ -1203,17 +1197,27 @@ } + static FT_Error + t2_hints_apply( T2_Hints hints, + FT_Outline* outline, + PSH_Globals globals, + FT_Render_Mode hint_mode ) + { + return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode ); + } + + FT_LOCAL_DEF( void ) t2_hints_funcs_init( T2_Hints_FuncsRec* funcs ) { FT_ZERO( 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; + funcs->open = (T2_Hints_OpenFunc) t2_hints_open; + funcs->close = (T2_Hints_CloseFunc) t2_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) t2_hints_apply; } diff --git a/src/thirdparty/freetype2/src/pshinter/pshrec.h b/src/thirdparty/freetype2/src/pshinter/pshrec.h index 02cc2102e..a79069f98 100644 --- a/src/thirdparty/freetype2/src/pshinter/pshrec.h +++ b/src/thirdparty/freetype2/src/pshinter/pshrec.h @@ -4,7 +4,7 @@ * * Postscript (Type1/Type2) hints recorder (specification). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -32,8 +32,7 @@ #define PSHREC_H_ -#include -#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include #include "pshglob.h" diff --git a/src/thirdparty/freetype2/src/psnames/psmodule.c b/src/thirdparty/freetype2/src/psnames/psmodule.c index 0ec440e67..c5d71edad 100644 --- a/src/thirdparty/freetype2/src/psnames/psmodule.c +++ b/src/thirdparty/freetype2/src/psnames/psmodule.c @@ -4,7 +4,7 @@ * * psnames module implementation (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include +#include +#include #include "psmodule.h" @@ -58,7 +57,7 @@ /* the name, as in `A.swash' or `e.final'; in this case, the */ /* VARIANT_BIT is set in the return value. */ /* */ - static FT_UInt32 + FT_CALLBACK_DEF( FT_UInt32 ) ps_unicode_value( const char* glyph_name ) { /* If the name begins with `uni', then the glyph name may be a */ @@ -156,31 +155,30 @@ /* 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; + FT_UInt32 value = 0; + const char* p = glyph_name; - for ( ; *p; p++ ) + for ( ; *p && *p != '.'; p++ ) + ; + + /* now look up the glyph in the Adobe Glyph List; */ + /* `.notdef', `.null' and the empty name are short cut */ + if ( p > glyph_name ) { - if ( *p == '.' && p > glyph_name ) - { - dot = p; - break; - } + value = (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); + + if ( *p == '.' ) + value |= (FT_UInt32)VARIANT_BIT; } - /* now look up the glyph in the Adobe Glyph List */ - if ( !dot ) - return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p ); - else - return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) | - VARIANT_BIT ); + return value; } } /* ft_qsort callback to sort the unicode map */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_uni_maps( const void* a, const void* b ) { @@ -311,7 +309,7 @@ /* Build a table that maps Unicode values to glyph indices. */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) ps_unicodes_init( FT_Memory memory, PS_Unicodes table, FT_UInt num_glyphs, @@ -327,9 +325,8 @@ /* we first allocate the table */ table->num_maps = 0; - table->maps = NULL; - if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) + if ( !FT_QNEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) ) { FT_UInt n; FT_UInt count; @@ -344,7 +341,7 @@ const char* gname = get_glyph_name( glyph_data, n ); - if ( gname ) + if ( gname && *gname ) { ps_check_extra_glyph_name( gname, n, extra_glyphs, extra_glyph_list_states ); @@ -392,9 +389,9 @@ /* Reallocate if the number of used entries is much smaller. */ if ( count < num_glyphs / 2 ) { - (void)FT_RENEW_ARRAY( table->maps, - num_glyphs + EXTRA_GLYPH_LIST_SIZE, - count ); + FT_MEM_QRENEW_ARRAY( table->maps, + num_glyphs + EXTRA_GLYPH_LIST_SIZE, + count ); error = FT_Err_Ok; } @@ -411,25 +408,22 @@ } - static FT_UInt + FT_CALLBACK_DEF( FT_UInt ) ps_unicodes_char_index( PS_Unicodes table, FT_UInt32 unicode ) { - PS_UniMap *min, *max, *mid, *result = NULL; + PS_UniMap *result = NULL; + PS_UniMap *min = table->maps; + PS_UniMap *max = min + table->num_maps; + PS_UniMap *mid = min + ( ( max - min ) >> 1 ); /* Perform a binary search on the table. */ - - min = table->maps; - max = min + table->num_maps - 1; - - while ( min <= max ) + while ( min < max ) { FT_UInt32 base_glyph; - mid = min + ( ( max - min ) >> 1 ); - if ( mid->unicode == unicode ) { result = mid; @@ -441,13 +435,15 @@ 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; + max = mid; + + /* reasonable prediction in a continuous block */ + mid += unicode - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( ( max - min ) >> 1 ); } if ( result ) @@ -457,7 +453,7 @@ } - static FT_UInt32 + FT_CALLBACK_DEF( FT_UInt ) ps_unicodes_char_next( PS_Unicodes table, FT_UInt32 *unicode ) { @@ -468,14 +464,13 @@ { FT_UInt min = 0; FT_UInt max = table->num_maps; - FT_UInt mid; + FT_UInt mid = min + ( ( max - min ) >> 1 ); PS_UniMap* map; FT_UInt32 base_glyph; while ( min < max ) { - mid = min + ( ( max - min ) >> 1 ); map = table->maps + mid; if ( map->unicode == char_code ) @@ -493,6 +488,11 @@ min = mid + 1; else max = mid; + + /* reasonable prediction in a continuous block */ + mid += char_code - base_glyph; + if ( mid >= max || mid < min ) + mid = min + ( max - min ) / 2; } if ( result ) @@ -518,7 +518,7 @@ #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */ - static const char* + FT_CALLBACK_DEF( const char* ) ps_get_macintosh_name( FT_UInt name_index ) { if ( name_index >= FT_NUM_MAC_NAMES ) @@ -528,7 +528,7 @@ } - static const char* + FT_CALLBACK_DEF( const char* ) ps_get_standard_strings( FT_UInt sid ) { if ( sid >= FT_NUM_SID_NAMES ) @@ -543,13 +543,13 @@ FT_DEFINE_SERVICE_PSCMAPSREC( pscmaps_interface, - (PS_Unicode_ValueFunc) ps_unicode_value, /* unicode_value */ - (PS_Unicodes_InitFunc) ps_unicodes_init, /* unicodes_init */ - (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, /* unicodes_char_index */ - (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, /* unicodes_char_next */ + ps_unicode_value, /* PS_Unicode_ValueFunc unicode_value */ + ps_unicodes_init, /* PS_Unicodes_InitFunc unicodes_init */ + ps_unicodes_char_index, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + ps_unicodes_char_next, /* PS_Unicodes_CharNextFunc unicodes_char_next */ - (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */ - (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */ + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ t1_standard_encoding, /* adobe_std_encoding */ t1_expert_encoding /* adobe_expert_encoding */ @@ -560,13 +560,13 @@ FT_DEFINE_SERVICE_PSCMAPSREC( pscmaps_interface, - NULL, /* unicode_value */ - NULL, /* unicodes_init */ - NULL, /* unicodes_char_index */ - NULL, /* unicodes_char_next */ + NULL, /* PS_Unicode_ValueFunc unicode_value */ + NULL, /* PS_Unicodes_InitFunc unicodes_init */ + NULL, /* PS_Unicodes_CharIndexFunc unicodes_char_index */ + NULL, /* PS_Unicodes_CharNextFunc unicodes_char_next */ - (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */ - (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */ + ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */ + ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */ t1_standard_encoding, /* adobe_std_encoding */ t1_expert_encoding /* adobe_expert_encoding */ @@ -612,9 +612,9 @@ PUT_PS_NAMES_SERVICE( (void*)&pscmaps_interface ), /* module specific interface */ - (FT_Module_Constructor)NULL, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) PUT_PS_NAMES_SERVICE( psnames_get_service ) /* get_interface */ + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + PUT_PS_NAMES_SERVICE( psnames_get_service ) /* FT_Module_Requester get_interface */ ) diff --git a/src/thirdparty/freetype2/src/psnames/psmodule.h b/src/thirdparty/freetype2/src/psnames/psmodule.h index 0df9a7d88..482fd0a36 100644 --- a/src/thirdparty/freetype2/src/psnames/psmodule.h +++ b/src/thirdparty/freetype2/src/psnames/psmodule.h @@ -4,7 +4,7 @@ * * High-level psnames module interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define PSMODULE_H_ -#include -#include FT_MODULE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/psnames/psnamerr.h b/src/thirdparty/freetype2/src/psnames/psnamerr.h index 67ab1765d..17987f9cd 100644 --- a/src/thirdparty/freetype2/src/psnames/psnamerr.h +++ b/src/thirdparty/freetype2/src/psnames/psnamerr.h @@ -4,7 +4,7 @@ * * PS names module error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef PSNAMERR_H_ #define PSNAMERR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX PSnames_Err_ #define FT_ERR_BASE FT_Mod_Err_PSnames -#include FT_ERRORS_H +#include #endif /* PSNAMERR_H_ */ diff --git a/src/thirdparty/freetype2/src/psnames/pstables.h b/src/thirdparty/freetype2/src/psnames/pstables.h index c0139bbc6..65ce6c0b4 100644 --- a/src/thirdparty/freetype2/src/psnames/pstables.h +++ b/src/thirdparty/freetype2/src/psnames/pstables.h @@ -4,7 +4,7 @@ * * PostScript glyph names. * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/raster/ftmisc.h b/src/thirdparty/freetype2/src/raster/ftmisc.h index a246569e3..9d97223e9 100644 --- a/src/thirdparty/freetype2/src/raster/ftmisc.h +++ b/src/thirdparty/freetype2/src/raster/ftmisc.h @@ -5,7 +5,7 @@ * Miscellaneous macros for stand-alone rasterizer (specification * only). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -47,11 +47,8 @@ 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 ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(FT_Byte)(var) /* from include/freetype/ftsystem.h */ @@ -95,27 +92,6 @@ #endif - 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; - } - - static FT_Long FT_MulDiv_No_Round( FT_Long a, FT_Long b, diff --git a/src/thirdparty/freetype2/src/raster/ftraster.c b/src/thirdparty/freetype2/src/raster/ftraster.c index 023b6c1ef..807d444e7 100644 --- a/src/thirdparty/freetype2/src/raster/ftraster.c +++ b/src/thirdparty/freetype2/src/raster/ftraster.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -62,10 +62,8 @@ #else /* !STANDALONE_ */ -#include #include "ftraster.h" -#include FT_INTERNAL_CALC_H /* for FT_MulDiv and FT_MulDiv_No_Round */ -#include FT_OUTLINE_H /* for FT_Outline_Get_CBox */ +#include /* for FT_MulDiv_No_Round */ #endif /* !STANDALONE_ */ @@ -116,12 +114,12 @@ * 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: + * Note that, for all generated profiles, the function End_Profile() + * is used to record all their bottom-most scanlines as well as the + * scanline above their 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: * * _ _ _______________________________________ * | | @@ -137,7 +135,7 @@ * optimize performance (see technical note on the sweep below). * * Of course, the raster detects whether the two stacks collide and - * handles the situation properly. + * handles the situation by bisecting the job and restarting. * */ @@ -150,9 +148,6 @@ /*************************************************************************/ /*************************************************************************/ - /* define DEBUG_RASTER if you want to compile a debugging version */ -/* #define DEBUG_RASTER */ - /*************************************************************************/ /*************************************************************************/ @@ -201,12 +196,13 @@ #define FT_THROW( e ) FT_ERR_CAT( Raster_Err_, e ) #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 Raster_Err_Ok 0 +#define Raster_Err_Invalid_Outline -1 +#define Raster_Err_Cannot_Render_Glyph -2 +#define Raster_Err_Invalid_Argument -3 +#define Raster_Err_Raster_Overflow -4 +#define Raster_Err_Raster_Uninitialized -5 +#define Raster_Err_Raster_Negative_Height -6 #define ft_memset memset @@ -226,18 +222,11 @@ #else /* !STANDALONE_ */ -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H /* for FT_TRACE, FT_ERROR, and FT_THROW */ +#include +#include /* for FT_TRACE, FT_ERROR, and FT_THROW */ #include "rasterrs.h" -#define Raster_Err_None FT_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_ */ @@ -262,8 +251,11 @@ /* 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 -#define SMulDiv_No_Round FT_MulDiv_No_Round +#ifdef FT_INT64 +#define SMulDiv( a, b, c ) (Long)( (FT_Int64)(a) * (b) / (c) ) +#else +#define SMulDiv FT_MulDiv_No_Round +#endif /* The rasterizer is a very general purpose component; please leave */ /* the following redefinitions there (you never know your target */ @@ -315,16 +307,6 @@ 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; @@ -337,6 +319,7 @@ #define Flow_Up 0x08U #define Overshoot_Top 0x10U #define Overshoot_Bottom 0x20U +#define Dropout 0x40U /* States of each line, arc, and profile */ @@ -355,41 +338,28 @@ struct TProfile_ { - FT_F26Dot6 X; /* current coordinate during sweep */ PProfile link; /* link to next profile (various purposes) */ - PLong offset; /* start of profile's data in render pool */ + PProfile next; /* next profile in same contour, used */ + /* during drop-out control */ + Int offset; /* bottom or currently scanned array index */ + Int height; /* profile's height in scanlines */ + Int start; /* profile's starting scanline, also use */ + /* as activation counter */ UShort flags; /* Bit 0-2: drop-out mode */ /* Bit 3: profile orientation (up/down) */ /* Bit 4: is top profile? */ /* Bit 5: is bottom profile? */ - Long height; /* profile's height in scanlines */ - Long start; /* profile's starting scanline */ + /* Bit 6: dropout detected */ - Int countL; /* number of lines to step before this */ - /* profile becomes drawable */ - - PProfile next; /* next profile in same contour, used */ - /* during drop-out control */ + FT_F26Dot6 X; /* current coordinate during sweep */ + Long x[1]; /* actually variable array of scanline */ + /* intersections with `height` elements */ }; typedef PProfile TProfileList; typedef PProfile* PProfileList; - /* Simple record used to implement a stack of bands, required */ - /* by the sub-banding mechanism */ - typedef struct black_TBand_ - { - Short y_min; /* band's minimum */ - Short y_max; /* band's maximum */ - - } black_TBand; - - -#define AlignProfileSize \ - ( ( sizeof ( TProfile ) + sizeof ( Alignment ) - 1 ) / sizeof ( Long ) ) - - #undef RAS_ARG #undef RAS_ARGS #undef RAS_VAR @@ -427,15 +397,13 @@ /* prototypes used for sweep function dispatch */ typedef void - Function_Sweep_Init( RAS_ARGS Short* min, - Short* max ); + Function_Sweep_Init( RAS_ARGS Int min, + Int max ); typedef void - Function_Sweep_Span( RAS_ARGS Short y, + Function_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ); + FT_F26Dot6 x2 ); typedef void Function_Sweep_Step( RAS_ARG ); @@ -460,6 +428,10 @@ #define IS_TOP_OVERSHOOT( x ) \ (Bool)( x - FLOOR( x ) >= ras.precision_half ) + /* Smart dropout rounding to find which pixel is closer to span ends. */ + /* To mimic Windows, symmetric cases do not depend on the precision. */ +#define SMART( p, q ) FLOOR( ( (p) + (q) + ras.precision * 63 / 64 ) >> 1 ) + #if FT_RENDER_POOL_SIZE > 2048 #define FT_MAX_BLACK_POOL ( FT_RENDER_POOL_SIZE / sizeof ( Long ) ) #else @@ -477,7 +449,6 @@ Int precision_half; Int precision_scale; Int precision_step; - Int precision_jitter; PLong buff; /* The profiles buffer */ PLong sizeBuff; /* Render pool size */ @@ -486,23 +457,14 @@ FT_Error error; - Int numTurns; /* number of Y-turns in outline */ - - TPoint* arc; /* current Bezier arc pointer */ - - UShort bWidth; /* target bitmap width */ - PByte bOrigin; /* target bitmap bottom-left origin */ + Byte dropOutControl; /* current drop_out control method */ Long lastX, lastY; Long minY, maxY; UShort num_Profs; /* current number of profiles */ + Int numTurns; /* number of Y-turns in outline */ - 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 */ @@ -510,11 +472,13 @@ TStates state; /* rendering state */ - FT_Bitmap target; /* description of target bit/pixmap */ FT_Outline outline; - Long traceOfs; /* current offset in target bitmap */ - Short traceIncr; /* sweep's increment in target bitmap */ + Int bTop; /* target bitmap max line index */ + Int bRight; /* target bitmap rightmost index */ + Int bPitch; /* target bitmap pitch */ + PByte bOrigin; /* target bitmap bottom-left origin */ + PByte bLine; /* target bitmap current line */ /* dispatch variables */ @@ -523,18 +487,6 @@ 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. */ - - TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ - - black_TBand band_stack[16]; /* band stack used for sub-banding */ - Int band_top; /* band stack top */ - }; @@ -592,187 +544,25 @@ * * 256 / (1 << 12) = 0.0625 pixels. * - * `precision_jitter' is an epsilon threshold used in - * `Vertical_Sweep_Span' to deal with small imperfections in the Bezier - * decomposition (after all, we are working with approximations only); - * it avoids switching on additional pixels which would cause artifacts - * otherwise. - * - * The value of `precision_jitter' has been determined heuristically. - * */ if ( High ) { ras.precision_bits = 12; ras.precision_step = 256; - ras.precision_jitter = 30; } 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 >> 1; ras.precision_scale = ras.precision >> Pixel_Bits; } - /************************************************************************** - * - * @Function: - * New_Profile - * - * @Description: - * Create a new profile in the render pool. - * - * @Input: - * aState :: - * The state/orientation of the new profile. - * - * overshoot :: - * Whether the profile's unrounded start position - * differs by at least a half pixel. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow or of incoherent - * profile. - */ - static Bool - New_Profile( RAS_ARGS TStates aState, - Bool overshoot ) - { - if ( !ras.fProfile ) - { - ras.cProfile = (PProfile)ras.top; - ras.fProfile = ras.cProfile; - ras.top += AlignProfileSize; - } - - if ( ras.top >= ras.maxBuff ) - { - ras.error = FT_THROW( Overflow ); - 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; - ras.cProfile->flags = ras.dropOutControl; - - switch ( aState ) - { - case Ascending_State: - ras.cProfile->flags |= Flow_Up; - if ( overshoot ) - ras.cProfile->flags |= Overshoot_Bottom; - - FT_TRACE6(( " new ascending profile = %p\n", ras.cProfile )); - break; - - case Descending_State: - if ( overshoot ) - ras.cProfile->flags |= Overshoot_Top; - FT_TRACE6(( " new descending profile = %p\n", ras.cProfile )); - break; - - default: - FT_ERROR(( "New_Profile: invalid profile direction\n" )); - ras.error = FT_THROW( Invalid ); - return FAILURE; - } - - if ( !ras.gProfile ) - ras.gProfile = ras.cProfile; - - ras.state = aState; - ras.fresh = TRUE; - ras.joint = FALSE; - - return SUCCESS; - } - - - /************************************************************************** - * - * @Function: - * End_Profile - * - * @Description: - * Finalize the current profile. - * - * @Input: - * overshoot :: - * Whether the profile's unrounded end position differs - * by at least a half pixel. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow or incoherency. - */ - static Bool - End_Profile( RAS_ARGS Bool overshoot ) - { - Long h; - - - h = (Long)( ras.top - ras.cProfile->offset ); - - if ( h < 0 ) - { - FT_ERROR(( "End_Profile: negative height encountered\n" )); - ras.error = FT_THROW( Neg_Height ); - return FAILURE; - } - - if ( h > 0 ) - { - PProfile oldProfile; - - - FT_TRACE6(( " ending profile %p, start = %ld, height = %ld\n", - ras.cProfile, ras.cProfile->start, h )); - - ras.cProfile->height = h; - if ( overshoot ) - { - if ( ras.cProfile->flags & Flow_Up ) - ras.cProfile->flags |= Overshoot_Top; - else - ras.cProfile->flags |= Overshoot_Bottom; - } - - oldProfile = ras.cProfile; - 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 = FT_THROW( Overflow ); - return FAILURE; - } - - ras.joint = FALSE; - - return SUCCESS; - } - - /************************************************************************** * * @Function: @@ -789,21 +579,31 @@ * SUCCESS on success. FAILURE in case of overflow. */ static Bool - Insert_Y_Turn( RAS_ARGS Int y ) + Insert_Y_Turns( RAS_ARGS Int y, + Int top ) { - PLong y_turns; - Int n; + Int n = ras.numTurns; + PLong y_turns = ras.maxBuff; - n = ras.numTurns - 1; - y_turns = ras.sizeBuff - ras.numTurns; + /* update top value */ + if ( n == 0 || top > y_turns[n] ) + y_turns[n] = top; /* look for first y value that is <= */ - while ( n >= 0 && y < y_turns[n] ) - n--; + while ( n-- && y < y_turns[n] ) + ; /* if it is <, simply insert it, ignore if == */ - if ( n >= 0 && y > y_turns[n] ) + if ( n < 0 || y > y_turns[n] ) + { + ras.maxBuff--; + if ( ras.maxBuff <= ras.top ) + { + ras.error = FT_THROW( Raster_Overflow ); + return FAILURE; + } + do { Int y2 = (Int)y_turns[n]; @@ -811,18 +611,162 @@ y_turns[n] = y; y = y2; - } while ( --n >= 0 ); + } while ( n-- >= 0 ); - if ( n < 0 ) + ras.numTurns++; + } + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * New_Profile + * + * @Description: + * Create 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 ) + { + Long e; + + + if ( !ras.cProfile || ras.cProfile->height ) { - ras.maxBuff--; - if ( ras.maxBuff <= ras.top ) + ras.cProfile = (PProfile)ras.top; + ras.top = ras.cProfile->x; + + if ( ras.top >= ras.maxBuff ) { - ras.error = FT_THROW( Overflow ); + FT_TRACE1(( "overflow in New_Profile\n" )); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } - ras.numTurns++; - ras.sizeBuff[-ras.numTurns] = y; + + ras.cProfile->height = 0; + } + + ras.cProfile->flags = ras.dropOutControl; + + switch ( aState ) + { + case Ascending_State: + ras.cProfile->flags |= Flow_Up; + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Bottom; + + e = CEILING( ras.lastY ); + break; + + case Descending_State: + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + ras.cProfile->flags |= Overshoot_Top; + + e = FLOOR( ras.lastY ); + break; + + default: + FT_ERROR(( "New_Profile: invalid profile direction\n" )); + ras.error = FT_THROW( Invalid_Outline ); + return FAILURE; + } + + if ( e > ras.maxY ) + e = ras.maxY; + if ( e < ras.minY ) + e = ras.minY; + ras.cProfile->start = (Int)TRUNC( e ); + + FT_TRACE7(( " new %s profile = %p, start = %d\n", + aState == Ascending_State ? "ascending" : "descending", + (void *)ras.cProfile, ras.cProfile->start )); + + if ( ras.lastY == e ) + *ras.top++ = ras.lastX; + + ras.state = aState; + + return SUCCESS; + } + + + /************************************************************************** + * + * @Function: + * End_Profile + * + * @Description: + * Finalize the current profile and record y-turns. + * + * @Return: + * SUCCESS on success. FAILURE in case of overflow or incoherency. + */ + static Bool + End_Profile( RAS_ARG ) + { + PProfile p = ras.cProfile; + Int h = (Int)( ras.top - p->x ); + Int bottom, top; + + + if ( h < 0 ) + { + FT_ERROR(( "End_Profile: negative height encountered\n" )); + ras.error = FT_THROW( Raster_Negative_Height ); + return FAILURE; + } + + if ( h > 0 ) + { + FT_TRACE7(( " ending profile %p, start = %2d, height = %+3d\n", + (void *)p, p->start, p->flags & Flow_Up ? h : -h )); + + p->height = h; + + if ( p->flags & Flow_Up ) + { + if ( IS_TOP_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Top; + + bottom = p->start; + top = bottom + h; + p->offset = 0; + p->X = p->x[0]; + } + else + { + if ( IS_BOTTOM_OVERSHOOT( ras.lastY ) ) + p->flags |= Overshoot_Bottom; + + top = p->start + 1; + bottom = top - h; + p->start = bottom; + p->offset = h - 1; + p->X = p->x[h - 1]; + } + + if ( Insert_Y_Turns( RAS_VARS bottom, top ) ) + return FAILURE; + + if ( !ras.gProfile ) + ras.gProfile = p; + + /* preliminary values to be finalized */ + p->next = ras.gProfile; + p->link = (PProfile)ras.top; + + ras.num_Profs++; } return SUCCESS; @@ -836,56 +780,29 @@ * * @Description: * Adjust all links in the profiles list. - * - * @Return: - * SUCCESS on success. FAILURE in case of overflow. */ - static Bool + static void Finalize_Profile_Table( RAS_ARG ) { - UShort n; - PProfile p; + UShort n = ras.num_Profs; + PProfile p = ras.fProfile; + PProfile q; - n = ras.num_Profs; - p = ras.fProfile; - - if ( n > 1 && p ) + /* there should be at least two profiles, up and down */ + while ( --n ) { - do - { - Int bottom, top; + q = p->link; + /* fix the contour loop */ + if ( q->next == p->next ) + p->next = q; - if ( n > 1 ) - p->link = (PProfile)( p->offset + p->height ); - else - p->link = NULL; - - if ( p->flags & Flow_Up ) - { - bottom = (Int)p->start; - top = (Int)( p->start + p->height - 1 ); - } - else - { - bottom = (Int)( p->start - p->height + 1 ); - top = (Int)p->start; - p->start = bottom; - p->offset += p->height - 1; - } - - if ( Insert_Y_Turn( RAS_VARS bottom ) || - Insert_Y_Turn( RAS_VARS top + 1 ) ) - return FAILURE; - - p = p->link; - } while ( --n ); + p = q; } - else - ras.fProfile = NULL; - return SUCCESS; + /* null-terminate */ + p->link = NULL; } @@ -1015,107 +932,78 @@ Long miny, Long maxy ) { - Long Dx, Dy; - Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */ - Long Ix, Rx, Ax; + Long e, e2, Dx, Dy; + Long Ix, Rx, Ax; + Int size; PLong top; - Dx = x2 - x1; - Dy = y2 - y1; - - if ( Dy <= 0 || y2 < miny || y1 > maxy ) + if ( 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 ); - } + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( 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 ( y1 == e ) + e += ras.precision; - if ( f1 > 0 ) - { - if ( e1 == e2 ) - return SUCCESS; - else - { - x1 += SMulDiv( Dx, ras.precision - f1, Dy ); - e1 += 1; - } - } - else - if ( ras.joint ) - { - ras.top--; - ras.joint = FALSE; - } + if ( e2 < e ) /* nothing to do */ + return SUCCESS; - ras.joint = (char)( f2 == 0 ); + size = (Int)TRUNC( e2 - e ) + 1; + top = ras.top; - if ( ras.fresh ) + if ( top + size >= ras.maxBuff ) { - ras.cProfile->start = e1; - ras.fresh = FALSE; - } - - size = e2 - e1 + 1; - if ( ras.top + size >= ras.maxBuff ) - { - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } - if ( Dx > 0 ) + Dx = x2 - x1; + Dy = y2 - y1; + + if ( Dx == 0 ) /* very easy */ { - Ix = SMulDiv_No_Round( ras.precision, Dx, Dy ); - Rx = ( ras.precision * Dx ) % Dy; + do + *top++ = x1; + while ( --size ); + goto Fin; + } + + Ix = SMulDiv( e - y1, Dx, Dy ); + x1 += Ix; + *top++ = x1; + + if ( --size ) + { + Ax = Dx * ( e - y1 ) - Dy * Ix; /* remainder */ + Ix = SMulDiv( ras.precision, Dx, Dy ); + Rx = Dx * ras.precision - Dy * Ix; /* remainder */ Dx = 1; - } - else - { - Ix = -SMulDiv_No_Round( 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 ) + if ( x2 < x1 ) { - Ax -= Dy; - x1 += Dx; + Ax = -Ax; + Rx = -Rx; + Dx = -Dx; } - size--; + + do + { + x1 += Ix; + Ax += Rx; + if ( Ax >= Dy ) + { + Ax -= Dy; + x1 += Dx; + } + *top++ = x1; + } + while ( --size ); } + Fin: ras.top = top; return SUCCESS; } @@ -1160,17 +1048,7 @@ 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; + return Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny ); } @@ -1205,112 +1083,78 @@ */ static Bool Bezier_Up( RAS_ARGS Int degree, + TPoint* arc, TSplitter splitter, Long miny, Long maxy ) { - Long y1, y2, e, e2, e0; - Short f1; + Long y1, y2, e, e2, dy; + Long dx, x2; - TPoint* arc; - TPoint* start_arc; - - PLong top; + PLong top; - arc = ras.arc; - y1 = arc[degree].y; - y2 = arc[0].y; - top = ras.top; + y1 = arc[degree].y; + y2 = arc[0].y; if ( y2 < miny || y1 > maxy ) - goto Fin; + return SUCCESS; - e2 = FLOOR( y2 ); + e2 = y2 > maxy ? maxy : FLOOR( y2 ); + e = y1 < miny ? miny : CEILING( y1 ); - if ( e2 > maxy ) - e2 = maxy; + if ( y1 == e ) + e += ras.precision; - e0 = miny; + if ( e2 < e ) /* nothing to do */ + return SUCCESS; - 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; + top = ras.top; if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff ) { - ras.top = top; - ras.error = FT_THROW( Overflow ); + ras.error = FT_THROW( Raster_Overflow ); return FAILURE; } - start_arc = arc; - do { - ras.joint = FALSE; - y2 = arc[0].y; + x2 = arc[0].x; if ( y2 > e ) { - y1 = arc[degree].y; - if ( y2 - y1 >= ras.precision_step ) + dy = y2 - arc[degree].y; + dx = x2 - arc[degree].x; + + /* split condition should be invariant of direction */ + if ( dy > ras.precision_step || + dx > ras.precision_step || + -dx > ras.precision_step ) { splitter( arc ); arc += degree; } else { - *top++ = arc[degree].x + FMulDiv( arc[0].x - arc[degree].x, - e - y1, y2 - y1 ); + *top++ = x2 - FMulDiv( y2 - e, dx, dy ); + e += ras.precision; arc -= degree; - e += ras.precision; } } else { if ( y2 == e ) { - ras.joint = TRUE; - *top++ = arc[0].x; - - e += ras.precision; + *top++ = x2; + e += ras.precision; } - arc -= degree; + arc -= degree; } - } while ( arc >= start_arc && e <= e2 ); + } + while ( e <= e2 ); - Fin: - ras.top = top; - ras.arc -= degree; + ras.top = top; return SUCCESS; } @@ -1342,12 +1186,12 @@ */ static Bool Bezier_Down( RAS_ARGS Int degree, + TPoint* arc, TSplitter splitter, Long miny, Long maxy ) { - TPoint* arc = ras.arc; - Bool result, fresh; + Bool result; arc[0].y = -arc[0].y; @@ -1356,12 +1200,7 @@ 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; + result = Bezier_Up( RAS_VARS degree, arc, splitter, -maxy, -miny ); arc[0].y = -arc[0].y; return result; @@ -1393,74 +1232,50 @@ Line_To( RAS_ARGS Long x, Long y ) { + TStates state; + + + if ( y == ras.lastY ) + goto Fin; + /* First, detect a change of direction */ - switch ( ras.state ) + state = ras.lastY < y ? Ascending_State : Descending_State; + + if ( ras.state != state ) { - case Unknown_State: - if ( y > ras.lastY ) - { - if ( New_Profile( RAS_VARS Ascending_State, - IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - else - { - if ( y < ras.lastY ) - if ( New_Profile( RAS_VARS Descending_State, - IS_TOP_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; + /* finalize current profile if any */ + if ( ras.state != Unknown_State && + End_Profile( RAS_VAR ) ) + goto Fail; - case Ascending_State: - if ( y < ras.lastY ) - { - if ( End_Profile( RAS_VARS IS_TOP_OVERSHOOT( ras.lastY ) ) || - New_Profile( RAS_VARS Descending_State, - IS_TOP_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; - - case Descending_State: - if ( y > ras.lastY ) - { - if ( End_Profile( RAS_VARS IS_BOTTOM_OVERSHOOT( ras.lastY ) ) || - New_Profile( RAS_VARS Ascending_State, - IS_BOTTOM_OVERSHOOT( ras.lastY ) ) ) - return FAILURE; - } - break; - - default: - ; + /* create a new profile */ + if ( New_Profile( RAS_VARS state ) ) + goto Fail; } /* Then compute the lines */ - switch ( ras.state ) + if ( state == Ascending_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: + goto Fail; + } + else + { if ( Line_Down( RAS_VARS ras.lastX, ras.lastY, x, y, ras.minY, ras.maxY ) ) - return FAILURE; - break; - - default: - ; + goto Fail; } + Fin: ras.lastX = x; ras.lastY = y; - return SUCCESS; + + Fail: + return FAILURE; } @@ -1499,22 +1314,24 @@ { Long y1, y2, y3, x3, ymin, ymax; TStates state_bez; + TPoint arcs[2 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ - 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; + arc = arcs; + arc[2].x = ras.lastX; + arc[2].y = ras.lastY; + arc[1].x = cx; + arc[1].y = cy; + arc[0].x = x; + 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; + y1 = arc[2].y; + y2 = arc[1].y; + y3 = arc[0].y; + x3 = arc[0].x; /* first, categorize the Bezier arc */ @@ -1529,16 +1346,20 @@ ymax = y1; } - if ( y2 < ymin || y2 > ymax ) + if ( y2 < FLOOR( ymin ) || y2 > CEILING( ymax ) ) { /* this arc has no given direction, split it! */ - Split_Conic( ras.arc ); - ras.arc += 2; + Split_Conic( arc ); + arc += 2; } else if ( y1 == y3 ) { - /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 2; + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ + arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; } else { @@ -1547,36 +1368,34 @@ state_bez = y1 < y3 ? Ascending_State : Descending_State; if ( ras.state != state_bez ) { - Bool o = ( state_bez == Ascending_State ) - ? IS_BOTTOM_OVERSHOOT( y1 ) - : IS_TOP_OVERSHOOT( y1 ); - - /* finalize current profile if any */ if ( ras.state != Unknown_State && - End_Profile( RAS_VARS o ) ) + End_Profile( RAS_VAR ) ) goto Fail; /* create a new profile */ - if ( New_Profile( RAS_VARS state_bez, o ) ) + 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 ) ) + if ( Bezier_Up( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) ) + if ( Bezier_Down( RAS_VARS 2, arc, Split_Conic, + ras.minY, ras.maxY ) ) goto Fail; + arc -= 2; + + ras.lastX = x3; + ras.lastY = y3; } - } while ( ras.arc >= ras.arcs ); - - ras.lastX = x3; - ras.lastY = y3; + } while ( arc >= arcs ); return SUCCESS; @@ -1628,25 +1447,27 @@ { Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2; TStates state_bez; + TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */ + TPoint* arc; /* current Bezier arc pointer */ - 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; + arc = arcs; + arc[3].x = ras.lastX; + arc[3].y = ras.lastY; + arc[2].x = cx1; + arc[2].y = cy1; + arc[1].x = cx2; + arc[1].y = cy2; + arc[0].x = x; + 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; + y1 = arc[3].y; + y2 = arc[2].y; + y3 = arc[1].y; + y4 = arc[0].y; + x4 = arc[0].x; /* first, categorize the Bezier arc */ @@ -1672,53 +1493,55 @@ ymax2 = y2; } - if ( ymin2 < ymin1 || ymax2 > ymax1 ) + if ( ymin2 < FLOOR( ymin1 ) || ymax2 > CEILING( ymax1 ) ) { /* this arc has no given direction, split it! */ - Split_Cubic( ras.arc ); - ras.arc += 3; + Split_Cubic( arc ); + arc += 3; } else if ( y1 == y4 ) { - /* this arc is flat, ignore it and pop it from the Bezier stack */ - ras.arc -= 3; + /* this arc is flat, advance position */ + /* and pop it from the Bezier stack */ + arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; } else { - state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State; + state_bez = y1 < y4 ? Ascending_State : Descending_State; /* detect a change of direction */ if ( ras.state != state_bez ) { - Bool o = ( state_bez == Ascending_State ) - ? IS_BOTTOM_OVERSHOOT( y1 ) - : IS_TOP_OVERSHOOT( y1 ); - - /* finalize current profile if any */ if ( ras.state != Unknown_State && - End_Profile( RAS_VARS o ) ) + End_Profile( RAS_VAR ) ) goto Fail; - if ( New_Profile( RAS_VARS state_bez, o ) ) + 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 ) ) + if ( Bezier_Up( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) goto Fail; } else - if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) ) + if ( Bezier_Down( RAS_VARS 3, arc, Split_Cubic, + ras.minY, ras.maxY ) ) goto Fail; + arc -= 3; + + ras.lastX = x4; + ras.lastY = y4; } - } while ( ras.arc >= ras.arcs ); - - ras.lastX = x4; - ras.lastY = y4; + } while ( arc >= arcs ); return SUCCESS; @@ -1761,11 +1584,16 @@ * * @Return: * SUCCESS on success, FAILURE on error. + * + * @Note: + * Unlike FT_Outline_Decompose(), this function handles the scanmode + * dropout tags in the individual contours. Therefore, it cannot be + * replaced. */ static Bool - Decompose_Curve( RAS_ARGS UShort first, - UShort last, - Int flipped ) + Decompose_Curve( RAS_ARGS Int first, + Int last, + Int flipped ) { FT_Vector v_last; FT_Vector v_control; @@ -1774,7 +1602,7 @@ FT_Vector* points; FT_Vector* point; FT_Vector* limit; - char* tags; + FT_Byte* tags; UInt tag; /* current point's state */ @@ -1963,7 +1791,7 @@ return SUCCESS; Invalid_Outline: - ras.error = FT_THROW( Invalid ); + ras.error = FT_THROW( Invalid_Outline ); Fail: return FAILURE; @@ -1990,69 +1818,55 @@ static Bool Convert_Glyph( RAS_ARGS Int flipped ) { - Int i; - UInt start; + Int i; + Int first, last; ras.fProfile = NULL; - ras.joint = FALSE; - ras.fresh = FALSE; + ras.cProfile = NULL; - ras.maxBuff = ras.sizeBuff - AlignProfileSize; + ras.top = ras.buff; + ras.maxBuff = ras.sizeBuff - 1; /* top reserve */ - ras.numTurns = 0; - - ras.cProfile = (PProfile)ras.top; - ras.cProfile->offset = ras.top; - ras.num_Profs = 0; - - start = 0; + ras.numTurns = 0; + ras.num_Profs = 0; + last = -1; for ( i = 0; i < ras.outline.n_contours; i++ ) { - PProfile lastProfile; - Bool o; - - ras.state = Unknown_State; ras.gProfile = NULL; - if ( Decompose_Curve( RAS_VARS (UShort)start, - (UShort)ras.outline.contours[i], - flipped ) ) + first = last + 1; + last = ras.outline.contours[i]; + + if ( Decompose_Curve( RAS_VARS first, last, flipped ) ) return FAILURE; - start = (UShort)ras.outline.contours[i] + 1; + /* Note that ras.gProfile can stay nil if the contour was */ + /* too small to be drawn or degenerate. */ + if ( !ras.gProfile ) + continue; /* we must now check 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->flags & Flow_Up ) == + if ( ( ras.gProfile->flags & Flow_Up ) == ( ras.cProfile->flags & Flow_Up ) ) ras.top--; - /* Note that ras.gProfile can be nil if the contour was too small */ - /* to be drawn. */ - lastProfile = ras.cProfile; - if ( ras.top != ras.cProfile->offset && - ( ras.cProfile->flags & Flow_Up ) ) - o = IS_TOP_OVERSHOOT( ras.lastY ); - else - o = IS_BOTTOM_OVERSHOOT( ras.lastY ); - if ( End_Profile( RAS_VARS o ) ) + if ( End_Profile( RAS_VAR ) ) return FAILURE; - /* close the `next profile in contour' linked list */ - if ( ras.gProfile ) - lastProfile->next = ras.gProfile; + if ( !ras.fProfile ) + ras.fProfile = ras.gProfile; } - if ( Finalize_Profile_Table( RAS_VAR ) ) - return FAILURE; + if ( ras.fProfile ) + Finalize_Profile_Table( RAS_VAR ); - return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE ); + return SUCCESS; } @@ -2065,24 +1879,11 @@ /*************************************************************************/ - /************************************************************************** - * - * Init_Linked - * - * Initializes an empty linked list. - */ - static void - Init_Linked( TProfileList* l ) - { - *l = NULL; - } - - /************************************************************************** * * InsNew * - * Inserts a new profile in a linked list. + * Inserts a new profile in a linked list, sorted by coordinate. */ static void InsNew( PProfileList list, @@ -2096,10 +1897,8 @@ current = *old; x = profile->X; - while ( current ) + while ( current && current->X < x ) { - if ( x < current->X ) - break; old = ¤t->link; current = *old; } @@ -2111,79 +1910,51 @@ /************************************************************************** * - * DelOld + * Increment * - * Removes an old profile from a linked list. + * Advances all profile in the list to the next scanline. It also + * sorts the trace list in the unlikely case of profile crossing. + * The profiles are inserted in sorted order. We might need a single + * swap to fix it when profiles (contours) cross. + * Bubble sort with immediate restart is good enough and simple. */ 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 ) + Increment( PProfileList list, + Int flow ) { PProfile *old, current, next; - /* First, set the new X coordinate of each profile */ - current = *list; - while ( current ) + /* First, set the new X coordinates and remove exhausted profiles */ + old = list; + while ( *old ) { - current->X = *current->offset; - current->offset += ( current->flags & Flow_Up ) ? 1 : -1; - current->height--; - current = current->link; + current = *old; + if ( --current->height ) + { + current->offset += flow; + current->X = current->x[current->offset]; + old = ¤t->link; + } + else + *old = current->link; /* remove */ } - /* Then sort them */ + /* Then make sure the list remains sorted */ old = list; current = *old; if ( !current ) return; - next = current->link; - - while ( next ) + while ( current->link ) { + next = current->link; + if ( current->X <= next->X ) { old = ¤t->link; - current = *old; - - if ( !current ) - return; + current = next; } else { @@ -2191,11 +1962,10 @@ current->link = next->link; next->link = current; + /* this is likely the only necessary swap -- restart */ old = list; current = *old; } - - next = current->link; } } @@ -2210,79 +1980,53 @@ */ static void - Vertical_Sweep_Init( RAS_ARGS Short* min, - Short* max ) + Vertical_Sweep_Init( RAS_ARGS Int min, + Int max ) { - Long pitch = ras.target.pitch; - FT_UNUSED( max ); - ras.traceIncr = (Short)-pitch; - ras.traceOfs = -*min * pitch; + ras.bLine = ras.bOrigin - min * ras.bPitch; } static void - Vertical_Sweep_Span( RAS_ARGS Short y, + Vertical_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2; - Byte* target; - - Int dropOutControl = left->flags & 7; + Int e1 = (Int)TRUNC( CEILING( x1 ) ); + Int e2 = (Int)TRUNC( FLOOR( x2 ) ); FT_UNUSED( y ); - FT_UNUSED( left ); - FT_UNUSED( right ); - /* in high-precision mode, we need 12 digits after the comma to */ - /* represent multiples of 1/(1<<12) = 1/4096 */ - FT_TRACE7(( " y=%d x=[%.12f;%.12f], drop-out=%d", + FT_TRACE7(( " y=%d x=[% .*f;% .*f]", y, - x1 / (double)ras.precision, - x2 / (double)ras.precision, - dropOutControl )); + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); - /* Drop-out control */ - - e1 = CEILING( x1 ); - e2 = FLOOR( x2 ); - - /* take care of the special case where both the left */ - /* and right contour lie exactly on pixel centers */ - if ( dropOutControl != 2 && - x2 - x1 - ras.precision <= ras.precision_jitter && - e1 != x1 && e2 != x2 ) - e2 = e1; - - e1 = TRUNC( e1 ); - e2 = TRUNC( e2 ); - - if ( e2 >= 0 && e1 < ras.bWidth ) + if ( e2 >= 0 && e1 <= ras.bRight ) { - Int c1, c2; - Byte f1, f2; + PByte target; + + Int c1, f1, c2, f2; if ( e1 < 0 ) e1 = 0; - if ( e2 >= ras.bWidth ) - e2 = ras.bWidth - 1; + if ( e2 > ras.bRight ) + e2 = ras.bRight; FT_TRACE7(( " -> x=[%d;%d]", e1, e2 )); - c1 = (Short)( e1 >> 3 ); - c2 = (Short)( e2 >> 3 ); + c1 = e1 >> 3; + c2 = e2 >> 3; - f1 = (Byte) ( 0xFF >> ( e1 & 7 ) ); - f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) ); + f1 = 0xFF >> ( e1 & 7 ); + f2 = ~0x7F >> ( e2 & 7 ); - target = ras.bOrigin + ras.traceOfs + c1; + target = ras.bLine + c1; c2 -= c1; if ( c2 > 0 ) @@ -2293,7 +2037,7 @@ /* This is due to the fact that, in the vast majority of cases, */ /* the span length in bytes is relatively small. */ while ( --c2 > 0 ) - *(++target) = 0xFF; + *( ++target ) = 0xFF; target[1] |= f2; } @@ -2306,165 +2050,50 @@ static void - Vertical_Sweep_Drop( RAS_ARGS Short y, + Vertical_Sweep_Drop( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2, pxl; - Short c1, f1; + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); + Int c1, f1; + + FT_UNUSED( y ); - FT_TRACE7(( " y=%d x=[%.12f;%.12f]", - y, - x1 / (double)ras.precision, - x2 / (double)ras.precision )); + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bRight ) + e1 = e2; - /* Drop-out control */ - - /* e2 x2 x1 e1 */ - /* */ - /* ^ | */ - /* | | */ - /* +-------------+---------------------+------------+ */ - /* | | */ - /* | v */ - /* */ - /* pixel contour contour pixel */ - /* center center */ - - /* drop-out mode scan conversion rules (as defined in OpenType) */ - /* --------------------------------------------------------------- */ - /* 0 1, 2, 3 */ - /* 1 1, 2, 4 */ - /* 2 1, 2 */ - /* 3 same as mode 2 */ - /* 4 1, 2, 5 */ - /* 5 1, 2, 6 */ - /* 6, 7 same as mode 2 */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - pxl = e1; - - if ( e1 > e2 ) + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bRight ) { - Int dropOutControl = left->flags & 7; + c1 = e2 >> 3; + f1 = 0x80 >> ( e2 & 7 ); - - FT_TRACE7(( ", drop-out=%d", dropOutControl )); - - if ( e1 == e2 + ras.precision ) - { - switch ( dropOutControl ) - { - case 0: /* simple drop-outs including stubs */ - pxl = e2; - break; - - case 4: /* smart drop-outs including stubs */ - pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); - break; - - case 1: /* simple drop-outs excluding stubs */ - case 5: /* smart drop-outs excluding stubs */ - - /* Drop-out Control Rules #4 and #6 */ - - /* The specification neither provides an exact definition */ - /* of a `stub' nor gives exact rules to exclude them. */ - /* */ - /* Here the constraints we use to recognize a stub. */ - /* */ - /* 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 */ - /* */ - /* We draw a stub if the following constraints are met. */ - /* */ - /* - for an upper or lower stub, there is top or bottom */ - /* overshoot, respectively */ - /* - the covered interval is greater or equal to a half */ - /* pixel */ - - /* upper stub test */ - if ( left->next == right && - left->height <= 0 && - !( left->flags & Overshoot_Top && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - /* lower stub test */ - if ( right->next == left && - left->start == y && - !( left->flags & Overshoot_Bottom && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - if ( dropOutControl == 1 ) - pxl = e2; - else - pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); - break; - - default: /* modes 2, 3, 6, 7 */ - goto Exit; /* no drop-out control */ - } - - /* undocumented but confirmed: If the drop-out would result in a */ - /* pixel outside of the bounding box, use the pixel inside of the */ - /* bounding box instead */ - if ( pxl < 0 ) - pxl = e1; - else if ( TRUNC( pxl ) >= ras.bWidth ) - pxl = e2; - - /* check that the other pixel isn't set */ - e1 = ( pxl == e1 ) ? e2 : e1; - - e1 = TRUNC( e1 ); - - c1 = (Short)( e1 >> 3 ); - f1 = (Short)( e1 & 7 ); - - if ( e1 >= 0 && e1 < ras.bWidth && - ras.bOrigin[ras.traceOfs + c1] & ( 0x80 >> f1 ) ) - goto Exit; - } - else - goto Exit; + if ( ras.bLine[c1] & f1 ) + return; } - e1 = TRUNC( pxl ); - - if ( e1 >= 0 && e1 < ras.bWidth ) + if ( e1 >= 0 && e1 <= ras.bRight ) { - FT_TRACE7(( " -> x=%d (drop-out)", e1 )); + c1 = e1 >> 3; + f1 = 0x80 >> ( e1 & 7 ); - c1 = (Short)( e1 >> 3 ); - f1 = (Short)( e1 & 7 ); + FT_TRACE7(( " y=%d x=%d%s\n", y, e1, + ras.bLine[c1] & f1 ? " redundant" : "" )); - ras.bOrigin[ras.traceOfs + c1] |= (char)( 0x80 >> f1 ); + ras.bLine[c1] |= f1; } - - Exit: - FT_TRACE7(( "\n" )); } static void Vertical_Sweep_Step( RAS_ARG ) { - ras.traceOfs += ras.traceIncr; + ras.bLine -= ras.bPitch; } @@ -2478,8 +2107,8 @@ */ static void - Horizontal_Sweep_Init( RAS_ARGS Short* min, - Short* max ) + Horizontal_Sweep_Init( RAS_ARGS Int min, + Int max ) { /* nothing, really */ FT_UNUSED_RASTER; @@ -2489,172 +2118,106 @@ static void - Horizontal_Sweep_Span( RAS_ARGS Short y, + Horizontal_Sweep_Span( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - FT_UNUSED( left ); - FT_UNUSED( right ); + Long e1 = CEILING( x1 ); + Long e2 = FLOOR( x2 ); - if ( x2 - x1 < ras.precision ) + FT_TRACE7(( " x=%d y=[% .*f;% .*f]", + y, + ras.precision_bits, (double)x1 / (double)ras.precision, + ras.precision_bits, (double)x2 / (double)ras.precision )); + + /* We should not need this procedure but the vertical sweep */ + /* mishandles horizontal lines through pixel centers. So we */ + /* have to check perfectly aligned span edges here. */ + /* */ + /* XXX: Can we handle horizontal lines better and drop this? */ + + if ( x1 == e1 ) { - Long e1, e2; + e1 = TRUNC( e1 ); - - FT_TRACE7(( " x=%d y=[%.12f;%.12f]", - y, - x1 / (double)ras.precision, - x2 / (double)ras.precision )); - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - - if ( e1 == e2 ) + if ( e1 >= 0 && e1 <= ras.bTop ) { - e1 = TRUNC( e1 ); - - if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) - { - Byte f1; - PByte bits; + Int f1; + PByte bits; - FT_TRACE7(( " -> y=%d (drop-out)", e1 )); + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e1 )); - bits[0] |= f1; - } + bits[0] |= f1; } - - FT_TRACE7(( "\n" )); } + + if ( x2 == e2 ) + { + e2 = TRUNC( e2 ); + + if ( e2 >= 0 && e2 <= ras.bTop ) + { + Int f1; + PByte bits; + + + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); + + FT_TRACE7(( bits[0] & f1 ? " redundant" + : " -> y=%ld edge", e2 )); + + bits[0] |= f1; + } + } + + FT_TRACE7(( "\n" )); } static void - Horizontal_Sweep_Drop( RAS_ARGS Short y, + Horizontal_Sweep_Drop( RAS_ARGS Int y, FT_F26Dot6 x1, - FT_F26Dot6 x2, - PProfile left, - PProfile right ) + FT_F26Dot6 x2 ) { - Long e1, e2, pxl; + Int e1 = (Int)TRUNC( x1 ); + Int e2 = (Int)TRUNC( x2 ); PByte bits; - Byte f1; + Int f1; - FT_TRACE7(( " x=%d y=[%.12f;%.12f]", - y, - x1 / (double)ras.precision, - x2 / (double)ras.precision )); + /* undocumented but confirmed: If the drop-out would result in a */ + /* pixel outside of the bounding box, use the pixel inside of the */ + /* bounding box instead */ + if ( e1 < 0 || e1 > ras.bTop ) + e1 = e2; - /* During the horizontal sweep, we only take care of drop-outs */ - - /* e1 + <-- pixel center */ - /* | */ - /* x1 ---+--> <-- contour */ - /* | */ - /* | */ - /* x2 <--+--- <-- contour */ - /* | */ - /* | */ - /* e2 + <-- pixel center */ - - e1 = CEILING( x1 ); - e2 = FLOOR ( x2 ); - pxl = e1; - - if ( e1 > e2 ) + /* otherwise check that the other pixel isn't set */ + else if ( e2 >=0 && e2 <= ras.bTop ) { - Int dropOutControl = left->flags & 7; + bits = ras.bOrigin + ( y >> 3 ) - e2 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); - - FT_TRACE7(( ", dropout=%d", dropOutControl )); - - if ( e1 == e2 + ras.precision ) - { - switch ( dropOutControl ) - { - case 0: /* simple drop-outs including stubs */ - pxl = e2; - break; - - case 4: /* smart drop-outs including stubs */ - pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); - break; - - case 1: /* simple drop-outs excluding stubs */ - case 5: /* smart drop-outs excluding stubs */ - /* see Vertical_Sweep_Drop for details */ - - /* rightmost stub test */ - if ( left->next == right && - left->height <= 0 && - !( left->flags & Overshoot_Top && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - /* leftmost stub test */ - if ( right->next == left && - left->start == y && - !( left->flags & Overshoot_Bottom && - x2 - x1 >= ras.precision_half ) ) - goto Exit; - - if ( dropOutControl == 1 ) - pxl = e2; - else - pxl = FLOOR( ( x1 + x2 - 1 ) / 2 + ras.precision_half ); - break; - - default: /* modes 2, 3, 6, 7 */ - goto Exit; /* no drop-out control */ - } - - /* undocumented but confirmed: If the drop-out would result in a */ - /* pixel outside of the bounding box, use the pixel inside of the */ - /* bounding box instead */ - if ( pxl < 0 ) - pxl = e1; - else if ( (ULong)( TRUNC( pxl ) ) >= ras.target.rows ) - pxl = e2; - - /* check that the other pixel isn't set */ - e1 = ( pxl == e1 ) ? e2 : e1; - - e1 = TRUNC( e1 ); - - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); - - if ( e1 >= 0 && - (ULong)e1 < ras.target.rows && - *bits & f1 ) - goto Exit; - } - else - goto Exit; + if ( *bits & f1 ) + return; } - e1 = TRUNC( pxl ); - - if ( e1 >= 0 && (ULong)e1 < ras.target.rows ) + if ( e1 >= 0 && e1 <= ras.bTop ) { - FT_TRACE7(( " -> y=%d (drop-out)", e1 )); + bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.bPitch; + f1 = 0x80 >> ( y & 7 ); - bits = ras.bOrigin + ( y >> 3 ) - e1 * ras.target.pitch; - f1 = (Byte)( 0x80 >> ( y & 7 ) ); + FT_TRACE7(( " x=%d y=%d%s\n", y, e1, + *bits & f1 ? " redundant" : "" )); - bits[0] |= f1; + *bits |= f1; } - - Exit: - FT_TRACE7(( "\n" )); } @@ -2670,116 +2233,61 @@ * * Generic Sweep Drawing routine * + * Note that this routine is executed with the pool containing at least + * two valid profiles (up and down) and two y-turns (top and bottom). + * */ - static Bool + static void Draw_Sweep( RAS_ARG ) { - Short y, y_change, y_height; + Int min_Y, max_Y, dropouts; + Int y, y_turn; - PProfile P, Q, P_Left, P_Right; + PProfile *Q, P, 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; + TProfileList waiting = ras.fProfile; + TProfileList draw_left = NULL; + TProfileList draw_right = NULL; - /* initialize empty linked lists */ + /* use y_turns to set the drawing range */ - 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 = FT_THROW( Invalid ); - return FAILURE; - } + min_Y = (Int)ras.maxBuff[0]; + max_Y = (Int)ras.maxBuff[ras.numTurns] - 1; /* now initialize 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 = P->start - min_Y; - P = P->link; - } + ras.Proc_Sweep_Init( RAS_VARS min_Y, max_Y ); /* 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 ) + for ( y = min_Y; y <= max_Y; ) { - /* check waiting list for new activations */ + /* check waiting list for new profile activations */ - P = waiting; - - while ( P ) + Q = &waiting; + while ( *Q ) { - Q = P->link; - P->countL -= y_height; - if ( P->countL == 0 ) + P = *Q; + if ( P->start == y ) { - DelOld( &waiting, P ); + *Q = P->link; /* remove */ + /* each active list contains profiles with the same flow */ + /* left and right are arbitrary, correspond to TrueType */ if ( P->flags & Flow_Up ) InsNew( &draw_left, P ); else InsNew( &draw_right, P ); } - - P = Q; + else + Q = &P->link; } - /* sort the drawing lists */ + y_turn = (Int)*++ras.maxBuff; - Sort( &draw_left ); - Sort( &draw_right ); - - y_change = (Short)ras.sizeBuff[-ras.numTurns--]; - y_height = (Short)( y_change - y ); - - while ( y < y_change ) + do { /* let's trace */ @@ -2790,9 +2298,13 @@ while ( P_Left && P_Right ) { - x1 = P_Left ->X; - x2 = P_Right->X; + Long x1 = P_Left ->X; + Long x2 = P_Right->X; + Long xs; + + /* TrueType should have x2 > x1, but can be opposite */ + /* by mistake or in CFF/Type1, fix it then */ if ( x1 > x2 ) { xs = x1; @@ -2800,205 +2312,130 @@ x2 = xs; } - e1 = FLOOR( x1 ); - e2 = CEILING( x2 ); + if ( CEILING( x1 ) <= FLOOR( x2 ) ) + ras.Proc_Sweep_Span( RAS_VARS y, x1, x2 ); - if ( x2 - x1 <= ras.precision && - e1 != x1 && e2 != x2 ) + /* otherwise, bottom ceiling > top floor, it is a drop-out */ + else { - if ( e1 > e2 || e2 == e1 + ras.precision ) + Int dropOutControl = P_Left->flags & 7; + + + /* Drop-out control */ + + /* e2 x2 x1 e1 */ + /* */ + /* ^ | */ + /* | | */ + /* +-------------+---------------------+------------+ */ + /* | | */ + /* | v */ + /* */ + /* pixel contour contour pixel */ + /* center center */ + + /* drop-out mode scan conversion rules (OpenType specs) */ + /* ------------------------------------------------------- */ + /* bit 0 exclude stubs if set */ + /* bit 1 ignore drop-outs if set */ + /* bit 2 smart rounding if set */ + + if ( dropOutControl & 2 ) + goto Next_Pair; + + /* The specification neither provides an exact definition */ + /* of a `stub' nor gives exact rules to exclude them. */ + /* */ + /* Here the constraints we use to recognize a stub. */ + /* */ + /* 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 */ + /* */ + /* We draw a stub if the following constraints are met. */ + /* */ + /* - for an upper or lower stub, there is top or bottom */ + /* overshoot, respectively */ + /* - the covered interval is greater or equal to a half */ + /* pixel */ + + if ( dropOutControl & 1 ) { - Int dropOutControl = P_Left->flags & 7; + /* upper stub test */ + if ( P_Left->height == 1 && + P_Left->next == P_Right && + !( P_Left->flags & Overshoot_Top && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; - - if ( dropOutControl != 2 ) - { - /* 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; + /* lower stub test */ + if ( P_Left->offset == 0 && + P_Right->next == P_Left && + !( P_Left->flags & Overshoot_Bottom && + x2 - x1 >= ras.precision_half ) ) + goto Next_Pair; } + + /* select the pixel to set and the other pixel */ + if ( dropOutControl & 4 ) + { + x2 = SMART( x1, x2 ); + x1 = x1 > x2 ? x2 + ras.precision : x2 - ras.precision; + } + else + { + x2 = FLOOR ( x2 ); + x1 = CEILING( x1 ); + } + + P_Left ->X = x2; + P_Right->X = x1; + + /* mark profile for drop-out processing */ + P_Left->flags |= Dropout; + dropouts++; } - ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right ); + Next_Pair: + P_Left = P_Left->link; + P_Right = P_Right->link; + } - Skip_To_Next: + /* handle drop-outs _after_ the span drawing */ + P_Left = draw_left; + P_Right = draw_right; + + while ( dropouts ) + { + if ( P_Left->flags & Dropout ) + { + ras.Proc_Sweep_Drop( RAS_VARS y, P_Left->X, P_Right->X ); + + P_Left->flags &= ~Dropout; + dropouts--; + } P_Left = P_Left->link; P_Right = P_Right->link; } - /* handle drop-outs _after_ the span drawing -- */ - /* drop-out 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 ); - } + Increment( &draw_left, 1 ); + Increment( &draw_right, -1 ); } - - /* now finalize the profiles that need 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, flush 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 && P_Right ) - { - 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; - } - - -#ifdef STANDALONE_ - - /************************************************************************** - * - * The following functions should only compile in stand-alone mode, - * i.e., when building this component without the rest of FreeType. - * - */ - - /************************************************************************** - * - * @Function: - * FT_Outline_Get_CBox - * - * @Description: - * Return 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 - * that 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. - * - * @Note: - * See @FT_Glyph_Get_CBox for a discussion of tricky fonts. - */ - - static void - FT_Outline_Get_CBox( const FT_Outline* outline, - FT_BBox *acbox ) - { - Long 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++ ) - { - Long 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; + while ( ++y < y_turn ); } } -#endif /* STANDALONE_ */ - /************************************************************************** * @@ -3016,63 +2453,62 @@ * Renderer error code. */ static int - Render_Single_Pass( RAS_ARGS Bool flipped ) + Render_Single_Pass( RAS_ARGS Bool flipped, + Int y_min, + Int y_max ) { - Short i, j, k; + Int y_mid; + Int band_top = 0; + Int band_stack[32]; /* enough to bisect 32-bit int bands */ - while ( ras.band_top >= 0 ) + FT_TRACE6(( "%s pass [%d..%d]\n", + flipped ? "Horizontal" : "Vertical", + y_min, y_max )); + + while ( 1 ) { - 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.minY = (Long)y_min * ras.precision; + ras.maxY = (Long)y_max * ras.precision; - ras.top = ras.buff; - - ras.error = Raster_Err_None; + ras.error = Raster_Err_Ok; if ( Convert_Glyph( RAS_VARS flipped ) ) { - if ( ras.error != Raster_Err_Overflow ) - return FAILURE; - - ras.error = Raster_Err_None; + if ( ras.error != Raster_Err_Raster_Overflow ) + return ras.error; /* sub-banding */ -#ifdef DEBUG_RASTER - ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) ); -#endif + if ( y_min == y_max ) + return ras.error; /* still Raster_Overflow */ - i = ras.band_stack[ras.band_top].y_min; - j = ras.band_stack[ras.band_top].y_max; + FT_TRACE6(( "band [%d..%d]: to be bisected\n", + y_min, y_max )); - k = (Short)( ( i + j ) / 2 ); + y_mid = ( y_min + y_max ) >> 1; - if ( ras.band_top >= 7 || k < i ) - { - ras.band_top = 0; - ras.error = FT_THROW( 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++; + band_stack[band_top++] = y_min; + y_min = y_mid + 1; } else { + FT_TRACE6(( "band [%d..%d]: %hd profiles; %td bytes remaining\n", + y_min, y_max, ras.num_Profs, + (char*)ras.maxBuff - (char*)ras.top )); + if ( ras.fProfile ) - if ( Draw_Sweep( RAS_VAR ) ) - return ras.error; - ras.band_top--; + Draw_Sweep( RAS_VAR ); + + if ( --band_top < 0 ) + break; + + y_max = y_min - 1; + y_min = band_stack[band_top]; } } - return SUCCESS; + return Raster_Err_Ok; } @@ -3091,74 +2527,53 @@ Render_Glyph( RAS_ARG ) { FT_Error error; + Long buffer[FT_MAX_BLACK_POOL]; + ras.buff = buffer; + ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + Set_High_Precision( RAS_VARS ras.outline.flags & FT_OUTLINE_HIGH_PRECISION ); + ras.dropOutControl = 0; + if ( ras.outline.flags & FT_OUTLINE_IGNORE_DROPOUTS ) - ras.dropOutControl = 2; - else - { - if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) - ras.dropOutControl = 4; - else - ras.dropOutControl = 0; + ras.dropOutControl |= 2; - if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) - ras.dropOutControl += 1; - } + if ( ras.outline.flags & FT_OUTLINE_SMART_DROPOUTS ) + ras.dropOutControl |= 4; - ras.second_pass = (Bool)( !( ras.outline.flags & - FT_OUTLINE_SINGLE_PASS ) ); + if ( !( ras.outline.flags & FT_OUTLINE_INCLUDE_STUBS ) ) + ras.dropOutControl |= 1; + + FT_TRACE6(( "BW Raster: precision 1/%d, dropout mode %d\n", + ras.precision, ras.dropOutControl )); /* Vertical Sweep */ - FT_TRACE7(( "Vertical pass (ftraster)\n" )); - 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 = (UShort)ras.target.width; - ras.bOrigin = (Byte*)ras.target.buffer; - - if ( ras.target.pitch > 0 ) - ras.bOrigin += (Long)( ras.target.rows - 1 ) * ras.target.pitch; - - if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 ) + error = Render_Single_Pass( RAS_VARS 0, 0, ras.bTop ); + if ( error ) return error; /* Horizontal Sweep */ - if ( ras.second_pass && ras.dropOutControl != 2 ) + if ( !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS ) ) { - FT_TRACE7(( "Horizontal pass (ftraster)\n" )); - 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 ) + error = Render_Single_Pass( RAS_VARS 1, 0, ras.bRight ); + if ( error ) return error; } - return Raster_Err_None; - } - - - static void - ft_black_init( black_PRaster raster ) - { - FT_UNUSED( raster ); + return Raster_Err_Ok; } @@ -3179,7 +2594,6 @@ *araster = (FT_Raster)&the_raster; FT_ZERO( &the_raster ); - ft_black_init( &the_raster ); return 0; } @@ -3197,30 +2611,30 @@ static int - ft_black_new( FT_Memory memory, - black_PRaster *araster ) + ft_black_new( void* memory_, /* FT_Memory */ + FT_Raster *araster_ ) /* black_PRaster */ { + FT_Memory memory = (FT_Memory)memory_; + black_PRaster *araster = (black_PRaster*)araster_; + FT_Error error; black_PRaster raster = NULL; - *araster = 0; if ( !FT_NEW( raster ) ) - { raster->memory = memory; - ft_black_init( raster ); - *araster = raster; - } + *araster = raster; return error; } static void - ft_black_done( black_PRaster raster ) + ft_black_done( FT_Raster raster_ ) /* black_PRaster */ { - FT_Memory memory = (FT_Memory)raster->memory; + black_PRaster raster = (black_PRaster)raster_; + FT_Memory memory = (FT_Memory)raster->memory; FT_FREE( raster ); @@ -3265,48 +2679,48 @@ black_TWorker worker[1]; #endif - Long buffer[FT_MAX_BLACK_POOL]; - if ( !raster ) - return FT_THROW( Not_Ini ); + return FT_THROW( Raster_Uninitialized ); if ( !outline ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return Raster_Err_None; + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return Raster_Err_Ok; if ( !outline->contours || !outline->points ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Outline ); /* this version of the raster does not support direct rendering, sorry */ - if ( params->flags & FT_RASTER_FLAG_DIRECT ) - return FT_THROW( Unsupported ); - - if ( params->flags & FT_RASTER_FLAG_AA ) - return FT_THROW( Unsupported ); + if ( params->flags & FT_RASTER_FLAG_DIRECT || + params->flags & FT_RASTER_FLAG_AA ) + return FT_THROW( Cannot_Render_Glyph ); if ( !target_map ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Argument ); /* nothing to do */ if ( !target_map->width || !target_map->rows ) - return Raster_Err_None; + return Raster_Err_Ok; if ( !target_map->buffer ) - return FT_THROW( Invalid ); + return FT_THROW( Invalid_Argument ); ras.outline = *outline; - ras.target = *target_map; - ras.buff = buffer; - ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + ras.bTop = (Int)target_map->rows - 1; + ras.bRight = (Int)target_map->width - 1; + ras.bPitch = (Int)target_map->pitch; + ras.bOrigin = (PByte)target_map->buffer; + + if ( ras.bPitch > 0 ) + ras.bOrigin += ras.bTop * ras.bPitch; return Render_Glyph( RAS_VAR ); } @@ -3317,11 +2731,11 @@ FT_GLYPH_FORMAT_OUTLINE, - (FT_Raster_New_Func) ft_black_new, /* raster_new */ - (FT_Raster_Reset_Func) ft_black_reset, /* raster_reset */ - (FT_Raster_Set_Mode_Func)ft_black_set_mode, /* raster_set_mode */ - (FT_Raster_Render_Func) ft_black_render, /* raster_render */ - (FT_Raster_Done_Func) ft_black_done /* raster_done */ + ft_black_new, /* FT_Raster_New_Func raster_new */ + ft_black_reset, /* FT_Raster_Reset_Func raster_reset */ + ft_black_set_mode, /* FT_Raster_Set_Mode_Func raster_set_mode */ + ft_black_render, /* FT_Raster_Render_Func raster_render */ + ft_black_done /* FT_Raster_Done_Func raster_done */ ) diff --git a/src/thirdparty/freetype2/src/raster/ftraster.h b/src/thirdparty/freetype2/src/raster/ftraster.h index 50d34201a..64499bf95 100644 --- a/src/thirdparty/freetype2/src/raster/ftraster.h +++ b/src/thirdparty/freetype2/src/raster/ftraster.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used @@ -22,8 +22,9 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_IMAGE_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/raster/ftrend1.c b/src/thirdparty/freetype2/src/raster/ftrend1.c index 62c727182..3fa008704 100644 --- a/src/thirdparty/freetype2/src/raster/ftrend1.c +++ b/src/thirdparty/freetype2/src/raster/ftrend1.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_OUTLINE_H +#include +#include +#include #include "ftrend1.h" #include "ftraster.h" @@ -28,8 +27,11 @@ /* initialize renderer -- init its raster */ static FT_Error - ft_raster1_init( FT_Renderer render ) + ft_raster1_init( FT_Module module ) /* FT_Renderer */ { + FT_Renderer render = (FT_Renderer)module; + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); return FT_Err_Ok; @@ -189,18 +191,18 @@ NULL, /* module specific interface */ - (FT_Module_Constructor)ft_raster1_init, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) NULL, /* get_interface */ + ft_raster1_init, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + NULL, /* FT_Module_Requester get_interface */ FT_GLYPH_FORMAT_OUTLINE, - (FT_Renderer_RenderFunc) ft_raster1_render, /* render_glyph */ - (FT_Renderer_TransformFunc)ft_raster1_transform, /* transform_glyph */ - (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, /* get_glyph_cbox */ - (FT_Renderer_SetModeFunc) ft_raster1_set_mode, /* set_mode */ + ft_raster1_render, /* FT_Renderer_RenderFunc render_glyph */ + ft_raster1_transform, /* FT_Renderer_TransformFunc transform_glyph */ + ft_raster1_get_cbox, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + ft_raster1_set_mode, /* FT_Renderer_SetModeFunc set_mode */ - (FT_Raster_Funcs*)&ft_standard_raster /* raster_class */ + &ft_standard_raster /* FT_Raster_Funcs* raster_class */ ) diff --git a/src/thirdparty/freetype2/src/raster/ftrend1.h b/src/thirdparty/freetype2/src/raster/ftrend1.h index 82ecac686..d838a942b 100644 --- a/src/thirdparty/freetype2/src/raster/ftrend1.h +++ b/src/thirdparty/freetype2/src/raster/ftrend1.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTREND1_H_ -#include -#include FT_RENDER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/raster/rasterrs.h b/src/thirdparty/freetype2/src/raster/rasterrs.h index 726640736..39d82a805 100644 --- a/src/thirdparty/freetype2/src/raster/rasterrs.h +++ b/src/thirdparty/freetype2/src/raster/rasterrs.h @@ -4,7 +4,7 @@ * * monochrome renderer error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef RASTERRS_H_ #define RASTERRS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX Raster_Err_ #define FT_ERR_BASE FT_Mod_Err_Raster -#include FT_ERRORS_H +#include #endif /* RASTERRS_H_ */ diff --git a/src/thirdparty/freetype2/src/sdf/ftbsdf.c b/src/thirdparty/freetype2/src/sdf/ftbsdf.c new file mode 100644 index 000000000..d4c5115ea --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftbsdf.c @@ -0,0 +1,1362 @@ +/**************************************************************************** + * + * ftbsdf.c + * + * Signed Distance Field support for bitmap fonts (body only). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 +#include +#include + +#include "ftsdf.h" +#include "ftsdferrs.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * A brief technical overview of how the BSDF rasterizer works + * ----------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * BSDF stands for Bitmap to Signed Distance Field rasterizer. + * + * * This renderer converts rasterized bitmaps to SDF. There is another + * renderer called 'sdf', which generates SDF directly from outlines; + * see file `ftsdf.c` for more. + * + * * The idea of generating SDF from bitmaps is taken from two research + * papers, where one is dependent on the other: + * + * - Per-Erik Danielsson: Euclidean Distance Mapping + * http://webstaff.itn.liu.se/~stegu/JFA/Danielsson.pdf + * + * From this paper we use the eight-point sequential Euclidean + * distance mapping (8SED). This is the heart of the process used + * in this rasterizer. + * + * - Stefan Gustavson, Robin Strand: Anti-aliased Euclidean distance transform. + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * + * The original 8SED algorithm discards the pixels' alpha values, + * which can contain information about the actual outline of the + * glyph. This paper takes advantage of those alpha values and + * approximates outline pretty accurately. + * + * * This rasterizer also works for monochrome bitmaps. However, the + * result is not as accurate since we don't have any way to + * approximate outlines from binary bitmaps. + * + * ======================================================================== + * + * Generating SDF from bitmap is done in several steps. + * + * (1) The only information we have is the bitmap itself. It can + * be monochrome or anti-aliased. If it is anti-aliased, pixel values + * are nothing but coverage values. These coverage values can be used + * to extract information about the outline of the image. For + * example, if the pixel's alpha value is 0.5, then we can safely + * assume that the outline passes through the center of the pixel. + * + * (2) Find edge pixels in the bitmap (see `bsdf_is_edge` for more). For + * all edge pixels we use the Anti-aliased Euclidean distance + * transform algorithm and compute approximate edge distances (see + * `compute_edge_distance` and/or the second paper for more). + * + * (3) Now that we have computed approximate distances for edge pixels we + * use the 8SED algorithm to basically sweep the entire bitmap and + * compute distances for the rest of the pixels. (Since the algorithm + * is pretty convoluted it is only explained briefly in a comment to + * function `edt8`. To see the actual algorithm refer to the first + * paper.) + * + * (4) Finally, compute the sign for each pixel. This is done in function + * `finalize_sdf`. The basic idea is that if a pixel's original + * alpha/coverage value is greater than 0.5 then it is 'inside' (and + * 'outside' otherwise). + * + * Pseudo Code: + * + * ``` + * b = source bitmap; + * t = target bitmap; + * dm = list of distances; // dimension equal to b + * + * foreach grid_point (x, y) in b: + * { + * if (is_edge(x, y)): + * dm = approximate_edge_distance(b, x, y); + * + * // do the 8SED on the distances + * edt8(dm); + * + * // determine the signs + * determine_signs(dm): + * + * // copy SDF data to the target bitmap + * copy(dm to t); + * } + * + */ + + + /************************************************************************** + * + * 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 bsdf + + + /************************************************************************** + * + * useful macros + * + */ + +#define ONE 65536 /* 1 in 16.16 */ + + + /************************************************************************** + * + * structs + * + */ + + + /************************************************************************** + * + * @Struct: + * BSDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing this is passed + * to the @FT_Raster_RenderFunc function, which then can be used however + * we want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct BSDF_TRaster_ + { + FT_Memory memory; + + } BSDF_TRaster, *BSDF_PRaster; + + + /************************************************************************** + * + * @Struct: + * ED + * + * @Description: + * Euclidean distance. It gets used for Euclidean distance transforms; + * it can also be interpreted as an edge distance. + * + * @Fields: + * dist :: + * Vector length of the `prox` parameter. Can be squared or absolute + * depending on the `USE_SQUARED_DISTANCES` macro defined in file + * `ftsdfcommon.h`. + * + * prox :: + * Vector to the nearest edge. Can also be interpreted as shortest + * distance of a point. + * + * alpha :: + * Alpha value of the original bitmap from which we generate SDF. + * Needed for computing the gradient and determining the proper sign + * of a pixel. + * + */ + typedef struct ED_ + { + FT_16D16 dist; + FT_16D16_Vec prox; + FT_Byte alpha; + + } ED; + + + /************************************************************************** + * + * @Struct: + * BSDF_Worker + * + * @Description: + * A convenience struct that is passed to functions while generating + * SDF; most of those functions require the same parameters. + * + * @Fields: + * distance_map :: + * A one-dimensional array that gets interpreted as two-dimensional + * one. It contains the Euclidean distances of all points of the + * bitmap. + * + * width :: + * Width of the above `distance_map`. + * + * rows :: + * Number of rows in the above `distance_map`. + * + * params :: + * Internal parameters and properties required by the rasterizer. See + * file `ftsdf.h` for more. + * + */ + typedef struct BSDF_Worker_ + { + ED* distance_map; + + FT_Int width; + FT_Int rows; + + SDF_Raster_Params params; + + } BSDF_Worker; + + + /************************************************************************** + * + * initializer + * + */ + + static const ED zero_ed = { 0, { 0, 0 }, 0 }; + + + /************************************************************************** + * + * rasterizer functions + * + */ + + /************************************************************************** + * + * @Function: + * bsdf_is_edge + * + * @Description: + * Check whether a pixel is an edge pixel, i.e., whether it is + * surrounded by a completely black pixel (zero alpha), and the current + * pixel is not a completely black pixel. + * + * @Input: + * dm :: + * Array of distances. The parameter must point to the current + * pixel, i.e., the pixel that is to be checked for being an edge. + * + * x :: + * The x position of the current pixel. + * + * y :: + * The y position of the current pixel. + * + * w :: + * Width of the bitmap. + * + * r :: + * Number of rows in the bitmap. + * + * @Return: + * 1~if the current pixel is an edge pixel, 0~otherwise. + * + */ + +#ifdef CHECK_NEIGHBOR +#undef CHECK_NEIGHBOR +#endif + +#define CHECK_NEIGHBOR( x_offset, y_offset ) \ + do \ + { \ + if ( x + x_offset >= 0 && x + x_offset < w && \ + y + y_offset >= 0 && y + y_offset < r ) \ + { \ + num_neighbors++; \ + \ + to_check = dm + y_offset * w + x_offset; \ + if ( to_check->alpha == 0 ) \ + { \ + is_edge = 1; \ + goto Done; \ + } \ + } \ + } while ( 0 ) + + static FT_Bool + bsdf_is_edge( ED* dm, /* distance map */ + FT_Int x, /* x index of point to check */ + FT_Int y, /* y index of point to check */ + FT_Int w, /* width */ + FT_Int r ) /* rows */ + { + FT_Bool is_edge = 0; + ED* to_check = NULL; + FT_Int num_neighbors = 0; + + + if ( dm->alpha == 0 ) + goto Done; + + if ( dm->alpha > 0 && dm->alpha < 255 ) + { + is_edge = 1; + goto Done; + } + + /* up */ + CHECK_NEIGHBOR( 0, -1 ); + + /* down */ + CHECK_NEIGHBOR( 0, 1 ); + + /* left */ + CHECK_NEIGHBOR( -1, 0 ); + + /* right */ + CHECK_NEIGHBOR( 1, 0 ); + + /* up left */ + CHECK_NEIGHBOR( -1, -1 ); + + /* up right */ + CHECK_NEIGHBOR( 1, -1 ); + + /* down left */ + CHECK_NEIGHBOR( -1, 1 ); + + /* down right */ + CHECK_NEIGHBOR( 1, 1 ); + + if ( num_neighbors != 8 ) + is_edge = 1; + + Done: + return is_edge; + } + +#undef CHECK_NEIGHBOR + + + /************************************************************************** + * + * @Function: + * compute_edge_distance + * + * @Description: + * Approximate the outline and compute the distance from `current` + * to the approximated outline. + * + * @Input: + * current :: + * Array of Euclidean distances. `current` must point to the position + * for which the distance is to be calculated. We treat this array as + * a two-dimensional array mapped to a one-dimensional array. + * + * x :: + * The x coordinate of the `current` parameter in the array. + * + * y :: + * The y coordinate of the `current` parameter in the array. + * + * w :: + * The width of the distances array. + * + * r :: + * Number of rows in the distances array. + * + * @Return: + * A vector pointing to the approximate edge distance. + * + * @Note: + * This is a computationally expensive function. Try to reduce the + * number of calls to this function. Moreover, this must only be used + * for edge pixel positions. + * + */ + static FT_16D16_Vec + compute_edge_distance( ED* current, + FT_Int x, + FT_Int y, + FT_Int w, + FT_Int r ) + { + /* + * This function, based on the paper presented by Stefan Gustavson and + * Robin Strand, gets used to approximate edge distances from + * anti-aliased bitmaps. + * + * The algorithm is as follows. + * + * (1) In anti-aliased images, the pixel's alpha value is the coverage + * of the pixel by the outline. For example, if the alpha value is + * 0.5f we can assume that the outline passes through the center of + * the pixel. + * + * (2) For this reason we can use that alpha value to approximate the real + * distance of the pixel to edge pretty accurately. A simple + * approximation is `(0.5f - alpha)`, assuming that the outline is + * parallel to the x or y~axis. However, in this algorithm we use a + * different approximation which is quite accurate even for + * non-axis-aligned edges. + * + * (3) The only remaining piece of information that we cannot + * approximate directly from the alpha is the direction of the edge. + * This is where we use Sobel's operator to compute the gradient of + * the pixel. The gradient give us a pretty good approximation of + * the edge direction. We use a 3x3 kernel filter to compute the + * gradient. + * + * (4) After the above two steps we have both the direction and the + * distance to the edge which is used to generate the Signed + * Distance Field. + * + * References: + * + * - Anti-Aliased Euclidean Distance Transform: + * http://weber.itn.liu.se/~stegu/aadist/edtaa_preprint.pdf + * - Sobel Operator: + * https://en.wikipedia.org/wiki/Sobel_operator + */ + + FT_16D16_Vec g = { 0, 0 }; + FT_16D16 dist, current_alpha; + FT_16D16 a1, temp; + FT_16D16 gx, gy; + FT_16D16 alphas[9]; + + + /* Since our spread cannot be 0, this condition */ + /* can never be true. */ + if ( x <= 0 || x >= w - 1 || + y <= 0 || y >= r - 1 ) + return g; + + /* initialize the alphas */ + alphas[0] = 256 * (FT_16D16)current[-w - 1].alpha; + alphas[1] = 256 * (FT_16D16)current[-w ].alpha; + alphas[2] = 256 * (FT_16D16)current[-w + 1].alpha; + alphas[3] = 256 * (FT_16D16)current[ -1].alpha; + alphas[4] = 256 * (FT_16D16)current[ 0].alpha; + alphas[5] = 256 * (FT_16D16)current[ 1].alpha; + alphas[6] = 256 * (FT_16D16)current[ w - 1].alpha; + alphas[7] = 256 * (FT_16D16)current[ w ].alpha; + alphas[8] = 256 * (FT_16D16)current[ w + 1].alpha; + + current_alpha = alphas[4]; + + /* Compute the gradient using the Sobel operator. */ + /* In this case we use the following 3x3 filters: */ + /* */ + /* For x: | -1 0 -1 | */ + /* | -root(2) 0 root(2) | */ + /* | -1 0 1 | */ + /* */ + /* For y: | -1 -root(2) -1 | */ + /* | 0 0 0 | */ + /* | 1 root(2) 1 | */ + /* */ + /* [Note]: 92681 is root(2) in 16.16 format. */ + g.x = -alphas[0] - + FT_MulFix( alphas[3], 92681 ) - + alphas[6] + + alphas[2] + + FT_MulFix( alphas[5], 92681 ) + + alphas[8]; + + g.y = -alphas[0] - + FT_MulFix( alphas[1], 92681 ) - + alphas[2] + + alphas[6] + + FT_MulFix( alphas[7], 92681 ) + + alphas[8]; + + FT_Vector_NormLen( &g ); + + /* The gradient gives us the direction of the */ + /* edge for the current pixel. Once we have the */ + /* approximate direction of the edge, we can */ + /* approximate the edge distance much better. */ + + if ( g.x == 0 || g.y == 0 ) + dist = ONE / 2 - alphas[4]; + else + { + gx = g.x; + gy = g.y; + + gx = FT_ABS( gx ); + gy = FT_ABS( gy ); + + if ( gx < gy ) + { + temp = gx; + gx = gy; + gy = temp; + } + + a1 = FT_DivFix( gy, gx ) / 2; + + if ( current_alpha < a1 ) + dist = ( gx + gy ) / 2 - + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + current_alpha ) ) ); + + else if ( current_alpha < ( ONE - a1 ) ) + dist = FT_MulFix( ONE / 2 - current_alpha, gx ); + + else + dist = -( gx + gy ) / 2 + + square_root( 2 * FT_MulFix( gx, + FT_MulFix( gy, + ONE - current_alpha ) ) ); + } + + g.x = FT_MulFix( g.x, dist ); + g.y = FT_MulFix( g.y, dist ); + + return g; + } + + + /************************************************************************** + * + * @Function: + * bsdf_approximate_edge + * + * @Description: + * Loops over all the pixels and call `compute_edge_distance` only for + * edge pixels. This makes the process a lot faster since + * `compute_edge_distance` uses functions such as `FT_Vector_NormLen', + * which are quite slow. + * + * @InOut: + * worker :: + * Contains the distance map as well as all the relevant parameters + * required by the function. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function directly manipulates `worker->distance_map`. + * + */ + static FT_Error + bsdf_approximate_edge( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + FT_Int i, j; + FT_Int index; + ED* ed; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + ed = worker->distance_map; + + for ( j = 0; j < worker->rows; j++ ) + { + for ( i = 0; i < worker->width; i++ ) + { + index = j * worker->width + i; + + if ( bsdf_is_edge( worker->distance_map + index, + i, j, + worker->width, + worker->rows ) ) + { + /* approximate the edge distance for edge pixels */ + ed[index].prox = compute_edge_distance( ed + index, + i, j, + worker->width, + worker->rows ); + ed[index].dist = VECTOR_LENGTH_16D16( ed[index].prox ); + } + else + { + /* for non-edge pixels assign far away distances */ + ed[index].dist = 400 * ONE; + ed[index].prox.x = 200 * ONE; + ed[index].prox.y = 200 * ONE; + } + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * bsdf_init_distance_map + * + * @Description: + * Initialize the distance map according to the '8-point sequential + * Euclidean distance mapping' (8SED) algorithm. Basically it copies + * the `source` bitmap alpha values to the `distance_map->alpha` + * parameter of `worker`. + * + * @Input: + * source :: + * Source bitmap to copy the data from. + * + * @Output: + * worker :: + * Target distance map to copy the data to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + bsdf_init_distance_map( const FT_Bitmap* source, + BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + FT_Int x_diff, y_diff; + FT_Int t_i, t_j, s_i, s_j; + FT_Byte* s; + ED* t; + + + /* again check the parameters (probably unnecessary) */ + if ( !source || !worker ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* Because of the way we convert a bitmap to SDF, */ + /* i.e., aligning the source to the center of the */ + /* target, the target's width and rows must be */ + /* checked before copying. */ + if ( worker->width < (FT_Int)source->width || + worker->rows < (FT_Int)source->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check pixel mode */ + if ( source->pixel_mode == FT_PIXEL_MODE_NONE ) + { + FT_ERROR(( "bsdf_copy_source_to_target:" + " Invalid pixel mode of source bitmap" )); + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( source->pixel_mode == FT_PIXEL_MODE_MONO ) + { + FT_TRACE0(( "bsdf_copy_source_to_target:" + " The `bsdf' renderer can convert monochrome\n" )); + FT_TRACE0(( " " + " bitmaps to SDF but the results are not perfect\n" )); + FT_TRACE0(( " " + " because there is no way to approximate actual\n" )); + FT_TRACE0(( " " + " outlines from monochrome bitmaps. Consider\n" )); + FT_TRACE0(( " " + " using an anti-aliased bitmap instead.\n" )); + } +#endif + + /* Calculate the width and row differences */ + /* between target and source. */ + x_diff = worker->width - (int)source->width; + y_diff = worker->rows - (int)source->rows; + + x_diff /= 2; + y_diff /= 2; + + t = (ED*)worker->distance_map; + s = source->buffer; + + /* For now we only support pixel mode `FT_PIXEL_MODE_MONO` */ + /* and `FT_PIXEL_MODE_GRAY`. More will be added later. */ + /* */ + /* [NOTE]: We can also use @FT_Bitmap_Convert to convert */ + /* bitmap to 8bpp. To avoid extra allocation and */ + /* since the target bitmap can be 16bpp we manually */ + /* convert the source bitmap to the desired bpp. */ + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + FT_Int div, mod; + FT_Byte pixel, byte; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * source->pitch; + else + s_index = s_j * source->pitch; + + div = s_index + s_i / 8; + mod = 7 - s_i % 8; + + pixel = s[div]; + byte = (FT_Byte)( 1 << mod ); + + t[t_index].alpha = pixel & byte ? 255 : 0; + } + } + } + break; + + case FT_PIXEL_MODE_GRAY: + { + FT_Int t_width = worker->width; + FT_Int t_rows = worker->rows; + FT_Int s_width = (int)source->width; + FT_Int s_rows = (int)source->rows; + + + /* loop over all pixels and assign pixel values from source */ + for ( t_j = 0; t_j < t_rows; t_j++ ) + { + for ( t_i = 0; t_i < t_width; t_i++ ) + { + FT_Int t_index = t_j * t_width + t_i; + FT_Int s_index; + + + t[t_index] = zero_ed; + + s_i = t_i - x_diff; + s_j = t_j - y_diff; + + /* Assign 0 to padding similar to */ + /* the source bitmap. */ + if ( s_i < 0 || s_i >= s_width || + s_j < 0 || s_j >= s_rows ) + continue; + + if ( worker->params.flip_y ) + s_index = ( s_rows - s_j - 1 ) * s_width + s_i; + else + s_index = s_j * s_width + s_i; + + /* simply copy the alpha values */ + t[t_index].alpha = s[s_index]; + } + } + } + break; + + default: + FT_ERROR(( "bsdf_copy_source_to_target:" + " unsopported pixel mode of source bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + break; + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * compare_neighbor + * + * @Description: + * Compare neighbor pixel (which is defined by the offset) and update + * `current` distance if the new distance is shorter than the original. + * + * @Input: + * x_offset :: + * X offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * y_offset :: + * Y offset of the neighbor to be checked. The offset is relative to + * the `current`. + * + * width :: + * Width of the `current` array. + * + * @InOut: + * current :: + * Pointer into array of distances. This parameter must point to the + * position whose neighbor is to be checked. The array is treated as + * a two-dimensional array. + * + */ + static void + compare_neighbor( ED* current, + FT_Int x_offset, + FT_Int y_offset, + FT_Int width ) + { +#if USE_SQUARED_DISTANCES + FT_16D16 edge_threshold = ONE / 4; +#else + FT_16D16 edge_threshold = ONE / 2; +#endif + ED* to_check; + FT_16D16 dist; + FT_16D16_Vec dist_vec; + + + /* + * Skip neighbor comparison if the distance is less than or equal to 0.5. + * When using squared distances, compare to 0.25 (= 0.5^2) instead. + */ + if ( current->dist <= edge_threshold ) + return; + + to_check = current + ( y_offset * width ) + x_offset; + + /* + * While checking for the nearest point we first approximate the + * distance of `current` by adding the deviation (which is sqrt(2) at + * most). Only if the new value is less than the current value we + * calculate the actual distances using `FT_Vector_Length`. This last + * step can be omitted by using squared distances. + */ + + /* + * Approximate the distance. We subtract 1 to avoid precision errors, + * which could happen because the two directions can be opposite. + */ + dist = to_check->dist - ONE; + + if ( dist < current->dist ) + { + dist_vec = to_check->prox; + + dist_vec.x += x_offset * ONE; + dist_vec.y += y_offset * ONE; + dist = VECTOR_LENGTH_16D16( dist_vec ); + + if ( dist < current->dist ) + { + current->dist = dist; + current->prox = dist_vec; + } + } + } + + + /************************************************************************** + * + * @Function: + * first_pass + * + * @Description: + * First pass of the 8SED algorithm. Loop over the bitmap from top to + * bottom and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + first_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from top to bottom and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the first row as it has no top */ + /* neighbor; it will be covered in the second scan of */ + /* the image (from bottom to top). */ + for ( j = 1; j < r; j++ ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, -1, w ); + /* up */ + compare_neighbor( current, 0, -1, w ); + /* up-right */ + compare_neighbor( current, 1, -1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * second_pass + * + * @Description: + * Second pass of the 8SED algorithm. Loop over the bitmap from bottom + * to top and scan each row left to right, updating the distances in + * `worker->distance_map`. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + */ + static void + second_pass( BSDF_Worker* worker ) + { + FT_Int i, j; /* iterators */ + FT_Int w, r; /* width, rows */ + ED* dm; /* distance map */ + + + dm = worker->distance_map; + w = worker->width; + r = worker->rows; + + /* Start scanning from bottom to top and sweep each */ + /* row back and forth comparing the distances of the */ + /* neighborhood. Leave the last row as it has no down */ + /* neighbor; it is already covered in the first scan */ + /* of the image (from top to bottom). */ + for ( j = r - 2; j >= 0; j-- ) + { + FT_Int index; + ED* current; + + + /* Forward pass of rows (left -> right). Leave the first */ + /* column, which gets covered in the backward pass. */ + for ( i = 1; i < w - 1; i++ ) + { + index = j * w + i; + current = dm + index; + + /* left-up */ + compare_neighbor( current, -1, 1, w ); + /* up */ + compare_neighbor( current, 0, 1, w ); + /* up-right */ + compare_neighbor( current, 1, 1, w ); + /* left */ + compare_neighbor( current, -1, 0, w ); + } + + /* Backward pass of rows (right -> left). Leave the last */ + /* column, which was already covered in the forward pass. */ + for ( i = w - 2; i >= 0; i-- ) + { + index = j * w + i; + current = dm + index; + + /* right */ + compare_neighbor( current, 1, 0, w ); + } + } + } + + + /************************************************************************** + * + * @Function: + * edt8 + * + * @Description: + * Compute the distance map of the a bitmap. Execute both first and + * second pass of the 8SED algorithm. + * + * @InOut: + * worker:: + * Contains all the relevant parameters. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + edt8( BSDF_Worker* worker ) + { + FT_Error error = FT_Err_Ok; + + + if ( !worker || !worker->distance_map ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* first scan of the image */ + first_pass( worker ); + + /* second scan of the image */ + second_pass( worker ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * finalize_sdf + * + * @Description: + * Copy the SDF data from `worker->distance_map` to the `target` bitmap. + * Also transform the data to output format, (which is 6.10 fixed-point + * format at the moment). + * + * @Input: + * worker :: + * Contains source distance map and other SDF data. + * + * @Output: + * target :: + * Target bitmap to which the SDF data is copied to. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + finalize_sdf( BSDF_Worker* worker, + const FT_Bitmap* target ) + { + FT_Error error = FT_Err_Ok; + + FT_Int w, r; + FT_Int i, j; + + FT_SDFFormat* t_buffer; + FT_16D16 sp_sq, spread; + + + if ( !worker || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + w = (int)target->width; + r = (int)target->rows; + t_buffer = (FT_SDFFormat*)target->buffer; + + if ( w != worker->width || + r != worker->rows ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + spread = (FT_16D16)FT_INT_16D16( worker->params.spread ); + +#if USE_SQUARED_DISTANCES + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread * + worker->params.spread ); +#else + sp_sq = (FT_16D16)FT_INT_16D16( worker->params.spread ); +#endif + + for ( j = 0; j < r; j++ ) + { + for ( i = 0; i < w; i++ ) + { + FT_Int index; + FT_16D16 dist; + FT_SDFFormat final_dist; + FT_Char sign; + + + index = j * w + i; + dist = worker->distance_map[index].dist; + + if ( dist < 0 || dist > sp_sq ) + dist = sp_sq; + +#if USE_SQUARED_DISTANCES + dist = square_root( dist ); +#endif + + /* We assume that if the pixel is inside a contour */ + /* its coverage value must be > 127. */ + sign = worker->distance_map[index].alpha < 127 ? -1 : 1; + + /* flip the sign according to the property */ + if ( worker->params.flip_sign ) + sign = -sign; + + /* concatenate from 16.16 to appropriate format */ + final_dist = map_fixed_to_sdf( dist * sign, spread ); + + t_buffer[index] = final_dist; + } + } + + Exit: + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + /* called when adding a new module through @FT_Add_Module */ + static FT_Error + bsdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* BSDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + BSDF_PRaster* araster = (BSDF_PRaster*)araster_; + + FT_Error error; + BSDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + /* unused */ + static void + bsdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + /* unused */ + static FT_Error + bsdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + /* called while rendering through @FT_Render_Glyph */ + static FT_Error + bsdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + const FT_Bitmap* source = NULL; + const FT_Bitmap* target = NULL; + + BSDF_TRaster* bsdf_raster = (BSDF_TRaster*)raster; + BSDF_Worker worker; + + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + + worker.distance_map = NULL; + + /* check for valid parameters */ + if ( !raster || !params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* check whether the flag is set */ + if ( sdf_params->root.flags != FT_RASTER_FLAG_SDF ) + { + error = FT_THROW( Raster_Corrupted ); + goto Exit; + } + + source = (const FT_Bitmap*)sdf_params->root.source; + target = (const FT_Bitmap*)sdf_params->root.target; + + /* check source and target bitmap */ + if ( !source || !target ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = bsdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "bsdf_raster_render: Raster not set up properly,\n" )); + FT_TRACE0(( " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "bsdf_raster_render:" + " The `spread' field of `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " is invalid; the value of this field must be\n" )); + FT_TRACE0(( " " + " within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params'\n" )); + FT_TRACE0(( " " + " instead of the default `FT_Raster_Params'\n" )); + FT_TRACE0(( " " + " while calling this function and set the fields\n" )); + FT_TRACE0(( " " + " accordingly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* set up the worker */ + + /* allocate the distance map */ + if ( FT_QALLOC_MULT( worker.distance_map, target->rows, + target->width * sizeof ( *worker.distance_map ) ) ) + goto Exit; + + worker.width = (int)target->width; + worker.rows = (int)target->rows; + worker.params = *sdf_params; + + FT_CALL( bsdf_init_distance_map( source, &worker ) ); + FT_CALL( bsdf_approximate_edge( &worker ) ); + FT_CALL( edt8( &worker ) ); + FT_CALL( finalize_sdf( &worker, target ) ); + + FT_TRACE0(( "bsdf_raster_render: Total memory used = %ld\n", + worker.width * worker.rows * + (long)sizeof ( *worker.distance_map ) )); + + Exit: + if ( worker.distance_map ) + FT_FREE( worker.distance_map ); + + return error; + } + + + /* called while deleting `FT_Library` only if the module is added */ + static void + bsdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((BSDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_bitmap_sdf_raster, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Raster_New_Func) bsdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) bsdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)bsdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) bsdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) bsdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdf.c b/src/thirdparty/freetype2/src/sdf/ftsdf.c new file mode 100644 index 000000000..1076b1b4e --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdf.c @@ -0,0 +1,3932 @@ +/**************************************************************************** + * + * ftsdf.c + * + * Signed Distance Field support for outline fonts (body). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 +#include +#include +#include +#include "ftsdf.h" + +#include "ftsdferrs.h" + + + /************************************************************************** + * + * A brief technical overview of how the SDF rasterizer works + * ---------------------------------------------------------- + * + * [Notes]: + * * SDF stands for Signed Distance Field everywhere. + * + * * This renderer generates SDF directly from outlines. There is + * another renderer called 'bsdf', which converts bitmaps to SDF; see + * file `ftbsdf.c` for more. + * + * * The basic idea of generating the SDF is taken from Viktor Chlumsky's + * research paper. The paper explains both single and multi-channel + * SDF, however, this implementation only generates single-channel SDF. + * + * Chlumsky, Viktor: Shape Decomposition for Multi-channel Distance + * Fields. Master's thesis. Czech Technical University in Prague, + * Faculty of InformationTechnology, 2015. + * + * For more information: https://github.com/Chlumsky/msdfgen + * + * ======================================================================== + * + * Generating SDF from outlines is pretty straightforward. + * + * (1) We have a set of contours that make the outline of a shape/glyph. + * Each contour comprises of several edges, with three types of edges. + * + * * line segments + * * conic Bezier curves + * * cubic Bezier curves + * + * (2) Apart from the outlines we also have a two-dimensional grid, namely + * the bitmap that is used to represent the final SDF data. + * + * (3) In order to generate SDF, our task is to find shortest signed + * distance from each grid point to the outline. The 'signed + * distance' means that if the grid point is filled by any contour + * then its sign is positive, otherwise it is negative. The pseudo + * code is as follows. + * + * ``` + * foreach grid_point (x, y): + * { + * int min_dist = INT_MAX; + * + * foreach contour in outline: + * { + * foreach edge in contour: + * { + * // get shortest distance from point (x, y) to the edge + * d = get_min_dist(x, y, edge); + * + * if (d < min_dist) + * min_dist = d; + * } + * + * bitmap[x, y] = min_dist; + * } + * } + * ``` + * + * (4) After running this algorithm the bitmap contains information about + * the shortest distance from each point to the outline of the shape. + * Of course, while this is the most straightforward way of generating + * SDF, we use various optimizations in our implementation. See the + * `sdf_generate_*' functions in this file for all details. + * + * The optimization currently used by default is subdivision; see + * function `sdf_generate_subdivision` for more. + * + * Also, to see how we compute the shortest distance from a point to + * each type of edge, check out the `get_min_distance_*' functions. + * + */ + + + /************************************************************************** + * + * 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 sdf + + + /************************************************************************** + * + * definitions + * + */ + + /* + * If set to 1, the rasterizer uses Newton-Raphson's method for finding + * the shortest distance from a point to a conic curve. + * + * If set to 0, an analytical method gets used instead, which computes the + * roots of a cubic polynomial to find the shortest distance. However, + * the analytical method can currently underflow; we thus use Newton's + * method by default. + */ +#ifndef USE_NEWTON_FOR_CONIC +#define USE_NEWTON_FOR_CONIC 1 +#endif + + /* + * The number of intervals a Bezier curve gets sampled and checked to find + * the shortest distance. + */ +#define MAX_NEWTON_DIVISIONS 4 + + /* + * The number of steps of Newton's iterations in each interval of the + * Bezier curve. Basically, we run Newton's approximation + * + * x -= Q(t) / Q'(t) + * + * for each division to get the shortest distance. + */ +#define MAX_NEWTON_STEPS 4 + + /* + * The epsilon distance (in 16.16 fractional units) used for corner + * resolving. If the difference of two distances is less than this value + * they will be checked for a corner if they are ambiguous. + */ +#define CORNER_CHECK_EPSILON 32 + +#if 0 + /* + * Coarse grid dimension. Will probably be removed in the future because + * coarse grid optimization is the slowest algorithm. + */ +#define CG_DIMEN 8 +#endif + + + /************************************************************************** + * + * macros + * + */ + +#define MUL_26D6( a, b ) ( ( ( a ) * ( b ) ) / 64 ) +#define VEC_26D6_DOT( p, q ) ( MUL_26D6( p.x, q.x ) + \ + MUL_26D6( p.y, q.y ) ) + + + /************************************************************************** + * + * structures and enums + * + */ + + /************************************************************************** + * + * @Struct: + * SDF_TRaster + * + * @Description: + * This struct is used in place of @FT_Raster and is stored within the + * internal FreeType renderer struct. While rasterizing it is passed to + * the @FT_Raster_RenderFunc function, which then can be used however we + * want. + * + * @Fields: + * memory :: + * Used internally to allocate intermediate memory while raterizing. + * + */ + typedef struct SDF_TRaster_ + { + FT_Memory memory; + + } SDF_TRaster, *SDF_PRaster; + + + /************************************************************************** + * + * @Enum: + * SDF_Edge_Type + * + * @Description: + * Enumeration of all curve types present in fonts. + * + * @Fields: + * SDF_EDGE_UNDEFINED :: + * Undefined edge, simply used to initialize and detect errors. + * + * SDF_EDGE_LINE :: + * Line segment with start and end point. + * + * SDF_EDGE_CONIC :: + * A conic/quadratic Bezier curve with start, end, and one control + * point. + * + * SDF_EDGE_CUBIC :: + * A cubic Bezier curve with start, end, and two control points. + * + */ + typedef enum SDF_Edge_Type_ + { + SDF_EDGE_UNDEFINED = 0, + SDF_EDGE_LINE = 1, + SDF_EDGE_CONIC = 2, + SDF_EDGE_CUBIC = 3 + + } SDF_Edge_Type; + + + /************************************************************************** + * + * @Enum: + * SDF_Contour_Orientation + * + * @Description: + * Enumeration of all orientation values of a contour. We determine the + * orientation by calculating the area covered by a contour. Contrary + * to values returned by @FT_Outline_Get_Orientation, + * `SDF_Contour_Orientation` is independent of the fill rule, which can + * be different for different font formats. + * + * @Fields: + * SDF_ORIENTATION_NONE :: + * Undefined orientation, used for initialization and error detection. + * + * SDF_ORIENTATION_CW :: + * Clockwise orientation (positive area covered). + * + * SDF_ORIENTATION_CCW :: + * Counter-clockwise orientation (negative area covered). + * + * @Note: + * See @FT_Outline_Get_Orientation for more details. + * + */ + typedef enum SDF_Contour_Orientation_ + { + SDF_ORIENTATION_NONE = 0, + SDF_ORIENTATION_CW = 1, + SDF_ORIENTATION_CCW = 2 + + } SDF_Contour_Orientation; + + + /************************************************************************** + * + * @Struct: + * SDF_Edge + * + * @Description: + * Represent an edge of a contour. + * + * @Fields: + * start_pos :: + * Start position of an edge. Valid for all types of edges. + * + * end_pos :: + * Etart position of an edge. Valid for all types of edges. + * + * control_a :: + * A control point of the edge. Valid only for `SDF_EDGE_CONIC` + * and `SDF_EDGE_CUBIC`. + * + * control_b :: + * Another control point of the edge. Valid only for + * `SDF_EDGE_CONIC`. + * + * edge_type :: + * Type of the edge, see @SDF_Edge_Type for all possible edge types. + * + * next :: + * Used to create a singly linked list, which can be interpreted + * as a contour. + * + */ + typedef struct SDF_Edge_ + { + FT_26D6_Vec start_pos; + FT_26D6_Vec end_pos; + FT_26D6_Vec control_a; + FT_26D6_Vec control_b; + + SDF_Edge_Type edge_type; + + struct SDF_Edge_* next; + + } SDF_Edge; + + + /************************************************************************** + * + * @Struct: + * SDF_Contour + * + * @Description: + * Represent a complete contour, which contains a list of edges. + * + * @Fields: + * last_pos :: + * Contains the value of `end_pos' of the last edge in the list of + * edges. Useful while decomposing the outline with + * @FT_Outline_Decompose. + * + * edges :: + * Linked list of all the edges that make the contour. + * + * next :: + * Used to create a singly linked list, which can be interpreted as a + * complete shape or @FT_Outline. + * + */ + typedef struct SDF_Contour_ + { + FT_26D6_Vec last_pos; + SDF_Edge* edges; + + struct SDF_Contour_* next; + + } SDF_Contour; + + + /************************************************************************** + * + * @Struct: + * SDF_Shape + * + * @Description: + * Represent a complete shape, which is the decomposition of + * @FT_Outline. + * + * @Fields: + * memory :: + * Used internally to allocate memory. + * + * contours :: + * Linked list of all the contours that make the shape. + * + */ + typedef struct SDF_Shape_ + { + FT_Memory memory; + SDF_Contour* contours; + + } SDF_Shape; + + + /************************************************************************** + * + * @Struct: + * SDF_Signed_Distance + * + * @Description: + * Represent signed distance of a point, i.e., the distance of the edge + * nearest to the point. + * + * @Fields: + * distance :: + * Distance of the point from the nearest edge. Can be squared or + * absolute depending on the `USE_SQUARED_DISTANCES` macro defined in + * file `ftsdfcommon.h`. + * + * cross :: + * Cross product of the shortest distance vector (i.e., the vector + * from the point to the nearest edge) and the direction of the edge + * at the nearest point. This is used to resolve ambiguities of + * `sign`. + * + * sign :: + * A value used to indicate whether the distance vector is outside or + * inside the contour corresponding to the edge. + * + * @Note: + * `sign` may or may not be correct, therefore it must be checked + * properly in case there is an ambiguity. + * + */ + typedef struct SDF_Signed_Distance_ + { + FT_16D16 distance; + FT_16D16 cross; + FT_Char sign; + + } SDF_Signed_Distance; + + + /************************************************************************** + * + * @Struct: + * SDF_Params + * + * @Description: + * Yet another internal parameters required by the rasterizer. + * + * @Fields: + * orientation :: + * This is not the @SDF_Contour_Orientation value but @FT_Orientation, + * which determines whether clockwise-oriented outlines are to be + * filled or counter-clockwise-oriented ones. + * + * flip_sign :: + * If set to true, flip the sign. By default the points filled by the + * outline are positive. + * + * flip_y :: + * If set to true the output bitmap is upside-down. Can be useful + * because OpenGL and DirectX use different coordinate systems for + * textures. + * + * overload_sign :: + * In the subdivision and bounding box optimization, the default + * outside sign is taken as -1. This parameter can be used to modify + * that behaviour. For example, while generating SDF for a single + * counter-clockwise contour, the outside sign should be 1. + * + */ + typedef struct SDF_Params_ + { + FT_Orientation orientation; + FT_Bool flip_sign; + FT_Bool flip_y; + + FT_Int overload_sign; + + } SDF_Params; + + + /************************************************************************** + * + * constants, initializer, and destructor + * + */ + + static + const FT_Vector zero_vector = { 0, 0 }; + + static + const SDF_Edge null_edge = { { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 }, + SDF_EDGE_UNDEFINED, NULL }; + + static + const SDF_Contour null_contour = { { 0, 0 }, NULL, NULL }; + + static + const SDF_Shape null_shape = { NULL, NULL }; + + static + const SDF_Signed_Distance max_sdf = { INT_MAX, 0, 0 }; + + + /* Create a new @SDF_Edge on the heap and assigns the `edge` */ + /* pointer to the newly allocated memory. */ + static FT_Error + sdf_edge_new( FT_Memory memory, + SDF_Edge** edge ) + { + FT_Error error = FT_Err_Ok; + SDF_Edge* ptr = NULL; + + + if ( !memory || !edge ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_edge; + *edge = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `edge` variable. */ + static void + sdf_edge_done( FT_Memory memory, + SDF_Edge** edge ) + { + if ( !memory || !edge || !*edge ) + return; + + FT_FREE( *edge ); + } + + + /* Create a new @SDF_Contour on the heap and assign */ + /* the `contour` pointer to the newly allocated memory. */ + static FT_Error + sdf_contour_new( FT_Memory memory, + SDF_Contour** contour ) + { + FT_Error error = FT_Err_Ok; + SDF_Contour* ptr = NULL; + + + if ( !memory || !contour ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_contour; + *contour = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `contour` variable. */ + /* Also free the list of edges. */ + static void + sdf_contour_done( FT_Memory memory, + SDF_Contour** contour ) + { + SDF_Edge* edges; + SDF_Edge* temp; + + + if ( !memory || !contour || !*contour ) + return; + + edges = (*contour)->edges; + + /* release all edges */ + while ( edges ) + { + temp = edges; + edges = edges->next; + + sdf_edge_done( memory, &temp ); + } + + FT_FREE( *contour ); + } + + + /* Create a new @SDF_Shape on the heap and assign */ + /* the `shape` pointer to the newly allocated memory. */ + static FT_Error + sdf_shape_new( FT_Memory memory, + SDF_Shape** shape ) + { + FT_Error error = FT_Err_Ok; + SDF_Shape* ptr = NULL; + + + if ( !memory || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( !FT_QNEW( ptr ) ) + { + *ptr = null_shape; + ptr->memory = memory; + *shape = ptr; + } + + Exit: + return error; + } + + + /* Free the allocated `shape` variable. */ + /* Also free the list of contours. */ + static void + sdf_shape_done( SDF_Shape** shape ) + { + FT_Memory memory; + SDF_Contour* contours; + SDF_Contour* temp; + + + if ( !shape || !*shape ) + return; + + memory = (*shape)->memory; + contours = (*shape)->contours; + + if ( !memory ) + return; + + /* release all contours */ + while ( contours ) + { + temp = contours; + contours = contours->next; + + sdf_contour_done( memory, &temp ); + } + + /* release the allocated shape struct */ + FT_FREE( *shape ); + } + + + /************************************************************************** + * + * shape decomposition functions + * + */ + + /* This function is called when starting a new contour at `to`, */ + /* which gets added to the shape's list. */ + static FT_Error + sdf_move_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_CALL( sdf_contour_new( memory, &contour ) ); + + contour->last_pos = *to; + contour->next = shape->contours; + shape->contours = contour; + + Exit: + return error; + } + + + /* This function is called when there is a line in the */ + /* contour. The line starts at the previous edge point and */ + /* stops at `to`. */ + static FT_Error + sdf_line_to( const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + if ( contour->last_pos.x == to->x && + contour->last_pos.y == to->y ) + goto Exit; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_LINE; + edge->start_pos = contour->last_pos; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a conic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with control point `control_1`. */ + static FT_Error + sdf_conic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + /* If the control point coincides with any of the end points */ + /* then it is a line and should be treated as one to avoid */ + /* unnecessary complexity later in the algorithm. */ + if ( ( contour->last_pos.x == control_1->x && + contour->last_pos.y == control_1->y ) || + ( control_1->x == to->x && + control_1->y == to->y ) ) + { + sdf_line_to( to, user ); + goto Exit; + } + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CONIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* This function is called when there is a cubic Bezier curve */ + /* in the contour. The curve starts at the previous edge point */ + /* and stops at `to`, with two control points `control_1` and */ + /* `control_2`. */ + static FT_Error + sdf_cubic_to( const FT_26D6_Vec* control_1, + const FT_26D6_Vec* control_2, + const FT_26D6_Vec* to, + void* user ) + { + SDF_Shape* shape = ( SDF_Shape* )user; + SDF_Edge* edge = NULL; + SDF_Contour* contour = NULL; + + FT_Error error = FT_Err_Ok; + FT_Memory memory = shape->memory; + + + if ( !control_2 || !control_1 || !to || !user ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contour = shape->contours; + + FT_CALL( sdf_edge_new( memory, &edge ) ); + + edge->edge_type = SDF_EDGE_CUBIC; + edge->start_pos = contour->last_pos; + edge->control_a = *control_1; + edge->control_b = *control_2; + edge->end_pos = *to; + + edge->next = contour->edges; + contour->edges = edge; + contour->last_pos = *to; + + Exit: + return error; + } + + + /* Construct the structure to hold all four outline */ + /* decomposition functions. */ + FT_DEFINE_OUTLINE_FUNCS( + sdf_decompose_funcs, + + (FT_Outline_MoveTo_Func) sdf_move_to, /* move_to */ + (FT_Outline_LineTo_Func) sdf_line_to, /* line_to */ + (FT_Outline_ConicTo_Func)sdf_conic_to, /* conic_to */ + (FT_Outline_CubicTo_Func)sdf_cubic_to, /* cubic_to */ + + 0, /* shift */ + 0 /* delta */ + ) + + + /* Decompose `outline` and put it into the `shape` structure. */ + static FT_Error + sdf_outline_decompose( FT_Outline* outline, + SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + + + if ( !outline || !shape ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + error = FT_Outline_Decompose( outline, + &sdf_decompose_funcs, + (void*)shape ); + + Exit: + return error; + } + + + /************************************************************************** + * + * utility functions + * + */ + + /* Return the control box of an edge. The control box is a rectangle */ + /* in which all the control points can fit tightly. */ + static FT_CBox + get_control_box( SDF_Edge edge ) + { + FT_CBox cbox = { 0, 0, 0, 0 }; + FT_Bool is_set = 0; + + + switch ( edge.edge_type ) + { + case SDF_EDGE_CUBIC: + cbox.xMin = edge.control_b.x; + cbox.xMax = edge.control_b.x; + cbox.yMin = edge.control_b.y; + cbox.yMax = edge.control_b.y; + + is_set = 1; + FALL_THROUGH; + + case SDF_EDGE_CONIC: + if ( is_set ) + { + cbox.xMin = edge.control_a.x < cbox.xMin + ? edge.control_a.x + : cbox.xMin; + cbox.xMax = edge.control_a.x > cbox.xMax + ? edge.control_a.x + : cbox.xMax; + + cbox.yMin = edge.control_a.y < cbox.yMin + ? edge.control_a.y + : cbox.yMin; + cbox.yMax = edge.control_a.y > cbox.yMax + ? edge.control_a.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.control_a.x; + cbox.xMax = edge.control_a.x; + cbox.yMin = edge.control_a.y; + cbox.yMax = edge.control_a.y; + + is_set = 1; + } + FALL_THROUGH; + + case SDF_EDGE_LINE: + if ( is_set ) + { + cbox.xMin = edge.start_pos.x < cbox.xMin + ? edge.start_pos.x + : cbox.xMin; + cbox.xMax = edge.start_pos.x > cbox.xMax + ? edge.start_pos.x + : cbox.xMax; + + cbox.yMin = edge.start_pos.y < cbox.yMin + ? edge.start_pos.y + : cbox.yMin; + cbox.yMax = edge.start_pos.y > cbox.yMax + ? edge.start_pos.y + : cbox.yMax; + } + else + { + cbox.xMin = edge.start_pos.x; + cbox.xMax = edge.start_pos.x; + cbox.yMin = edge.start_pos.y; + cbox.yMax = edge.start_pos.y; + } + + cbox.xMin = edge.end_pos.x < cbox.xMin + ? edge.end_pos.x + : cbox.xMin; + cbox.xMax = edge.end_pos.x > cbox.xMax + ? edge.end_pos.x + : cbox.xMax; + + cbox.yMin = edge.end_pos.y < cbox.yMin + ? edge.end_pos.y + : cbox.yMin; + cbox.yMax = edge.end_pos.y > cbox.yMax + ? edge.end_pos.y + : cbox.yMax; + + break; + + default: + break; + } + + return cbox; + } + + + /* Return orientation of a single contour. */ + /* Note that the orientation is independent of the fill rule! */ + /* So, for TTF a clockwise-oriented contour has to be filled */ + /* and the opposite for OTF fonts. */ + static SDF_Contour_Orientation + get_contour_orientation ( SDF_Contour* contour ) + { + SDF_Edge* head = NULL; + FT_26D6 area = 0; + + + /* return none if invalid parameters */ + if ( !contour || !contour->edges ) + return SDF_ORIENTATION_NONE; + + head = contour->edges; + + /* Calculate the area of the control box for all edges. */ + while ( head ) + { + switch ( head->edge_type ) + { + case SDF_EDGE_LINE: + area += MUL_26D6( ( head->end_pos.x - head->start_pos.x ), + ( head->end_pos.y + head->start_pos.y ) ); + break; + + case SDF_EDGE_CONIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->end_pos.x - head->control_a.x, + head->end_pos.y + head->control_a.y ); + break; + + case SDF_EDGE_CUBIC: + area += MUL_26D6( head->control_a.x - head->start_pos.x, + head->control_a.y + head->start_pos.y ); + area += MUL_26D6( head->control_b.x - head->control_a.x, + head->control_b.y + head->control_a.y ); + area += MUL_26D6( head->end_pos.x - head->control_b.x, + head->end_pos.y + head->control_b.y ); + break; + + default: + return SDF_ORIENTATION_NONE; + } + + head = head->next; + } + + /* Clockwise contours cover a positive area, and counter-clockwise */ + /* contours cover a negative area. */ + if ( area > 0 ) + return SDF_ORIENTATION_CW; + else + return SDF_ORIENTATION_CCW; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a conic */ + /* into two conics exactly half way at t = 0.5. */ + static void + split_conic( FT_26D6_Vec* base ) + { + FT_26D6 a, b; + + + base[4].x = base[2].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b / 2; + base[2].x = ( a + b ) / 4; + base[1].x = a / 2; + + base[4].y = base[2].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b / 2; + base[2].y = ( a + b ) / 4; + base[1].y = a / 2; + } + + + /* This function is exactly the same as the one */ + /* in the smooth renderer. It splits a cubic */ + /* into two cubics exactly half way at t = 0.5. */ + static void + split_cubic( FT_26D6_Vec* base ) + { + FT_26D6 a, b, c; + + + base[6].x = base[3].x; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c / 2; + c += b; + base[4].x = c / 4; + base[1].x = a / 2; + a += b; + base[2].x = a / 4; + base[3].x = ( a + c ) / 8; + + base[6].y = base[3].y; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c / 2; + c += b; + base[4].y = c / 4; + base[1].y = a / 2; + a += b; + base[2].y = a / 4; + base[3].y = ( a + c ) / 8; + } + + + /* Split a conic Bezier curve into a number of lines */ + /* and add them to `out'. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_conic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[5]; + SDF_Edge* left,* right; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split conic outline */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + + split_conic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_conic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_conic( memory, &cpos[2], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left ) ); + FT_CALL( sdf_edge_new( memory, &right ) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[2]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[2]; + right->end_pos = cpos[4]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Split a cubic Bezier curve into a number of lines */ + /* and add them to `out`. */ + /* */ + /* This function uses recursion; we thus need */ + /* parameter `max_splits' for stopping. */ + static FT_Error + split_sdf_cubic( FT_Memory memory, + FT_26D6_Vec* control_points, + FT_UInt max_splits, + SDF_Edge** out ) + { + FT_Error error = FT_Err_Ok; + FT_26D6_Vec cpos[7]; + SDF_Edge* left, *right; + const FT_26D6 threshold = ONE_PIXEL / 4; + + + if ( !memory || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* split the cubic */ + cpos[0] = control_points[0]; + cpos[1] = control_points[1]; + cpos[2] = control_points[2]; + cpos[3] = control_points[3]; + + /* If the segment is flat enough we won't get any benefit by */ + /* splitting it further, so we can just stop splitting. */ + /* */ + /* Check the deviation of the Bezier curve and stop if it is */ + /* smaller than the pre-defined `threshold` value. */ + if ( FT_ABS( 2 * cpos[0].x - 3 * cpos[1].x + cpos[3].x ) < threshold && + FT_ABS( 2 * cpos[0].y - 3 * cpos[1].y + cpos[3].y ) < threshold && + FT_ABS( cpos[0].x - 3 * cpos[2].x + 2 * cpos[3].x ) < threshold && + FT_ABS( cpos[0].y - 3 * cpos[2].y + 2 * cpos[3].y ) < threshold ) + { + split_cubic( cpos ); + goto Append; + } + + split_cubic( cpos ); + + /* If max number of splits is done */ + /* then stop and add the lines to */ + /* the list. */ + if ( max_splits <= 2 ) + goto Append; + + /* Otherwise keep splitting. */ + FT_CALL( split_sdf_cubic( memory, &cpos[0], max_splits / 2, out ) ); + FT_CALL( split_sdf_cubic( memory, &cpos[3], max_splits / 2, out ) ); + + /* [NOTE]: This is not an efficient way of */ + /* splitting the curve. Check the deviation */ + /* instead and stop if the deviation is less */ + /* than a pixel. */ + + goto Exit; + + Append: + /* Do allocation and add the lines to the list. */ + + FT_CALL( sdf_edge_new( memory, &left) ); + FT_CALL( sdf_edge_new( memory, &right) ); + + left->start_pos = cpos[0]; + left->end_pos = cpos[3]; + left->edge_type = SDF_EDGE_LINE; + + right->start_pos = cpos[3]; + right->end_pos = cpos[6]; + right->edge_type = SDF_EDGE_LINE; + + left->next = right; + right->next = (*out); + *out = left; + + Exit: + return error; + } + + + /* Subdivide an entire shape into line segments */ + /* such that it doesn't look visually different */ + /* from the original curve. */ + static FT_Error + split_sdf_shape( SDF_Shape* shape ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + SDF_Contour* contours; + SDF_Contour* new_contours = NULL; + + + if ( !shape || !shape->memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + contours = shape->contours; + memory = shape->memory; + + /* for each contour */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + SDF_Edge* new_edges = NULL; + + SDF_Contour* tempc; + + + /* for each edge */ + while ( edges ) + { + SDF_Edge* edge = edges; + SDF_Edge* temp; + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + /* Just create a duplicate edge in case */ + /* it is a line. We can use the same edge. */ + FT_CALL( sdf_edge_new( memory, &temp ) ); + + ft_memcpy( temp, edge, sizeof ( *edge ) ); + + temp->next = new_edges; + new_edges = temp; + break; + + case SDF_EDGE_CONIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[3]; + FT_26D6 dx, dy; + FT_UInt num_splits; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->end_pos; + + dx = FT_ABS( ctrls[2].x + ctrls[0].x - 2 * ctrls[1].x ); + dy = FT_ABS( ctrls[2].y + ctrls[0].y - 2 * ctrls[1].y ); + if ( dx < dy ) + dx = dy; + + /* Calculate the number of necessary bisections. Each */ + /* bisection causes a four-fold reduction of the deviation, */ + /* hence we bisect the Bezier curve until the deviation */ + /* becomes less than 1/8 of a pixel. For more details */ + /* check file `ftgrays.c`. */ + num_splits = 1; + while ( dx > ONE_PIXEL / 8 ) + { + dx >>= 2; + num_splits <<= 1; + } + + error = split_sdf_conic( memory, ctrls, num_splits, &new_edges ); + } + break; + + case SDF_EDGE_CUBIC: + /* Subdivide the curve and add it to the list. */ + { + FT_26D6_Vec ctrls[4]; + + + ctrls[0] = edge->start_pos; + ctrls[1] = edge->control_a; + ctrls[2] = edge->control_b; + ctrls[3] = edge->end_pos; + + error = split_sdf_cubic( memory, ctrls, 32, &new_edges ); + } + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + if ( error != FT_Err_Ok ) + goto Exit; + + edges = edges->next; + } + + /* add to the contours list */ + FT_CALL( sdf_contour_new( memory, &tempc ) ); + + tempc->next = new_contours; + tempc->edges = new_edges; + new_contours = tempc; + new_edges = NULL; + + /* deallocate the contour */ + tempc = contours; + contours = contours->next; + + sdf_contour_done( memory, &tempc ); + } + + shape->contours = new_contours; + + Exit: + return error; + } + + + /************************************************************************** + * + * for debugging + * + */ + +#ifdef FT_DEBUG_LEVEL_TRACE + + static void + sdf_shape_dump( SDF_Shape* shape ) + { + FT_UInt num_contours = 0; + + FT_UInt total_edges = 0; + FT_UInt total_lines = 0; + FT_UInt total_conic = 0; + FT_UInt total_cubic = 0; + + SDF_Contour* contour_list; + + + if ( !shape ) + { + FT_TRACE5(( "sdf_shape_dump: null shape\n" )); + return; + } + + contour_list = shape->contours; + + FT_TRACE5(( "sdf_shape_dump (values are in 26.6 format):\n" )); + + while ( contour_list ) + { + FT_UInt num_edges = 0; + SDF_Edge* edge_list; + SDF_Contour* contour = contour_list; + + + FT_TRACE5(( " Contour %u\n", num_contours )); + + edge_list = contour->edges; + + while ( edge_list ) + { + SDF_Edge* edge = edge_list; + + + FT_TRACE5(( " %3u: ", num_edges )); + + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + FT_TRACE5(( "Line: (%ld, %ld) -- (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->end_pos.x, edge->end_pos.y )); + total_lines++; + break; + + case SDF_EDGE_CONIC: + FT_TRACE5(( "Conic: (%ld, %ld) .. (%ld, %ld) .. (%ld, %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->end_pos.x, edge->end_pos.y )); + total_conic++; + break; + + case SDF_EDGE_CUBIC: + FT_TRACE5(( "Cubic: (%ld, %ld) .. (%ld, %ld)" + " .. (%ld, %ld) .. (%ld %ld)\n", + edge->start_pos.x, edge->start_pos.y, + edge->control_a.x, edge->control_a.y, + edge->control_b.x, edge->control_b.y, + edge->end_pos.x, edge->end_pos.y )); + total_cubic++; + break; + + default: + break; + } + + num_edges++; + total_edges++; + edge_list = edge_list->next; + } + + num_contours++; + contour_list = contour_list->next; + } + + FT_TRACE5(( "\n" )); + FT_TRACE5(( " total number of contours = %u\n", num_contours )); + FT_TRACE5(( " total number of edges = %u\n", total_edges )); + FT_TRACE5(( " |__lines = %u\n", total_lines )); + FT_TRACE5(( " |__conic = %u\n", total_conic )); + FT_TRACE5(( " |__cubic = %u\n", total_cubic )); + } + +#endif /* FT_DEBUG_LEVEL_TRACE */ + + + /************************************************************************** + * + * math functions + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* [NOTE]: All the functions below down until rasterizer */ + /* can be avoided if we decide to subdivide the */ + /* curve into lines. */ + + /* This function uses Newton's iteration to find */ + /* the cube root of a fixed-point integer. */ + static FT_16D16 + cube_root( FT_16D16 val ) + { + /* [IMPORTANT]: This function is not good as it may */ + /* not break, so use a lookup table instead. Or we */ + /* can use an algorithm similar to `square_root`. */ + + FT_Int v, g, c; + + + if ( val == 0 || + val == -FT_INT_16D16( 1 ) || + val == FT_INT_16D16( 1 ) ) + return val; + + v = val < 0 ? -val : val; + g = square_root( v ); + c = 0; + + while ( 1 ) + { + c = FT_MulFix( FT_MulFix( g, g ), g ) - v; + c = FT_DivFix( c, 3 * FT_MulFix( g, g ) ); + + g -= c; + + if ( ( c < 0 ? -c : c ) < 30 ) + break; + } + + return val < 0 ? -g : g; + } + + + /* Calculate the perpendicular by using '1 - base^2'. */ + /* Then use arctan to compute the angle. */ + static FT_16D16 + arc_cos( FT_16D16 val ) + { + FT_16D16 p; + FT_16D16 b = val; + FT_16D16 one = FT_INT_16D16( 1 ); + + + if ( b > one ) + b = one; + if ( b < -one ) + b = -one; + + p = one - FT_MulFix( b, b ); + p = square_root( p ); + + return FT_Atan2( b, p ); + } + + + /* Compute roots of a quadratic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/QuadraticFormula.html */ + static FT_UShort + solve_quadratic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_16D16 out[2] ) + { + FT_16D16 discriminant = 0; + + + a = FT_26D6_16D16( a ); + b = FT_26D6_16D16( b ); + c = FT_26D6_16D16( c ); + + if ( a == 0 ) + { + if ( b == 0 ) + return 0; + else + { + out[0] = FT_DivFix( -c, b ); + + return 1; + } + } + + discriminant = FT_MulFix( b, b ) - 4 * FT_MulFix( a, c ); + + if ( discriminant < 0 ) + return 0; + else if ( discriminant == 0 ) + { + out[0] = FT_DivFix( -b, 2 * a ); + + return 1; + } + else + { + discriminant = square_root( discriminant ); + + out[0] = FT_DivFix( -b + discriminant, 2 * a ); + out[1] = FT_DivFix( -b - discriminant, 2 * a ); + + return 2; + } + } + + + /* Compute roots of a cubic polynomial, assign them to `out`, */ + /* and return number of real roots. */ + /* */ + /* The procedure can be found at */ + /* */ + /* https://mathworld.wolfram.com/CubicFormula.html */ + static FT_UShort + solve_cubic_equation( FT_26D6 a, + FT_26D6 b, + FT_26D6 c, + FT_26D6 d, + FT_16D16 out[3] ) + { + FT_16D16 q = 0; /* intermediate */ + FT_16D16 r = 0; /* intermediate */ + + FT_16D16 a2 = b; /* x^2 coefficients */ + FT_16D16 a1 = c; /* x coefficients */ + FT_16D16 a0 = d; /* constant */ + + FT_16D16 q3 = 0; + FT_16D16 r2 = 0; + FT_16D16 a23 = 0; + FT_16D16 a22 = 0; + FT_16D16 a1x2 = 0; + + + /* cutoff value for `a` to be a cubic, otherwise solve quadratic */ + if ( a == 0 || FT_ABS( a ) < 16 ) + return solve_quadratic_equation( b, c, d, out ); + + if ( d == 0 ) + { + out[0] = 0; + + return solve_quadratic_equation( a, b, c, out + 1 ) + 1; + } + + /* normalize the coefficients; this also makes them 16.16 */ + a2 = FT_DivFix( a2, a ); + a1 = FT_DivFix( a1, a ); + a0 = FT_DivFix( a0, a ); + + /* compute intermediates */ + a1x2 = FT_MulFix( a1, a2 ); + a22 = FT_MulFix( a2, a2 ); + a23 = FT_MulFix( a22, a2 ); + + q = ( 3 * a1 - a22 ) / 9; + r = ( 9 * a1x2 - 27 * a0 - 2 * a23 ) / 54; + + /* [BUG]: `q3` and `r2` still cause underflow. */ + + q3 = FT_MulFix( q, q ); + q3 = FT_MulFix( q3, q ); + + r2 = FT_MulFix( r, r ); + + if ( q3 < 0 && r2 < -q3 ) + { + FT_16D16 t = 0; + + + q3 = square_root( -q3 ); + t = FT_DivFix( r, q3 ); + + if ( t > ( 1 << 16 ) ) + t = ( 1 << 16 ); + if ( t < -( 1 << 16 ) ) + t = -( 1 << 16 ); + + t = arc_cos( t ); + a2 /= 3; + q = 2 * square_root( -q ); + + out[0] = FT_MulFix( q, FT_Cos( t / 3 ) ) - a2; + out[1] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 2 ) / 3 ) ) - a2; + out[2] = FT_MulFix( q, FT_Cos( ( t + FT_ANGLE_PI * 4 ) / 3 ) ) - a2; + + return 3; + } + + else if ( r2 == -q3 ) + { + FT_16D16 s = 0; + + + s = cube_root( r ); + a2 /= -3; + + out[0] = a2 + ( 2 * s ); + out[1] = a2 - s; + + return 2; + } + + else + { + FT_16D16 s = 0; + FT_16D16 t = 0; + FT_16D16 dis = 0; + + + if ( q3 == 0 ) + dis = FT_ABS( r ); + else + dis = square_root( q3 + r2 ); + + s = cube_root( r + dis ); + t = cube_root( r - dis ); + a2 /= -3; + out[0] = ( a2 + ( s + t ) ); + + return 1; + } + } + +#endif /* !USE_NEWTON_FOR_CONIC */ + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** RASTERIZER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * @Function: + * resolve_corner + * + * @Description: + * At some places on the grid two edges can give opposite directions; + * this happens when the closest point is on one of the endpoint. In + * that case we need to check the proper sign. + * + * This can be visualized by an example: + * + * ``` + * x + * + * o + * ^ \ + * / \ + * / \ + * (a) / \ (b) + * / \ + * / \ + * / v + * ``` + * + * Suppose `x` is the point whose shortest distance from an arbitrary + * contour we want to find out. It is clear that `o` is the nearest + * point on the contour. Now to determine the sign we do a cross + * product of the shortest distance vector and the edge direction, i.e., + * + * ``` + * => sign = cross(x - o, direction(a)) + * ``` + * + * Using the right hand thumb rule we can see that the sign will be + * positive. + * + * If we use `b', however, we have + * + * ``` + * => sign = cross(x - o, direction(b)) + * ``` + * + * In this case the sign will be negative. To determine the correct + * sign we thus divide the plane in two halves and check which plane the + * point lies in. + * + * ``` + * | + * x | + * | + * o + * ^|\ + * / | \ + * / | \ + * (a) / | \ (b) + * / | \ + * / \ + * / v + * ``` + * + * We can see that `x` lies in the plane of `a`, so we take the sign + * determined by `a`. This test can be easily done by calculating the + * orthogonality and taking the greater one. + * + * The orthogonality is simply the sinus of the two vectors (i.e., + * x - o) and the corresponding direction. We efficiently pre-compute + * the orthogonality with the corresponding `get_min_distance_*` + * functions. + * + * @Input: + * sdf1 :: + * First signed distance (can be any of `a` or `b`). + * + * sdf1 :: + * Second signed distance (can be any of `a` or `b`). + * + * @Return: + * The correct signed distance, which is computed by using the above + * algorithm. + * + * @Note: + * The function does not care about the actual distance, it simply + * returns the signed distance which has a larger cross product. As a + * consequence, this function should not be used if the two distances + * are fairly apart. In that case simply use the signed distance with + * a shorter absolute distance. + * + */ + static SDF_Signed_Distance + resolve_corner( SDF_Signed_Distance sdf1, + SDF_Signed_Distance sdf2 ) + { + return FT_ABS( sdf1.cross ) > FT_ABS( sdf2.cross ) ? sdf1 : sdf2; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_line + * + * @Description: + * Find the shortest distance from the `line` segment to a given `point` + * and assign it to `out`. Use it for line segments only. + * + * @Input: + * line :: + * The line segment to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `line`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `line' parameter must have an edge type of `SDF_EDGE_LINE`. + * + */ + static FT_Error + get_min_distance_line( SDF_Edge* line, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * In order to calculate the shortest distance from a point to + * a line segment, we do the following. Let's assume that + * + * ``` + * a = start point of the line segment + * b = end point of the line segment + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) Write the parametric equation of the line. + * + * ``` + * point_on_line = a + (b - a) * t (t is the factor) + * ``` + * + * (2) Find the projection of point `p` on the line. The projection + * will be perpendicular to the line, which allows us to get the + * solution by making the dot product zero. + * + * ``` + * (point_on_line - a) . (p - point_on_line) = 0 + * + * (point_on_line) + * (a) x-------o----------------x (b) + * |_| + * | + * | + * (p) + * ``` + * + * (3) Simplification of the above equation yields the factor of + * `point_on_line`: + * + * ``` + * t = ((p - a) . (b - a)) / |b - a|^2 + * ``` + * + * (4) We clamp factor `t` between [0.0f, 1.0f] because `point_on_line` + * can be outside of the line segment: + * + * ``` + * (point_on_line) + * (a) x------------------------x (b) -----o--- + * |_| + * | + * | + * (p) + * ``` + * + * (5) Finally, the distance we are interested in is + * + * ``` + * |point_on_line - p| + * ``` + */ + + FT_Error error = FT_Err_Ok; + + FT_Vector a; /* start position */ + FT_Vector b; /* end position */ + FT_Vector p; /* current point */ + + FT_26D6_Vec line_segment; /* `b` - `a` */ + FT_26D6_Vec p_sub_a; /* `p` - `a` */ + + FT_26D6 sq_line_length; /* squared length of `line_segment` */ + FT_16D16 factor; /* factor of the nearest point */ + FT_26D6 cross; /* used to determine sign */ + + FT_16D16_Vec nearest_point; /* `point_on_line` */ + FT_16D16_Vec nearest_vector; /* `p` - `nearest_point` */ + + + if ( !line || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( line->edge_type != SDF_EDGE_LINE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + a = line->start_pos; + b = line->end_pos; + p = point; + + line_segment.x = b.x - a.x; + line_segment.y = b.y - a.y; + + p_sub_a.x = p.x - a.x; + p_sub_a.y = p.y - a.y; + + sq_line_length = ( line_segment.x * line_segment.x ) / 64 + + ( line_segment.y * line_segment.y ) / 64; + + /* currently factor is 26.6 */ + factor = ( p_sub_a.x * line_segment.x ) / 64 + + ( p_sub_a.y * line_segment.y ) / 64; + + /* now factor is 16.16 */ + factor = FT_DivFix( factor, sq_line_length ); + + /* clamp the factor between 0.0 and 1.0 in fixed-point */ + if ( factor > FT_INT_16D16( 1 ) ) + factor = FT_INT_16D16( 1 ); + if ( factor < 0 ) + factor = 0; + + nearest_point.x = FT_MulFix( FT_26D6_16D16( line_segment.x ), + factor ); + nearest_point.y = FT_MulFix( FT_26D6_16D16( line_segment.y ), + factor ); + + nearest_point.x = FT_26D6_16D16( a.x ) + nearest_point.x; + nearest_point.y = FT_26D6_16D16( a.y ) + nearest_point.y; + + nearest_vector.x = nearest_point.x - FT_26D6_16D16( p.x ); + nearest_vector.y = nearest_point.y - FT_26D6_16D16( p.y ); + + cross = FT_MulFix( nearest_vector.x, line_segment.y ) - + FT_MulFix( nearest_vector.y, line_segment.x ); + + /* assign the output */ + out->sign = cross < 0 ? 1 : -1; + out->distance = VECTOR_LENGTH_16D16( nearest_vector ); + + /* Instead of finding `cross` for checking corner we */ + /* directly set it here. This is more efficient */ + /* because if the distance is perpendicular we can */ + /* directly set it to 1. */ + if ( factor != 0 && factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); + else + { + /* [OPTIMIZATION]: Pre-compute this direction. */ + /* If not perpendicular then compute `cross`. */ + FT_Vector_NormLen( &line_segment ); + FT_Vector_NormLen( &nearest_vector ); + + out->cross = FT_MulFix( line_segment.x, nearest_vector.y ) - + FT_MulFix( line_segment.y, nearest_vector.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * get_min_distance_conic + * + * @Description: + * Find the shortest distance from the `conic` Bezier curve to a given + * `point` and assign it to `out`. Use it for conic/quadratic curves + * only. + * + * @Input: + * conic :: + * The conic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `conic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The `conic` parameter must have an edge type of `SDF_EDGE_CONIC`. + * + */ + +#if !USE_NEWTON_FOR_CONIC + + /* + * The function uses an analytical method to find the shortest distance + * which is faster than the Newton-Raphson method, but has underflows at + * the moment. Use Newton's method if you can see artifacts in the SDF. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a + * quadratic Bezier curve is similar to the line segment algorithm. The + * shortest distance is perpendicular to the Bezier curve; the only + * difference from line is that there can be more than one + * perpendicular, and we also have to check the endpoints, because the + * perpendicular may not be the shortest. + * + * Let's assume that + * ``` + * p0 = first endpoint + * p1 = control point + * p2 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` a factor in the range [0.0f, 1.0f]. This equation can + * be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = p1 - p0 + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + 2t * B + p0 + * ``` + * + * (2) The derivative of the last equation above is + * + * ``` + * B'(t) = 2 *(tA + B) + * ``` + * + * (3) To find the shortest distance from `p` to `B(t)` we find the + * point on the curve at which the shortest distance vector (i.e., + * `B(t) - p`) and the direction (i.e., `B'(t)`) make 90 degrees. + * In other words, we make the dot product zero. + * + * ``` + * (B(t) - p) . (B'(t)) = 0 + * (t^2 * A + 2t * B + p0 - p) . (2 * (tA + B)) = 0 + * ``` + * + * After simplifying we get a cubic equation + * + * ``` + * at^3 + bt^2 + ct + d = 0 + * ``` + * + * with + * + * ``` + * a = A.A + * b = 3A.B + * c = 2B.B + A.p0 - A.p + * d = p0.B - p.B + * ``` + * + * (4) Now the roots of the equation can be computed using 'Cardano's + * Cubic formula'; we clamp the roots in the range [0.0f, 1.0f]. + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB; /* A, B in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_26D6 a, b, c, d; /* cubic coefficients */ + + FT_16D16 roots[3] = { 0, 0, 0 }; /* real roots of the cubic eq. */ + FT_16D16 min_factor; /* factor at `nearest_point` */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort num_roots; /* number of real roots of cubic */ + FT_UShort i; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = p1.x - p0.x; + bB.y = p1.y - p0.y; + + /* compute cubic coefficients */ + a = VEC_26D6_DOT( aA, aA ); + + b = 3 * VEC_26D6_DOT( aA, bB ); + + c = 2 * VEC_26D6_DOT( bB, bB ) + + VEC_26D6_DOT( aA, p0 ) - + VEC_26D6_DOT( aA, p ); + + d = VEC_26D6_DOT( p0, bB ) - + VEC_26D6_DOT( p, bB ); + + /* find the roots */ + num_roots = solve_cubic_equation( a, b, c, d, roots ); + + if ( num_roots == 0 ) + { + roots[0] = 0; + roots[1] = FT_INT_16D16( 1 ); + num_roots = 2; + } + + /* [OPTIMIZATION]: Check the roots, clamp them and discard */ + /* duplicate roots. */ + + /* convert these values to 16.16 for further computation */ + aA.x = FT_26D6_16D16( aA.x ); + aA.y = FT_26D6_16D16( aA.y ); + + bB.x = FT_26D6_16D16( bB.x ); + bB.y = FT_26D6_16D16( bB.y ); + + p0.x = FT_26D6_16D16( p0.x ); + p0.y = FT_26D6_16D16( p0.y ); + + p.x = FT_26D6_16D16( p.x ); + p.y = FT_26D6_16D16( p.y ); + + for ( i = 0; i < num_roots; i++ ) + { + FT_16D16 t = roots[i]; + FT_16D16 t2 = 0; + FT_16D16 dist = 0; + + FT_16D16_Vec curve_point; + FT_16D16_Vec dist_vector; + + /* + * Ideally we should discard the roots which are outside the range + * [0.0, 1.0] and check the endpoints of the Bezier curve, but Behdad + * Esfahbod proved the following lemma. + * + * Lemma: + * + * (1) If the closest point on the curve [0, 1] is to the endpoint at + * `t` = 1 and the cubic has no real roots at `t` = 1 then the + * cubic must have a real root at some `t` > 1. + * + * (2) Similarly, if the closest point on the curve [0, 1] is to the + * endpoint at `t` = 0 and the cubic has no real roots at `t` = 0 + * then the cubic must have a real root at some `t` < 0. + * + * Now because of this lemma we only need to clamp the roots and that + * will take care of the endpoints. + * + * For more details see + * + * https://lists.nongnu.org/archive/html/freetype-devel/2020-06/msg00147.html + */ + + if ( t < 0 ) + t = 0; + if ( t > FT_INT_16D16( 1 ) ) + t = FT_INT_16D16( 1 ); + + t2 = FT_MulFix( t, t ); + + /* B(t) = t^2 * A + 2t * B + p0 - p */ + curve_point.x = FT_MulFix( aA.x, t2 ) + + 2 * FT_MulFix( bB.x, t ) + p0.x; + curve_point.y = FT_MulFix( aA.y, t2 ) + + 2 * FT_MulFix( bB.y, t ) + p0.y; + + /* `curve_point` - `p` */ + dist_vector.x = curve_point.x - p.x; + dist_vector.y = curve_point.y - p.y; + + dist = VECTOR_LENGTH_16D16( dist_vector ); + + if ( dist < min ) + { + min = dist; + nearest_point = curve_point; + min_factor = t; + } + } + + /* B'(t) = 2 * (tA + B) */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + 2 * bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + 2 * bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - p.x, direction.y ) - + FT_MulFix( nearest_point.y - p.y, direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + +#else /* USE_NEWTON_FOR_CONIC */ + + /* + * The function uses Newton's approximation to find the shortest distance, + * which is a bit slower than the analytical method but doesn't cause + * underflow. + */ + static FT_Error + get_min_distance_conic( SDF_Edge* conic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * This method uses Newton-Raphson's approximation to find the shortest + * distance from a point to a conic curve. It does not involve solving + * any cubic equation, that is why there is no risk of underflow. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a quadratic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^2 * p0 + 2(1 - t)t * p1 + t^2 * p2 + * ``` + * + * with `t` the factor in the range [0.0f, 1.0f]. The above + * equation can be rewritten as + * + * ``` + * B(t) = t^2 * (p0 - 2p1 + p2) + 2t * (p1 - p0) + p0 + * ``` + * + * With + * + * ``` + * A = p0 - 2p1 + p2 + * B = 2 * (p1 - p0) + * ``` + * + * we have + * + * ``` + * B(t) = t^2 * A + t * B + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 2t * A + B + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 2A + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^2 * A + t^2 * B + p0 - p + * ``` + * + * With + * + * ``` + * C = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^2 * A + t * B + C + * ``` + * + * (5) Finally, the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degrees with the curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC; /* A, B, C in the above comment */ + FT_26D6_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_26D6_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2; /* control points of a conic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at `nearest_point' */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest squared distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !conic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( conic->edge_type != SDF_EDGE_CONIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = conic->start_pos; + p1 = conic->control_a; + p2 = conic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = p0.x - 2 * p1.x + p2.x; + aA.y = p0.y - 2 * p1.y + p2.y; + + bB.x = 2 * ( p1.x - p0.x ); + bB.y = 2 * ( p1.y - p0.y ); + + cC.x = p0.x; + cC.y = p0.y; + + /* do Newton's iterations */ + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + FT_16D16 factor2; + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point` - `p` */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + + /* B(t) = t^2 * A + t * B + p0 */ + curve_point.x = FT_MulFix( aA.x, factor2 ) + + FT_MulFix( bB.x, factor ) + cC.x; + curve_point.y = FT_MulFix( aA.y, factor2 ) + + FT_MulFix( bB.y, factor ) + cC.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + nearest_point = curve_point; + } + + /* This is Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 2tA + B */ + d1.x = FT_MulFix( aA.x, 2 * factor ) + bB.x; + d1.y = FT_MulFix( aA.y, 2 * factor ) + bB.y; + + /* B''(t) = 2A */ + d2.x = 2 * aA.x; + d2.y = 2 * aA.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 2t * A + B */ + direction.x = 2 * FT_MulFix( aA.x, min_factor ) + bB.x; + direction.y = 2 * FT_MulFix( aA.y, min_factor ) + bB.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + +#endif /* USE_NEWTON_FOR_CONIC */ + + + /************************************************************************** + * + * @Function: + * get_min_distance_cubic + * + * @Description: + * Find the shortest distance from the `cubic` Bezier curve to a given + * `point` and assigns it to `out`. Use it for cubic curves only. + * + * @Input: + * cubic :: + * The cubic Bezier curve to which the shortest distance is to be + * computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `cubic`. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function uses Newton's approximation to find the shortest + * distance. Another way would be to divide the cubic into conic or + * subdivide the curve into lines, but that is not implemented. + * + * The `cubic` parameter must have an edge type of `SDF_EDGE_CUBIC`. + * + */ + static FT_Error + get_min_distance_cubic( SDF_Edge* cubic, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + /* + * The procedure to find the shortest distance from a point to a cubic + * Bezier curve is similar to quadratic curve algorithm. The only + * difference is that while calculating factor `t`, instead of a cubic + * polynomial equation we have to find the roots of a 5th degree + * polynomial equation. Solving this would require a significant amount + * of time, and still the results may not be accurate. We are thus + * going to directly approximate the value of `t` using the Newton-Raphson + * method. + * + * Let's assume that + * + * ``` + * p0 = first endpoint + * p1 = first control point + * p2 = second control point + * p3 = second endpoint + * p = point from which shortest distance is to be calculated + * ``` + * + * (1) The equation of a cubic Bezier curve can be written as + * + * ``` + * B(t) = (1 - t)^3 * p0 + 3(1 - t)^2 t * p1 + + * 3(1 - t)t^2 * p2 + t^3 * p3 + * ``` + * + * The equation can be expanded and written as + * + * ``` + * B(t) = t^3 * (-p0 + 3p1 - 3p2 + p3) + + * 3t^2 * (p0 - 2p1 + p2) + 3t * (-p0 + p1) + p0 + * ``` + * + * With + * + * ``` + * A = -p0 + 3p1 - 3p2 + p3 + * B = 3(p0 - 2p1 + p2) + * C = 3(-p0 + p1) + * ``` + * + * we have + * + * ``` + * B(t) = t^3 * A + t^2 * B + t * C + p0 + * ``` + * + * (2) The derivative of the above equation is + * + * ``` + * B'(t) = 3t^2 * A + 2t * B + C + * ``` + * + * (3) The second derivative of the above equation is + * + * ``` + * B''(t) = 6t * A + 2B + * ``` + * + * (4) The equation `P(t)` of the distance from point `p` to the curve + * can be written as + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + p0 - p + * ``` + * + * With + * + * ``` + * D = p0 - p + * ``` + * + * we have + * + * ``` + * P(t) = t^3 * A + t^2 * B + t * C + D + * ``` + * + * (5) Finally the equation of the angle between `B(t)` and `P(t)` can + * be written as + * + * ``` + * Q(t) = P(t) . B'(t) + * ``` + * + * (6) Our task is to find a value of `t` such that the above equation + * `Q(t)` becomes zero, that is, the point-to-curve vector makes + * 90~degree with curve. We solve this with the Newton-Raphson + * method. + * + * (7) We first assume an arbitrary value of factor `t`, which we then + * improve. + * + * ``` + * t := Q(t) / Q'(t) + * ``` + * + * Putting the value of `Q(t)` from the above equation gives + * + * ``` + * t := P(t) . B'(t) / derivative(P(t) . B'(t)) + * t := P(t) . B'(t) / + * (P'(t) . B'(t) + P(t) . B''(t)) + * ``` + * + * Note that `P'(t)` is the same as `B'(t)` because the constant is + * gone due to the derivative. + * + * (8) Finally we get the equation to improve the factor as + * + * ``` + * t := P(t) . B'(t) / + * (B'(t) . B'( t ) + P(t) . B''(t)) + * ``` + * + * [note]: `B` and `B(t)` are different in the above equations. + */ + + FT_Error error = FT_Err_Ok; + + FT_26D6_Vec aA, bB, cC, dD; /* A, B, C, D in the above comment */ + FT_16D16_Vec nearest_point = { 0, 0 }; + /* point on curve nearest to `point` */ + FT_16D16_Vec direction; /* direction of curve at `nearest_point` */ + + FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */ + FT_26D6_Vec p; /* `point` to which shortest distance */ + + FT_16D16 min_factor = 0; /* factor at shortest distance */ + FT_16D16 min_factor_sq = 0; /* factor at shortest distance */ + FT_16D16 cross; /* to determine the sign */ + FT_16D16 min = FT_INT_MAX; /* shortest distance */ + + FT_UShort iterations; + FT_UShort steps; + + + if ( !cubic || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( cubic->edge_type != SDF_EDGE_CUBIC ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + p0 = cubic->start_pos; + p1 = cubic->control_a; + p2 = cubic->control_b; + p3 = cubic->end_pos; + p = point; + + /* compute substitution coefficients */ + aA.x = -p0.x + 3 * ( p1.x - p2.x ) + p3.x; + aA.y = -p0.y + 3 * ( p1.y - p2.y ) + p3.y; + + bB.x = 3 * ( p0.x - 2 * p1.x + p2.x ); + bB.y = 3 * ( p0.y - 2 * p1.y + p2.y ); + + cC.x = 3 * ( p1.x - p0.x ); + cC.y = 3 * ( p1.y - p0.y ); + + dD.x = p0.x; + dD.y = p0.y; + + for ( iterations = 0; iterations <= MAX_NEWTON_DIVISIONS; iterations++ ) + { + FT_16D16 factor = FT_INT_16D16( iterations ) / MAX_NEWTON_DIVISIONS; + + FT_16D16 factor2; /* factor^2 */ + FT_16D16 factor3; /* factor^3 */ + FT_16D16 length; + + FT_16D16_Vec curve_point; /* point on the curve */ + FT_16D16_Vec dist_vector; /* `curve_point' - `p' */ + + FT_26D6_Vec d1; /* first derivative */ + FT_26D6_Vec d2; /* second derivative */ + + FT_16D16 temp1; + FT_16D16 temp2; + + + for ( steps = 0; steps < MAX_NEWTON_STEPS; steps++ ) + { + factor2 = FT_MulFix( factor, factor ); + factor3 = FT_MulFix( factor2, factor ); + + /* B(t) = t^3 * A + t^2 * B + t * C + D */ + curve_point.x = FT_MulFix( aA.x, factor3 ) + + FT_MulFix( bB.x, factor2 ) + + FT_MulFix( cC.x, factor ) + dD.x; + curve_point.y = FT_MulFix( aA.y, factor3 ) + + FT_MulFix( bB.y, factor2 ) + + FT_MulFix( cC.y, factor ) + dD.y; + + /* convert to 16.16 */ + curve_point.x = FT_26D6_16D16( curve_point.x ); + curve_point.y = FT_26D6_16D16( curve_point.y ); + + /* P(t) in the comment */ + dist_vector.x = curve_point.x - FT_26D6_16D16( p.x ); + dist_vector.y = curve_point.y - FT_26D6_16D16( p.y ); + + length = VECTOR_LENGTH_16D16( dist_vector ); + + if ( length < min ) + { + min = length; + min_factor = factor; + min_factor_sq = factor2; + nearest_point = curve_point; + } + + /* This the Newton's approximation. */ + /* */ + /* t := P(t) . B'(t) / */ + /* (B'(t) . B'(t) + P(t) . B''(t)) */ + + /* B'(t) = 3t^2 * A + 2t * B + C */ + d1.x = FT_MulFix( aA.x, 3 * factor2 ) + + FT_MulFix( bB.x, 2 * factor ) + cC.x; + d1.y = FT_MulFix( aA.y, 3 * factor2 ) + + FT_MulFix( bB.y, 2 * factor ) + cC.y; + + /* B''(t) = 6t * A + 2B */ + d2.x = FT_MulFix( aA.x, 6 * factor ) + 2 * bB.x; + d2.y = FT_MulFix( aA.y, 6 * factor ) + 2 * bB.y; + + dist_vector.x /= 1024; + dist_vector.y /= 1024; + + /* temp1 = P(t) . B'(t) */ + temp1 = VEC_26D6_DOT( dist_vector, d1 ); + + /* temp2 = B'(t) . B'(t) + P(t) . B''(t) */ + temp2 = VEC_26D6_DOT( d1, d1 ) + + VEC_26D6_DOT( dist_vector, d2 ); + + factor -= FT_DivFix( temp1, temp2 ); + + if ( factor < 0 || factor > FT_INT_16D16( 1 ) ) + break; + } + } + + /* B'(t) = 3t^2 * A + 2t * B + C */ + direction.x = FT_MulFix( aA.x, 3 * min_factor_sq ) + + FT_MulFix( bB.x, 2 * min_factor ) + cC.x; + direction.y = FT_MulFix( aA.y, 3 * min_factor_sq ) + + FT_MulFix( bB.y, 2 * min_factor ) + cC.y; + + /* determine the sign */ + cross = FT_MulFix( nearest_point.x - FT_26D6_16D16( p.x ), + direction.y ) - + FT_MulFix( nearest_point.y - FT_26D6_16D16( p.y ), + direction.x ); + + /* assign the values */ + out->distance = min; + out->sign = cross < 0 ? 1 : -1; + + if ( min_factor != 0 && min_factor != FT_INT_16D16( 1 ) ) + out->cross = FT_INT_16D16( 1 ); /* the two are perpendicular */ + else + { + /* convert to nearest vector */ + nearest_point.x -= FT_26D6_16D16( p.x ); + nearest_point.y -= FT_26D6_16D16( p.y ); + + /* compute `cross` if not perpendicular */ + FT_Vector_NormLen( &direction ); + FT_Vector_NormLen( &nearest_point ); + + out->cross = FT_MulFix( direction.x, nearest_point.y ) - + FT_MulFix( direction.y, nearest_point.x ); + } + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_edge_get_min_distance + * + * @Description: + * Find shortest distance from `point` to any type of `edge`. It checks + * the edge type and then calls the relevant `get_min_distance_*` + * function. + * + * @Input: + * edge :: + * An edge to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from `point` to `edge`. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_edge_get_min_distance( SDF_Edge* edge, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + + + if ( !edge || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + /* edge-specific distance calculation */ + switch ( edge->edge_type ) + { + case SDF_EDGE_LINE: + get_min_distance_line( edge, point, out ); + break; + + case SDF_EDGE_CONIC: + get_min_distance_conic( edge, point, out ); + break; + + case SDF_EDGE_CUBIC: + get_min_distance_cubic( edge, point, out ); + break; + + default: + error = FT_THROW( Invalid_Argument ); + } + + Exit: + return error; + } + + + /* `sdf_generate' is not used at the moment */ +#if 0 + + #error "DO NOT USE THIS!" + #error "The function still outputs 16-bit data, which might cause memory" + #error "corruption. If required I will add this later." + + /************************************************************************** + * + * @Function: + * sdf_contour_get_min_distance + * + * @Description: + * Iterate over all edges that make up the contour, find the shortest + * distance from a point to this contour, and assigns result to `out`. + * + * @Input: + * contour :: + * A contour to which the shortest distance is to be computed. + * + * point :: + * Point from which the shortest distance is to be computed. + * + * @Output: + * out :: + * Signed distance from the `point' to the `contour'. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function does not return a signed distance for each edge which + * makes up the contour, it simply returns the shortest of all the + * edges. + * + */ + static FT_Error + sdf_contour_get_min_distance( SDF_Contour* contour, + FT_26D6_Vec point, + SDF_Signed_Distance* out ) + { + FT_Error error = FT_Err_Ok; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Edge* edge_list; + + + if ( !contour || !out ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + edge_list = contour->edges; + + /* iterate over all the edges manually */ + while ( edge_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + FT_16D16 diff; + + + FT_CALL( sdf_edge_get_min_distance( edge_list, + point, + ¤t_dist ) ); + + if ( current_dist.distance >= 0 ) + { + diff = current_dist.distance - min_dist.distance; + + + if ( FT_ABS( diff ) < CORNER_CHECK_EPSILON ) + min_dist = resolve_corner( min_dist, current_dist ); + else if ( diff < 0 ) + min_dist = current_dist; + } + else + FT_TRACE0(( "sdf_contour_get_min_distance: Overflow.\n" )); + + edge_list = edge_list->next; + } + + *out = min_dist; + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate + * + * @Description: + * This is the main function that is responsible for generating signed + * distance fields. The function does not align or compute the size of + * `bitmap`; therefore the calling application must set up `bitmap` + * properly and transform the `shape' appropriately in advance. + * + * Currently we check all pixels against all contours and all edges. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_UInt width = 0; + FT_UInt rows = 0; + FT_UInt x = 0; /* used to loop in x direction, i.e., width */ + FT_UInt y = 0; /* used to loop in y direction, i.e., rows */ + FT_UInt sp_sq = 0; /* `spread` [* `spread`] as a 16.16 fixed value */ + + FT_Short* buffer; + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + width = bitmap->width; + rows = bitmap->rows; + buffer = (FT_Short*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( spread * spread ); + else + sp_sq = FT_INT_16D16( spread ); + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])\n", + width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all rows */ + for ( y = 0; y < rows; y++ ) + { + /* loop over all pixels of a row */ + for ( x = 0; x < width; x++ ) + { + /* `grid_point` is the current pixel position; */ + /* our task is to find the shortest distance */ + /* from this point to the entire shape. */ + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance min_dist = max_sdf; + SDF_Contour* contour_list; + + FT_UInt index; + FT_Short value; + + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point' is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + contour_list = shape->contours; + + /* iterate over all contours manually */ + while ( contour_list ) + { + SDF_Signed_Distance current_dist = max_sdf; + + + FT_CALL( sdf_contour_get_min_distance( contour_list, + grid_point, + ¤t_dist ) ); + + if ( current_dist.distance < min_dist.distance ) + min_dist = current_dist; + + contour_list = contour_list->next; + } + + /* [OPTIMIZATION]: if (min_dist > sp_sq) then simply clamp */ + /* the value to spread to avoid square_root */ + + /* clamp the values to spread */ + if ( min_dist.distance > sp_sq ) + min_dist.distance = sp_sq; + + /* square_root the values and fit in a 6.10 fixed-point */ + if ( USE_SQUARED_DISTANCES ) + min_dist.distance = square_root( min_dist.distance ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + min_dist.sign = -min_dist.sign; + if ( internal_params.flip_sign ) + min_dist.sign = -min_dist.sign; + + min_dist.distance /= 64; /* convert from 16.16 to 22.10 */ + + value = min_dist.distance & 0x0000FFFF; /* truncate to 6.10 */ + value *= min_dist.sign; + + if ( internal_params.flip_y ) + index = y * width + x; + else + index = ( rows - y - 1 ) * width + x; + + buffer[index] = value; + } + } + + Exit: + return error; + } + +#endif /* 0 */ + + + /************************************************************************** + * + * @Function: + * sdf_generate_bounding_box + * + * @Description: + * This function does basically the same thing as `sdf_generate` above + * but more efficiently. + * + * Instead of checking all pixels against all edges, we loop over all + * edges and only check pixels around the control box of the edge; the + * control box is increased by the spread in all directions. Anything + * outside of the control box that exceeds `spread` doesn't need to be + * computed. + * + * Lastly, to determine the sign of unchecked pixels, we do a single + * pass of all rows starting with a '+' sign and flipping when we come + * across a '-' sign and continue. This also eliminates the possibility + * of overflow because we only check the proximity of the curve. + * Therefore we can use squared distanced safely. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_bounding_box( const SDF_Params internal_params, + const SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Int width, rows, i, j; + FT_Int sp_sq; /* max value to check */ + + SDF_Contour* contours; /* list of all contours */ + FT_SDFFormat* buffer; /* the bitmap buffer */ + + /* This buffer has the same size in indices as the */ + /* bitmap buffer. When we check a pixel position for */ + /* a shortest distance we keep it in this buffer. */ + /* This way we can find out which pixel is set, */ + /* and also determine the signs properly. */ + SDF_Signed_Distance* dists = NULL; + + const FT_16D16 fixed_spread = (FT_16D16)FT_INT_16D16( spread ); + + + if ( !shape || !bitmap ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( spread < MIN_SPREAD || spread > MAX_SPREAD ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = shape->memory; + if ( !memory ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + if ( FT_ALLOC( dists, + bitmap->width * bitmap->rows * sizeof ( *dists ) ) ) + goto Exit; + + contours = shape->contours; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + buffer = (FT_SDFFormat*)bitmap->buffer; + + if ( USE_SQUARED_DISTANCES ) + sp_sq = FT_INT_16D16( (FT_Int)( spread * spread ) ); + else + sp_sq = fixed_spread; + + if ( width == 0 || rows == 0 ) + { + FT_TRACE0(( "sdf_generate:" + " Cannot render glyph with width/height == 0\n" )); + FT_TRACE0(( " " + " (width, height provided [%d, %d])", width, rows )); + + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* loop over all contours */ + while ( contours ) + { + SDF_Edge* edges = contours->edges; + + + /* loop over all edges */ + while ( edges ) + { + FT_CBox cbox; + FT_Int x, y; + + + /* get the control box and increase it by `spread' */ + cbox = get_control_box( *edges ); + + cbox.xMin = ( cbox.xMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.xMax = ( cbox.xMax + 63 ) / 64 + ( FT_Pos )spread; + cbox.yMin = ( cbox.yMin - 63 ) / 64 - ( FT_Pos )spread; + cbox.yMax = ( cbox.yMax + 63 ) / 64 + ( FT_Pos )spread; + + /* now loop over the pixels in the control box. */ + for ( y = cbox.yMin; y < cbox.yMax; y++ ) + { + for ( x = cbox.xMin; x < cbox.xMax; x++ ) + { + FT_26D6_Vec grid_point = zero_vector; + SDF_Signed_Distance dist = max_sdf; + FT_UInt index = 0; + FT_16D16 diff = 0; + + + if ( x < 0 || x >= width ) + continue; + if ( y < 0 || y >= rows ) + continue; + + grid_point.x = FT_INT_26D6( x ); + grid_point.y = FT_INT_26D6( y ); + + /* This `grid_point` is at the corner, but we */ + /* use the center of the pixel. */ + grid_point.x += FT_INT_26D6( 1 ) / 2; + grid_point.y += FT_INT_26D6( 1 ) / 2; + + FT_CALL( sdf_edge_get_min_distance( edges, + grid_point, + &dist ) ); + + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + dist.sign = -dist.sign; + + /* ignore if the distance is greater than spread; */ + /* otherwise it creates artifacts due to the wrong sign */ + if ( dist.distance > sp_sq ) + continue; + + /* take the square root of the distance if required */ + if ( USE_SQUARED_DISTANCES ) + dist.distance = square_root( dist.distance ); + + if ( internal_params.flip_y ) + index = (FT_UInt)( y * width + x ); + else + index = (FT_UInt)( ( rows - y - 1 ) * width + x ); + + /* check whether the pixel is set or not */ + if ( dists[index].sign == 0 ) + dists[index] = dist; + else + { + diff = FT_ABS( dists[index].distance - dist.distance ); + + if ( diff <= CORNER_CHECK_EPSILON ) + dists[index] = resolve_corner( dists[index], dist ); + else if ( dists[index].distance > dist.distance ) + dists[index] = dist; + } + } + } + + edges = edges->next; + } + + contours = contours->next; + } + + /* final pass */ + for ( j = 0; j < rows; j++ ) + { + /* We assume the starting pixel of each row is outside. */ + FT_Char current_sign = -1; + FT_UInt index; + + + if ( internal_params.overload_sign != 0 ) + current_sign = internal_params.overload_sign < 0 ? -1 : 1; + + for ( i = 0; i < width; i++ ) + { + index = (FT_UInt)( j * width + i ); + + /* if the pixel is not set */ + /* its shortest distance is more than `spread` */ + if ( dists[index].sign == 0 ) + dists[index].distance = fixed_spread; + else + current_sign = dists[index].sign; + + /* clamp the values */ + if ( dists[index].distance > fixed_spread ) + dists[index].distance = fixed_spread; + + /* flip sign if required */ + dists[index].distance *= internal_params.flip_sign ? -current_sign + : current_sign; + + /* concatenate to appropriate format */ + buffer[index] = map_fixed_to_sdf( dists[index].distance, + fixed_spread ); + } + } + + Exit: + FT_FREE( dists ); + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_subdivision + * + * @Description: + * Subdivide the shape into a number of straight lines, then use the + * above `sdf_generate_bounding_box` function to generate the SDF. + * + * Note: After calling this function `shape` no longer has the original + * edges, it only contains lines. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. + * See @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + */ + static FT_Error + sdf_generate_subdivision( const SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + /* + * Thanks to Alexei for providing the idea of this optimization. + * + * We take advantage of two facts. + * + * (1) Computing the shortest distance from a point to a line segment is + * very fast. + * (2) We don't have to compute the shortest distance for the entire + * two-dimensional grid. + * + * Both ideas lead to the following optimization. + * + * (1) Split the outlines into a number of line segments. + * + * (2) For each line segment, only process its neighborhood. + * + * (3) Compute the closest distance to the line only for neighborhood + * grid points. + * + * This greatly reduces the number of grid points to check. + */ + + FT_Error error = FT_Err_Ok; + + + FT_CALL( split_sdf_shape( shape ) ); + FT_CALL( sdf_generate_bounding_box( internal_params, + shape, spread, bitmap ) ); + + Exit: + return error; + } + + + /************************************************************************** + * + * @Function: + * sdf_generate_with_overlaps + * + * @Description: + * This function can be used to generate SDF for glyphs with overlapping + * contours. The function generates SDF for contours separately on + * separate bitmaps (to generate SDF it uses + * `sdf_generate_subdivision`). At the end it simply combines all the + * SDF into the output bitmap; this fixes all the signs and removes + * overlaps. + * + * @Input: + * internal_params :: + * Internal parameters and properties required by the rasterizer. See + * @SDF_Params for more. + * + * shape :: + * A complete shape which is used to generate SDF. + * + * spread :: + * Maximum distances to be allowed in the output bitmap. + * + * @Output: + * bitmap :: + * The output bitmap which will contain the SDF information. + * + * @Return: + * FreeType error, 0 means success. + * + * @Note: + * The function cannot generate a proper SDF for glyphs with + * self-intersecting contours because we cannot separate them into two + * separate bitmaps. In case of self-intersecting contours it is + * necessary to remove the overlaps before generating the SDF. + * + */ + static FT_Error + sdf_generate_with_overlaps( SDF_Params internal_params, + SDF_Shape* shape, + FT_UInt spread, + const FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + + FT_Int num_contours; /* total number of contours */ + FT_Int i, j; /* iterators */ + FT_Int width, rows; /* width and rows of the bitmap */ + FT_Bitmap* bitmaps; /* separate bitmaps for contours */ + + SDF_Contour* contour; /* temporary variable to iterate */ + SDF_Contour* temp_contour; /* temporary contour */ + SDF_Contour* head; /* head of the contour list */ + SDF_Shape temp_shape; /* temporary shape */ + + FT_Memory memory; /* to allocate memory */ + FT_SDFFormat* t; /* target bitmap buffer */ + FT_Bool flip_sign; /* flip sign? */ + + /* orientation of all the separate contours */ + SDF_Contour_Orientation* orientations; + + + bitmaps = NULL; + orientations = NULL; + head = NULL; + + if ( !shape || !bitmap || !shape->memory ) + return FT_THROW( Invalid_Argument ); + + /* Disable `flip_sign` to avoid extra complication */ + /* during the combination phase. */ + flip_sign = internal_params.flip_sign; + internal_params.flip_sign = 0; + + contour = shape->contours; + memory = shape->memory; + temp_shape.memory = memory; + width = (FT_Int)bitmap->width; + rows = (FT_Int)bitmap->rows; + num_contours = 0; + + /* find the number of contours in the shape */ + while ( contour ) + { + num_contours++; + contour = contour->next; + } + + /* allocate the bitmaps to generate SDF for separate contours */ + if ( FT_ALLOC( bitmaps, + (FT_UInt)num_contours * sizeof ( *bitmaps ) ) ) + goto Exit; + + /* allocate array to hold orientation for all contours */ + if ( FT_ALLOC( orientations, + (FT_UInt)num_contours * sizeof ( *orientations ) ) ) + goto Exit; + + contour = shape->contours; + + /* Iterate over all contours and generate SDF separately. */ + for ( i = 0; i < num_contours; i++ ) + { + /* initialize the corresponding bitmap */ + FT_Bitmap_Init( &bitmaps[i] ); + + bitmaps[i].width = bitmap->width; + bitmaps[i].rows = bitmap->rows; + bitmaps[i].pitch = bitmap->pitch; + bitmaps[i].num_grays = bitmap->num_grays; + bitmaps[i].pixel_mode = bitmap->pixel_mode; + + /* allocate memory for the buffer */ + if ( FT_ALLOC( bitmaps[i].buffer, + bitmap->rows * (FT_UInt)bitmap->pitch ) ) + goto Exit; + + /* determine the orientation */ + orientations[i] = get_contour_orientation( contour ); + + /* The `overload_sign` property is specific to */ + /* `sdf_generate_bounding_box`. This basically */ + /* overloads the default sign of the outside */ + /* pixels, which is necessary for */ + /* counter-clockwise contours. */ + if ( orientations[i] == SDF_ORIENTATION_CCW && + internal_params.orientation == FT_ORIENTATION_FILL_RIGHT ) + internal_params.overload_sign = 1; + else if ( orientations[i] == SDF_ORIENTATION_CW && + internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + internal_params.overload_sign = 1; + else + internal_params.overload_sign = 0; + + /* Make `contour->next` NULL so that there is */ + /* one contour in the list. Also hold the next */ + /* contour in a temporary variable so as to */ + /* restore the original value. */ + temp_contour = contour->next; + contour->next = NULL; + + /* Use `temp_shape` to hold the new contour. */ + /* Now, `temp_shape` has only one contour. */ + temp_shape.contours = contour; + + /* finally generate the SDF */ + FT_CALL( sdf_generate_subdivision( internal_params, + &temp_shape, + spread, + &bitmaps[i] ) ); + + /* Restore the original `next` variable. */ + contour->next = temp_contour; + + /* Since `split_sdf_shape` deallocated the original */ + /* contours list we need to assign the new value to */ + /* the shape's contour. */ + temp_shape.contours->next = head; + head = temp_shape.contours; + + /* Simply flip the orientation in case of post-script fonts */ + /* so as to avoid modificatons in the combining phase. */ + if ( internal_params.orientation == FT_ORIENTATION_FILL_LEFT ) + { + if ( orientations[i] == SDF_ORIENTATION_CW ) + orientations[i] = SDF_ORIENTATION_CCW; + else if ( orientations[i] == SDF_ORIENTATION_CCW ) + orientations[i] = SDF_ORIENTATION_CW; + } + + contour = contour->next; + } + + /* assign the new contour list to `shape->contours` */ + shape->contours = head; + + /* cast the output bitmap buffer */ + t = (FT_SDFFormat*)bitmap->buffer; + + /* Iterate over all pixels and combine all separate */ + /* contours. These are the rules for combining: */ + /* */ + /* (1) For all clockwise contours, compute the largest */ + /* value. Name this as `val_c`. */ + /* (2) For all counter-clockwise contours, compute the */ + /* smallest value. Name this as `val_ac`. */ + /* (3) Now, finally use the smaller value of `val_c' */ + /* and `val_ac'. */ + for ( j = 0; j < rows; j++ ) + { + for ( i = 0; i < width; i++ ) + { + FT_Int id = j * width + i; /* index of current pixel */ + FT_Int c; /* contour iterator */ + + FT_SDFFormat val_c = 0; /* max clockwise value */ + FT_SDFFormat val_ac = UCHAR_MAX; /* min counter-clockwise val */ + + + /* iterate through all the contours */ + for ( c = 0; c < num_contours; c++ ) + { + /* current contour value */ + FT_SDFFormat temp = ( (FT_SDFFormat*)bitmaps[c].buffer )[id]; + + + if ( orientations[c] == SDF_ORIENTATION_CW ) + val_c = FT_MAX( val_c, temp ); /* clockwise */ + else + val_ac = FT_MIN( val_ac, temp ); /* counter-clockwise */ + } + + /* Finally find the smaller of the two and assign to output. */ + /* Also apply `flip_sign` if set. */ + t[id] = FT_MIN( val_c, val_ac ); + + if ( flip_sign ) + t[id] = invert_sign( t[id] ); + } + } + + Exit: + /* deallocate orientations array */ + if ( orientations ) + FT_FREE( orientations ); + + /* deallocate temporary bitmaps */ + if ( bitmaps ) + { + if ( num_contours == 0 ) + error = FT_THROW( Raster_Corrupted ); + else + { + for ( i = 0; i < num_contours; i++ ) + FT_FREE( bitmaps[i].buffer ); + + FT_FREE( bitmaps ); + } + } + + /* restore the `flip_sign` property */ + internal_params.flip_sign = flip_sign; + + return error; + } + + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + sdf_raster_new( void* memory_, /* FT_Memory */ + FT_Raster* araster_ ) /* SDF_PRaster* */ + { + FT_Memory memory = (FT_Memory)memory_; + SDF_PRaster* araster = (SDF_PRaster*)araster_; + + + FT_Error error; + SDF_PRaster raster = NULL; + + + if ( !FT_NEW( raster ) ) + raster->memory = memory; + + *araster = raster; + + return error; + } + + + static void + sdf_raster_reset( FT_Raster raster, + unsigned char* pool_base, + unsigned long pool_size ) + { + FT_UNUSED( raster ); + FT_UNUSED( pool_base ); + FT_UNUSED( pool_size ); + } + + + static FT_Error + sdf_raster_set_mode( FT_Raster raster, + unsigned long mode, + void* args ) + { + FT_UNUSED( raster ); + FT_UNUSED( mode ); + FT_UNUSED( args ); + + return FT_Err_Ok; + } + + + static FT_Error + sdf_raster_render( FT_Raster raster, + const FT_Raster_Params* params ) + { + FT_Error error = FT_Err_Ok; + SDF_TRaster* sdf_raster = (SDF_TRaster*)raster; + FT_Outline* outline = NULL; + const SDF_Raster_Params* sdf_params = (const SDF_Raster_Params*)params; + + FT_Memory memory = NULL; + SDF_Shape* shape = NULL; + SDF_Params internal_params; + + + /* check for valid arguments */ + if ( !sdf_raster || !sdf_params ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + outline = (FT_Outline*)sdf_params->root.source; + + /* check whether outline is valid */ + if ( !outline ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* if the outline is empty, return */ + if ( outline->n_points == 0 || outline->n_contours == 0 ) + goto Exit; + + /* check whether the outline has valid fields */ + if ( !outline->contours || !outline->points ) + { + error = FT_THROW( Invalid_Outline ); + goto Exit; + } + + /* check whether spread is set properly */ + if ( sdf_params->spread > MAX_SPREAD || + sdf_params->spread < MIN_SPREAD ) + { + FT_TRACE0(( "sdf_raster_render:" + " The `spread' field of `SDF_Raster_Params' is invalid,\n" )); + FT_TRACE0(( " " + " the value of this field must be within [%d, %d].\n", + MIN_SPREAD, MAX_SPREAD )); + FT_TRACE0(( " " + " Also, you must pass `SDF_Raster_Params' instead of\n" )); + FT_TRACE0(( " " + " the default `FT_Raster_Params' while calling\n" )); + FT_TRACE0(( " " + " this function and set the fields properly.\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + memory = sdf_raster->memory; + if ( !memory ) + { + FT_TRACE0(( "sdf_raster_render:" + " Raster not setup properly,\n" )); + FT_TRACE0(( " " + " unable to find memory handle.\n" )); + + error = FT_THROW( Invalid_Handle ); + goto Exit; + } + + /* set up the parameters */ + internal_params.orientation = FT_Outline_Get_Orientation( outline ); + internal_params.flip_sign = sdf_params->flip_sign; + internal_params.flip_y = sdf_params->flip_y; + internal_params.overload_sign = 0; + + FT_CALL( sdf_shape_new( memory, &shape ) ); + + FT_CALL( sdf_outline_decompose( outline, shape ) ); + + if ( sdf_params->overlaps ) + FT_CALL( sdf_generate_with_overlaps( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + else + FT_CALL( sdf_generate_subdivision( internal_params, + shape, sdf_params->spread, + sdf_params->root.target ) ); + + if ( shape ) + sdf_shape_done( &shape ); + + Exit: + return error; + } + + + static void + sdf_raster_done( FT_Raster raster ) + { + FT_Memory memory = (FT_Memory)((SDF_TRaster*)raster)->memory; + + + FT_FREE( raster ); + } + + + FT_DEFINE_RASTER_FUNCS( + ft_sdf_raster, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Raster_New_Func) sdf_raster_new, /* raster_new */ + (FT_Raster_Reset_Func) sdf_raster_reset, /* raster_reset */ + (FT_Raster_Set_Mode_Func)sdf_raster_set_mode, /* raster_set_mode */ + (FT_Raster_Render_Func) sdf_raster_render, /* raster_render */ + (FT_Raster_Done_Func) sdf_raster_done /* raster_done */ + ) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdf.h b/src/thirdparty/freetype2/src/sdf/ftsdf.h new file mode 100644 index 000000000..fb1758036 --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdf.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * + * ftsdf.h + * + * Signed Distance Field support (specification). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTSDF_H_ +#define FTSDF_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + +/* common properties and function */ +#include "ftsdfcommon.h" + +FT_BEGIN_HEADER + + /************************************************************************** + * + * @struct: + * SDF_Raster_Params + * + * @description: + * This struct must be passed to the raster render function + * @FT_Raster_RenderFunc instead of @FT_Raster_Params because the + * rasterizer requires some additional information to render properly. + * + * @fields: + * root :: + * The native raster parameters structure. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true makes the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties are valid for both the 'sdf' and 'bsdf' renderers; the + * exception is `overlaps`, which gets ignored by the 'bsdf' renderer. + * + */ + typedef struct SDF_Raster_Params_ + { + FT_Raster_Params root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Raster_Params; + + + /* rasterizer to convert outline to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_sdf_raster; + + /* rasterizer to convert bitmap to SDF */ + FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_bitmap_sdf_raster; + +FT_END_HEADER + +#endif /* FTSDF_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdfcommon.c b/src/thirdparty/freetype2/src/sdf/ftsdfcommon.c new file mode 100644 index 000000000..fa99944f8 --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdfcommon.c @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * ftsdfcommon.c + * + * Auxiliary data for Signed Distance Field support (body). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 "ftsdf.h" +#include "ftsdfcommon.h" + + + /************************************************************************** + * + * format and sign manipulating functions + * + */ + + /* + * Convert 16.16 fixed-point values to the desired output format. + * In this case we reduce 16.16 fixed-point values to normalized + * 8-bit values. + * + * The `max_value` in the parameter is the maximum value in the + * distance field map and is equal to the spread. We normalize + * the distances using this value instead of computing the maximum + * value for the entire bitmap. + * + * You can use this function to map the 16.16 signed values to any + * format required. Do note that the output buffer is 8-bit, so only + * use an 8-bit format for `FT_SDFFormat`, or increase the buffer size in + * `ftsdfrend.c`. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ) + { + FT_SDFFormat out; + FT_16D16 udist; + + + /* normalize the distance values */ + dist = FT_DivFix( dist, max_value ); + + udist = dist < 0 ? -dist : dist; + + /* Reduce the distance values to 8 bits. */ + /* */ + /* Since +1/-1 in 16.16 takes the 16th bit, we right-shift */ + /* the number by 9 to make it fit into the 7-bit range. */ + /* */ + /* One bit is reserved for the sign. */ + udist >>= 9; + + /* Since `char` can only store a maximum positive value */ + /* of 127 we need to make sure it does not wrap around and */ + /* give a negative value. */ + if ( dist > 0 && udist > 127 ) + udist = 127; + if ( dist < 0 && udist > 128 ) + udist = 128; + + /* Output the data; negative values are from [0, 127] and positive */ + /* from [128, 255]. One important thing is that negative values */ + /* are inverted here, that means [0, 128] maps to [-128, 0] linearly. */ + /* More on that in `freetype.h` near the documentation of */ + /* `FT_RENDER_MODE_SDF`. */ + out = dist < 0 ? 128 - (FT_SDFFormat)udist + : (FT_SDFFormat)udist + 128; + + return out; + } + + + /* + * Invert the signed distance packed into the corresponding format. + * So if the values are negative they will become positive in the + * chosen format. + * + * [Note]: This function should only be used after converting the + * 16.16 signed distance values to `FT_SDFFormat`. If that + * conversion has not been done, then simply invert the sign + * and use the above function to pack the values. + */ + FT_LOCAL_DEF( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ) + { + return 255 - dist; + } + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdfcommon.h b/src/thirdparty/freetype2/src/sdf/ftsdfcommon.h new file mode 100644 index 000000000..b87e97ed3 --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdfcommon.h @@ -0,0 +1,140 @@ +/**************************************************************************** + * + * ftsdfcommon.h + * + * Auxiliary data for Signed Distance Field support (specification). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 common functions and properties + * for both the 'sdf' and 'bsdf' renderers. + * + */ + +#ifndef FTSDFCOMMON_H_ +#define FTSDFCOMMON_H_ + +#include +#include FT_CONFIG_CONFIG_H +#include + + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * default values (cannot be set individually for each renderer) + * + */ + + /* default spread value */ +#define DEFAULT_SPREAD 8 + /* minimum spread supported by the renderer */ +#define MIN_SPREAD 2 + /* maximum spread supported by the renderer */ +#define MAX_SPREAD 32 + /* pixel size in 26.6 */ +#define ONE_PIXEL ( 1 << 6 ) + + + /************************************************************************** + * + * common definitions (cannot be set individually for each renderer) + * + */ + + /* If this macro is set to 1 the rasterizer uses squared distances for */ + /* computation. It can greatly improve the performance but there is a */ + /* chance of overflow and artifacts. You can safely use it up to a */ + /* pixel size of 128. */ +#ifndef USE_SQUARED_DISTANCES +#define USE_SQUARED_DISTANCES 0 +#endif + + + /************************************************************************** + * + * common macros + * + */ + + /* convert int to 26.6 fixed-point */ +#define FT_INT_26D6( x ) ( x * 64 ) + /* convert int to 16.16 fixed-point */ +#define FT_INT_16D16( x ) ( x * 65536 ) + /* convert 26.6 to 16.16 fixed-point */ +#define FT_26D6_16D16( x ) ( x * 1024 ) + + + /* Convenience macro to call a function; it */ + /* jumps to label `Exit` if an error occurs. */ +#define FT_CALL( x ) do \ + { \ + error = ( x ); \ + if ( error != FT_Err_Ok ) \ + goto Exit; \ + } while ( 0 ) + + + /* + * The macro `VECTOR_LENGTH_16D16` computes either squared distances or + * actual distances, depending on the value of `USE_SQUARED_DISTANCES`. + * + * By using squared distances the performance can be greatly improved but + * there is a risk of overflow. + */ +#if USE_SQUARED_DISTANCES +#define VECTOR_LENGTH_16D16( v ) ( FT_MulFix( v.x, v.x ) + \ + FT_MulFix( v.y, v.y ) ) +#else +#define VECTOR_LENGTH_16D16( v ) FT_Vector_Length( &v ) +#endif + + + /************************************************************************** + * + * common typedefs + * + */ + + typedef FT_Vector FT_26D6_Vec; /* with 26.6 fixed-point components */ + typedef FT_Vector FT_16D16_Vec; /* with 16.16 fixed-point components */ + + typedef FT_Int32 FT_16D16; /* 16.16 fixed-point representation */ + typedef FT_Int32 FT_26D6; /* 26.6 fixed-point representation */ + typedef FT_Byte FT_SDFFormat; /* format to represent SDF data */ + + typedef FT_BBox FT_CBox; /* control box of a curve */ + + +#define square_root( x ) (FT_16D16)FT_SqrtFixed( (FT_UInt32)( x ) ) + + FT_LOCAL( FT_SDFFormat ) + map_fixed_to_sdf( FT_16D16 dist, + FT_16D16 max_value ); + + FT_LOCAL( FT_SDFFormat ) + invert_sign( FT_SDFFormat dist ); + + +FT_END_HEADER + +#endif /* FTSDFCOMMON_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdferrs.h b/src/thirdparty/freetype2/src/sdf/ftsdferrs.h new file mode 100644 index 000000000..e28e2e1ca --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdferrs.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * + * ftsdferrs.h + * + * Signed Distance Field error codes (specification only). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTSDFERRS_H_ +#define FTSDFERRS_H_ + +#include + +#undef FTERRORS_H_ + +#undef FT_ERR_PREFIX +#define FT_ERR_PREFIX Sdf_Err_ +#define FT_ERR_BASE FT_Mod_Err_Sdf + +#include + +#endif /* FTSDFERRS_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdfrend.c b/src/thirdparty/freetype2/src/sdf/ftsdfrend.c new file mode 100644 index 000000000..e24b3b614 --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdfrend.c @@ -0,0 +1,603 @@ +/**************************************************************************** + * + * ftsdfrend.c + * + * Signed Distance Field renderer interface (body). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 +#include +#include +#include +#include "ftsdfrend.h" +#include "ftsdf.h" + +#include "ftsdferrs.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 sdf + + + /************************************************************************** + * + * macros and default property values + * + */ +#define SDF_RENDERER( rend ) ( (SDF_Renderer)rend ) + + + /************************************************************************** + * + * for setting properties + * + */ + + /* property setter function */ + static FT_Error + sdf_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + FT_UNUSED( value_is_string ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + if ( val > MAX_SPREAD || val < MIN_SPREAD ) + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " the `spread' property can have a value\n" )); + FT_TRACE0(( " " + " within range [%d, %d] (value provided: %d)\n", + MIN_SPREAD, MAX_SPREAD, val )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + render->spread = (FT_UInt)val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `spread' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_sign = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_sign' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int val = *(const FT_Int*)value; + + + render->flip_y = val ? 1 : 0; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `flip_y' to %d\n", val )); + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Bool val = *(const FT_Bool*)value; + + + render->overlaps = val; + FT_TRACE7(( "[sdf] sdf_property_set:" + " updated property `overlaps' to %d\n", val )); + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_set:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + Exit: + return error; + } + + + /* property getter function */ + static FT_Error + sdf_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SDF_Renderer render = SDF_RENDERER( FT_RENDERER( module ) ); + + + if ( ft_strcmp( property_name, "spread" ) == 0 ) + { + FT_UInt* val = (FT_UInt*)value; + + + *val = render->spread; + } + + else if ( ft_strcmp( property_name, "flip_sign" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_sign; + } + + else if ( ft_strcmp( property_name, "flip_y" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->flip_y; + } + + else if ( ft_strcmp( property_name, "overlaps" ) == 0 ) + { + FT_Int* val = (FT_Int*)value; + + + *val = render->overlaps; + } + + else + { + FT_TRACE0(( "[sdf] sdf_property_get:" + " missing property `%s'\n", property_name )); + error = FT_THROW( Missing_Property ); + } + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + sdf_service_properties, + + (FT_Properties_SetFunc)sdf_property_set, /* set_property */ + (FT_Properties_GetFunc)sdf_property_get ) /* get_property */ + + + FT_DEFINE_SERVICEDESCREC1( + sdf_services, + + FT_SERVICE_ID_PROPERTIES, &sdf_service_properties ) + + + static FT_Module_Interface + ft_sdf_requester( FT_Module module, + const char* module_interface ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( sdf_services, module_interface ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** OUTLINE TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************** + * + * interface functions + * + */ + + static FT_Error + ft_sdf_init( FT_Module module ) /* SDF_Renderer */ + { + SDF_Renderer sdf_render = SDF_RENDERER( module ); + + + sdf_render->spread = DEFAULT_SPREAD; + sdf_render->flip_sign = 0; + sdf_render->flip_y = 0; + sdf_render->overlaps = 0; + + return FT_Err_Ok; + } + + + static void + ft_sdf_done( FT_Module module ) + { + FT_UNUSED( module ); + } + + + /* generate signed distance field from a glyph's slot image */ + static FT_Error + ft_sdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Outline* outline = &slot->outline; + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = NULL; + FT_Renderer render = NULL; + + FT_Pos x_shift = 0; + FT_Pos y_shift = 0; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + /* deallocate the previously allocated bitmap */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + /* preset the bitmap using the glyph's outline; */ + /* the sdf bitmap is similar to an anti-aliased bitmap */ + /* with a slightly bigger size and different pixel mode */ + if ( ft_glyphslot_preset_bitmap( slot, FT_RENDER_MODE_NORMAL, origin ) ) + { + error = FT_THROW( Raster_Overflow ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* the padding will simply be equal to the `spread' */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply the padding; will be in all the directions */ + bitmap->rows += y_pad * 2; + bitmap->width += x_pad * 2; + + /* ignore the pitch, pixel mode and set custom */ + bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; + bitmap->pitch = (int)( bitmap->width ); + bitmap->num_grays = 255; + + /* allocate new buffer */ + if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) + goto Exit; + + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + x_shift = 64 * -slot->bitmap_left; + y_shift = 64 * -slot->bitmap_top; + y_shift += 64 * (FT_Int)bitmap->rows; + + if ( origin ) + { + x_shift += origin->x; + y_shift += origin->y; + } + + /* translate outline to render it into the bitmap */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, x_shift, y_shift ); + + /* set up parameters */ + params.root.target = bitmap; + params.root.source = outline; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + params.overlaps = sdf_module->overlaps; + + /* render the outline */ + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + /* transform the outline back to the original state */ + if ( x_shift || y_shift ) + FT_Outline_Translate( outline, -x_shift, -y_shift ); + + Exit: + if ( !error ) + { + /* the glyph is successfully rendered to a bitmap */ + slot->format = FT_GLYPH_FORMAT_BITMAP; + } + else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + + return error; + } + + + /* transform the glyph using matrix and/or delta */ + static FT_Error + ft_sdf_transform( FT_Renderer render, + FT_GlyphSlot slot, + const FT_Matrix* matrix, + const FT_Vector* delta ) + { + FT_Error error = FT_Err_Ok; + + + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( 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 control box of a glyph's outline */ + static void + ft_sdf_get_cbox( FT_Renderer render, + FT_GlyphSlot slot, + FT_BBox* cbox ) + { + FT_ZERO( cbox ); + + if ( slot->format == render->glyph_format ) + FT_Outline_Get_CBox( &slot->outline, cbox ); + } + + + /* set render specific modes or attributes */ + static FT_Error + ft_sdf_set_mode( FT_Renderer render, + FT_ULong mode_tag, + FT_Pointer data ) + { + /* pass it to the rasterizer */ + return render->clazz->raster_class->raster_set_mode( render->raster, + mode_tag, + data ); + } + + + FT_DEFINE_RENDERER( + ft_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "sdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_OUTLINE, + + (FT_Renderer_RenderFunc) ft_sdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_sdf_raster /* raster_class */ + ) + + + /*************************************************************************/ + /*************************************************************************/ + /** **/ + /** BITMAP TO SDF CONVERTER **/ + /** **/ + /*************************************************************************/ + /*************************************************************************/ + + /* generate signed distance field from glyph's bitmap */ + static FT_Error + ft_bsdf_render( FT_Renderer module, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = NULL; + + FT_Bitmap* bitmap = &slot->bitmap; + FT_Renderer render = NULL; + FT_Bitmap target; + + FT_Pos x_pad = 0; + FT_Pos y_pad = 0; + + SDF_Raster_Params params; + SDF_Renderer sdf_module = SDF_RENDERER( module ); + + + /* initialize the bitmap in case any error occurs */ + FT_Bitmap_Init( &target ); + + render = &sdf_module->root; + memory = render->root.memory; + + /* check whether slot format is correct before rendering */ + if ( slot->format != render->glyph_format ) + { + error = FT_THROW( Invalid_Glyph_Format ); + goto Exit; + } + + /* check whether render mode is correct */ + if ( mode != FT_RENDER_MODE_SDF ) + { + error = FT_THROW( Cannot_Render_Glyph ); + goto Exit; + } + + if ( origin ) + { + FT_ERROR(( "ft_bsdf_render: can't translate the bitmap\n" )); + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + } + + /* nothing to render */ + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + + /* Do not generate SDF if the bitmap is not owned by the */ + /* glyph: it might be that the source buffer is already freed. */ + if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ) + { + FT_ERROR(( "ft_bsdf_render: can't generate SDF from" + " unowned source bitmap\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + FT_Bitmap_New( &target ); + + /* padding will simply be equal to `spread` */ + x_pad = sdf_module->spread; + y_pad = sdf_module->spread; + + /* apply padding, which extends to all directions */ + target.rows = bitmap->rows + y_pad * 2; + target.width = bitmap->width + x_pad * 2; + + /* set up the target bitmap */ + target.pixel_mode = FT_PIXEL_MODE_GRAY; + target.pitch = (int)( target.width ); + target.num_grays = 255; + + if ( FT_ALLOC_MULT( target.buffer, target.rows, target.pitch ) ) + goto Exit; + + /* set up parameters */ + params.root.target = ⌖ + params.root.source = bitmap; + params.root.flags = FT_RASTER_FLAG_SDF; + params.spread = sdf_module->spread; + params.flip_sign = sdf_module->flip_sign; + params.flip_y = sdf_module->flip_y; + + error = render->raster_render( render->raster, + (const FT_Raster_Params*)¶ms ); + + Exit: + if ( !error ) + { + /* the glyph is successfully converted to a SDF */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + FT_FREE( bitmap->buffer ); + + slot->bitmap = target; + slot->bitmap_top += y_pad; + slot->bitmap_left -= x_pad; + + if ( target.buffer ) + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + } + else if ( target.buffer ) + FT_FREE( target.buffer ); + + return error; + } + + + FT_DEFINE_RENDERER( + ft_bitmap_sdf_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SDF_Renderer_Module ), + + "bsdf", + 0x10000L, + 0x20000L, + + NULL, + + (FT_Module_Constructor)ft_sdf_init, + (FT_Module_Destructor) ft_sdf_done, + (FT_Module_Requester) ft_sdf_requester, + + FT_GLYPH_FORMAT_BITMAP, + + (FT_Renderer_RenderFunc) ft_bsdf_render, /* render_glyph */ + (FT_Renderer_TransformFunc)ft_sdf_transform, /* transform_glyph */ + (FT_Renderer_GetCBoxFunc) ft_sdf_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_sdf_set_mode, /* set_mode */ + + (FT_Raster_Funcs*)&ft_bitmap_sdf_raster /* raster_class */ + ) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sdf/ftsdfrend.h b/src/thirdparty/freetype2/src/sdf/ftsdfrend.h new file mode 100644 index 000000000..ab98a7963 --- /dev/null +++ b/src/thirdparty/freetype2/src/sdf/ftsdfrend.h @@ -0,0 +1,118 @@ +/**************************************************************************** + * + * ftsdfrend.h + * + * Signed Distance Field renderer interface (specification). + * + * Copyright (C) 2020-2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * Written by Anuj Verma. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTSDFREND_H_ +#define FTSDFREND_H_ + +#include +#include +#include + +FT_BEGIN_HEADER + + + /************************************************************************** + * + * @struct: + * SDF_Renderer_Module + * + * @description: + * This struct extends the native renderer struct `FT_RendererRec`. It + * is basically used to store various parameters required by the + * renderer and some additional parameters that can be used to tweak the + * output of the renderer. + * + * @fields: + * root :: + * The native rendere struct. + * + * spread :: + * This is an essential parameter/property required by the renderer. + * `spread` defines the maximum unsigned value that is present in the + * final SDF output. For the default value check file + * `ftsdfcommon.h`. + * + * flip_sign :: + * By default positive values indicate positions inside of contours, + * i.e., filled by a contour. If this property is true then that + * output will be the opposite of the default, i.e., negative values + * indicate positions inside of contours. + * + * flip_y :: + * Setting this parameter to true makes the output image flipped + * along the y-axis. + * + * overlaps :: + * Set this to true to generate SDF for glyphs having overlapping + * contours. The overlapping support is limited to glyphs that do not + * have self-intersecting contours. Also, removing overlaps require a + * considerable amount of extra memory; additionally, it will not work + * if generating SDF from bitmap. + * + * @note: + * All properties except `overlaps` are valid for both the 'sdf' and + * 'bsdf' renderers. + * + */ + typedef struct SDF_Renderer_Module_ + { + FT_RendererRec root; + FT_UInt spread; + FT_Bool flip_sign; + FT_Bool flip_y; + FT_Bool overlaps; + + } SDF_Renderer_Module, *SDF_Renderer; + + + /************************************************************************** + * + * @renderer: + * ft_sdf_renderer_class + * + * @description: + * Renderer to convert @FT_Outline to signed distance fields. + * + */ + FT_DECLARE_RENDERER( ft_sdf_renderer_class ) + + + /************************************************************************** + * + * @renderer: + * ft_bitmap_sdf_renderer_class + * + * @description: + * This is not exactly a renderer; it is just a converter that + * transforms bitmaps to signed distance fields. + * + * @note: + * This is not a separate module, it is part of the 'sdf' module. + * + */ + FT_DECLARE_RENDERER( ft_bitmap_sdf_renderer_class ) + + +FT_END_HEADER + +#endif /* FTSDFREND_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/pngshim.c b/src/thirdparty/freetype2/src/sfnt/pngshim.c index ca85d9751..9df75dc3a 100644 --- a/src/thirdparty/freetype2/src/sfnt/pngshim.c +++ b/src/thirdparty/freetype2/src/sfnt/pngshim.c @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * @@ -17,10 +17,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #include FT_CONFIG_STANDARD_LIBRARY_H @@ -61,13 +60,19 @@ /* predates clang; the `__BYTE_ORDER__' preprocessor symbol was */ /* introduced in gcc 4.6 and clang 3.2, respectively. */ /* `__builtin_shuffle' for gcc was introduced in gcc 4.7.0. */ -#if ( ( defined( __GNUC__ ) && \ + /* */ + /* Intel compilers do not currently support __builtin_shuffle; */ + + /* The Intel check must be first. */ +#if !defined( __INTEL_COMPILER ) && \ + ( ( defined( __GNUC__ ) && \ ( ( __GNUC__ >= 5 ) || \ ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ >= 7 ) ) ) ) || \ ( defined( __clang__ ) && \ ( ( __clang_major__ >= 4 ) || \ ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ defined( __OPTIMIZE__ ) && \ + defined( __SSE__ ) && \ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #ifdef __clang__ @@ -234,7 +239,7 @@ *e = FT_THROW( Invalid_Stream_Read ); png_error( png, NULL ); - return; + /* return; (never reached) */ } ft_memcpy( data, stream->cursor, length ); @@ -265,7 +270,10 @@ int bitdepth, color_type, interlace; FT_Int i; - png_byte* *rows = NULL; /* pacify compiler */ + + /* `rows` gets modified within a 'setjmp' scope; */ + /* we thus need the `volatile` keyword. */ + png_byte* *volatile rows = NULL; if ( x_offset < 0 || @@ -327,6 +335,13 @@ if ( populate_map_and_metrics ) { + /* reject too large bitmaps similarly to the rasterizer */ + if ( imgHeight > 0x7FFF || imgWidth > 0x7FFF ) + { + error = FT_THROW( Array_Too_Large ); + goto DestroyExit; + } + metrics->width = (FT_UShort)imgWidth; metrics->height = (FT_UShort)imgHeight; @@ -335,13 +350,6 @@ map->pixel_mode = FT_PIXEL_MODE_BGRA; map->pitch = (int)( map->width * 4 ); map->num_grays = 256; - - /* reject too large bitmaps similarly to the rasterizer */ - if ( map->rows > 0x7FFF || map->width > 0x7FFF ) - { - error = FT_THROW( Array_Too_Large ); - goto DestroyExit; - } } /* convert palette/gray image to rgb */ @@ -359,7 +367,7 @@ } /* transform transparency to alpha */ - if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) + if ( png_get_valid( png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) @@ -379,7 +387,7 @@ png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ - png_read_update_info(png, info ); + png_read_update_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, @@ -398,9 +406,7 @@ switch ( color_type ) { - default: - /* Shouldn't happen, but fall through. */ - + default: /* Shouldn't happen, but ... */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; @@ -422,7 +428,7 @@ goto DestroyExit; } - if ( FT_NEW_ARRAY( rows, imgHeight ) ) + if ( FT_QNEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; @@ -433,11 +439,11 @@ png_read_image( png, rows ); - FT_FREE( rows ); - png_read_end( png, info ); DestroyExit: + /* even if reading fails with longjmp, rows must be freed */ + FT_FREE( rows ); png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); @@ -448,7 +454,7 @@ #else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ /* ANSI C doesn't like empty source files */ - typedef int _pngshim_dummy; + typedef int pngshim_dummy_; #endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ diff --git a/src/thirdparty/freetype2/src/sfnt/pngshim.h b/src/thirdparty/freetype2/src/sfnt/pngshim.h index 06c6f6b20..c59199e60 100644 --- a/src/thirdparty/freetype2/src/sfnt/pngshim.h +++ b/src/thirdparty/freetype2/src/sfnt/pngshim.h @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2019 by + * Copyright (C) 2013-2025 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * @@ -21,7 +21,6 @@ #define PNGSHIM_H_ -#include #include "ttload.h" diff --git a/src/thirdparty/freetype2/src/sfnt/sfdriver.c b/src/thirdparty/freetype2/src/sfnt/sfdriver.c index 261168528..ec78247aa 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfdriver.c +++ b/src/thirdparty/freetype2/src/sfnt/sfdriver.c @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_OBJECTS_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include +#include #include "sfdriver.h" #include "ttload.h" @@ -37,27 +36,35 @@ #include "ttcpal.h" #endif +#ifdef FT_CONFIG_OPTION_SVG +#include "ttsvg.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 +#include +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.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 +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H +#include +#include #endif @@ -76,41 +83,57 @@ * */ - static void* - get_sfnt_table( TT_Face face, + FT_CALLBACK_DEF( FT_Error ) + sfnt_load_table( FT_Face face, /* TT_Face */ + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + TT_Face ttface = (TT_Face)face; + + + return tt_face_load_any( ttface, tag, offset, buffer, length ); + } + + + FT_CALLBACK_DEF( void* ) + get_sfnt_table( FT_Face face, /* TT_Face */ FT_Sfnt_Tag tag ) { + TT_Face ttface = (TT_Face)face; + void* table; switch ( tag ) { case FT_SFNT_HEAD: - table = &face->header; + table = &ttface->header; break; case FT_SFNT_HHEA: - table = &face->horizontal; + table = &ttface->horizontal; break; case FT_SFNT_VHEA: - table = face->vertical_info ? &face->vertical : NULL; + table = ttface->vertical_info ? &ttface->vertical : NULL; break; case FT_SFNT_OS2: - table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2; + table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2; break; case FT_SFNT_POST: - table = &face->postscript; + table = &ttface->postscript; break; case FT_SFNT_MAXP: - table = &face->max_profile; + table = &ttface->max_profile; break; case FT_SFNT_PCLT: - table = face->pclt.Version ? &face->pclt : NULL; + table = ttface->pclt.Version ? &ttface->pclt : NULL; break; default: @@ -121,26 +144,29 @@ } - static FT_Error - sfnt_table_info( TT_Face face, + FT_CALLBACK_DEF( FT_Error ) + sfnt_table_info( FT_Face face, /* TT_Face */ FT_UInt idx, FT_ULong *tag, FT_ULong *offset, FT_ULong *length ) { + TT_Face ttface = (TT_Face)face; + + if ( !offset || !length ) return FT_THROW( Invalid_Argument ); if ( !tag ) - *length = face->num_tables; + *length = ttface->num_tables; else { - if ( idx >= face->num_tables ) + if ( idx >= ttface->num_tables ) return FT_THROW( Table_Missing ); - *tag = face->dir_tables[idx].Tag; - *offset = face->dir_tables[idx].Offset; - *length = face->dir_tables[idx].Length; + *tag = ttface->dir_tables[idx].Tag; + *offset = ttface->dir_tables[idx].Offset; + *length = ttface->dir_tables[idx].Length; } return FT_Err_Ok; @@ -150,9 +176,9 @@ FT_DEFINE_SERVICE_SFNT_TABLEREC( sfnt_service_sfnt_table, - (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */ - (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */ - (FT_SFNT_TableInfoFunc)sfnt_table_info /* table_info */ + sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */ + get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */ + sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */ ) @@ -163,7 +189,7 @@ * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) sfnt_get_glyph_name( FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, @@ -181,7 +207,7 @@ } - static FT_UInt + FT_CALLBACK_DEF( FT_UInt ) sfnt_get_name_index( FT_Face face, const FT_String* glyph_name ) { @@ -195,7 +221,7 @@ else if ( (FT_ULong)face->num_glyphs < FT_UINT_MAX ) max_gid = (FT_UInt)face->num_glyphs; else - FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08x\n", + FT_TRACE0(( "Ignore glyph names for invalid GID 0x%08x - 0x%08lx\n", FT_UINT_MAX, face->num_glyphs )); for ( i = 0; i < max_gid; i++ ) @@ -218,8 +244,8 @@ FT_DEFINE_SERVICE_GLYPHDICTREC( sfnt_service_glyph_dict, - (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */ - (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index /* name_index */ + sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ ) #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ @@ -375,61 +401,61 @@ { case 15: k4 ^= (FT_UInt32)tail[14] << 16; - /* fall through */ + FALL_THROUGH; case 14: k4 ^= (FT_UInt32)tail[13] << 8; - /* fall through */ + FALL_THROUGH; case 13: k4 ^= (FT_UInt32)tail[12]; k4 *= c4; k4 = ROTL32( k4, 18 ); k4 *= c1; h4 ^= k4; - /* fall through */ + FALL_THROUGH; case 12: k3 ^= (FT_UInt32)tail[11] << 24; - /* fall through */ + FALL_THROUGH; case 11: k3 ^= (FT_UInt32)tail[10] << 16; - /* fall through */ + FALL_THROUGH; case 10: k3 ^= (FT_UInt32)tail[9] << 8; - /* fall through */ + FALL_THROUGH; case 9: k3 ^= (FT_UInt32)tail[8]; k3 *= c3; k3 = ROTL32( k3, 17 ); k3 *= c4; h3 ^= k3; - /* fall through */ + FALL_THROUGH; case 8: k2 ^= (FT_UInt32)tail[7] << 24; - /* fall through */ + FALL_THROUGH; case 7: k2 ^= (FT_UInt32)tail[6] << 16; - /* fall through */ + FALL_THROUGH; case 6: k2 ^= (FT_UInt32)tail[5] << 8; - /* fall through */ + FALL_THROUGH; case 5: k2 ^= (FT_UInt32)tail[4]; k2 *= c2; k2 = ROTL32( k2, 16 ); k2 *= c3; h2 ^= k2; - /* fall through */ + FALL_THROUGH; case 4: k1 ^= (FT_UInt32)tail[3] << 24; - /* fall through */ + FALL_THROUGH; case 3: k1 ^= (FT_UInt32)tail[2] << 16; - /* fall through */ + FALL_THROUGH; case 2: k1 ^= (FT_UInt32)tail[1] << 8; - /* fall through */ + FALL_THROUGH; case 1: k1 ^= (FT_UInt32)tail[0]; k1 *= c1; @@ -492,17 +518,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength / 2 + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -522,15 +546,14 @@ FT_TRACE0(( "get_win_string:" " Character 0x%X invalid in PS name string\n", ((unsigned)p[0])*256 + (unsigned)p[1] )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_win_string_error: @@ -551,17 +574,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -581,15 +602,14 @@ FT_TRACE0(( "get_apple_string:" " Character `%c' (0x%X) invalid in PS name string\n", *p, *p )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_apple_string_error: @@ -603,7 +623,7 @@ } - static FT_Bool + FT_CALLBACK_DEF( FT_Bool ) sfnt_get_name_id( TT_Face face, FT_UShort id, FT_Int *win, @@ -658,7 +678,7 @@ /* - * Find the shortest decimal representation of a 16.16 fixed point + * Find the shortest decimal representation of a 16.16 fixed-point * number. The function fills `buf' with the result, returning a pointer * to the position after the representation's last byte. */ @@ -734,7 +754,7 @@ an equivalent representation of `fixed'. The above FOR loop always finds the larger of the two values; I - verified this by iterating over all possible fixed point numbers. + verified this by iterating over all possible fixed-point numbers. If the remainder is 17232*10, both values are equally good, and we take the next even number (following IEEE 754's `round to nearest, @@ -742,7 +762,7 @@ If the remainder is smaller than 17232*10, the lower of the two numbers is nearer to the exact result (values 17232 and 34480 were - also found by testing all possible fixed point values). + also found by testing all possible fixed-point values). We use this to find a shorter decimal representation. If not ending with digit zero, we take the representation with less error. @@ -820,9 +840,9 @@ if ( !found ) { - /* as a last resort we try the family name; note that this is */ - /* not in the Adobe TechNote, but GX fonts (which predate the */ - /* TechNote) benefit from this behaviour */ + /* according to the 'name' documentation in the OpenType */ + /* specification the font family name is to be used if the */ + /* typographic family name is missing, so let's do that */ found = sfnt_get_name_id( face, TT_NAME_ID_FONT_FAMILY, &win, @@ -854,6 +874,10 @@ { FT_TRACE0(( "sfnt_get_var_ps_name:" " No valid PS name prefix for font instances found\n" )); + /* XXX It probably makes sense to never let this fail */ + /* since an arbitrary prefix should work, too. */ + /* On the other hand, it is very unlikely that */ + /* we ever reach this code at all. */ return NULL; } @@ -869,9 +893,9 @@ result[len] = '\0'; FT_TRACE0(( "sfnt_get_var_ps_name:" - " Shortening variation PS name prefix\n" - " " - " to %d characters\n", len )); + " Shortening variation PS name prefix\n" )); + FT_TRACE0(( " " + " to %u characters\n", len )); } face->var_postscript_prefix = result; @@ -921,16 +945,16 @@ if ( !subfamily_name ) { FT_TRACE1(( "sfnt_get_var_ps_name:" - " can't construct named instance PS name;\n" - " " + " can't construct named instance PS name;\n" )); + FT_TRACE1(( " " " trying to construct normal instance PS name\n" )); goto construct_instance_name; } /* after the prefix we have character `-' followed by the */ /* subfamily name (using only characters a-z, A-Z, and 0-9) */ - if ( FT_ALLOC( result, face->var_postscript_prefix_len + - 1 + ft_strlen( subfamily_name ) + 1 ) ) + if ( FT_QALLOC( result, face->var_postscript_prefix_len + + 1 + ft_strlen( subfamily_name ) + 1 ) ) return NULL; ft_strcpy( result, face->var_postscript_prefix ); @@ -958,9 +982,9 @@ construct_instance_name: axis = mm_var->axis; - if ( FT_ALLOC( result, - face->var_postscript_prefix_len + - num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) + if ( FT_QALLOC( result, + face->var_postscript_prefix_len + + num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) return NULL; p = result; @@ -994,6 +1018,7 @@ if ( t != ' ' && ft_isalnum( t ) ) *p++ = t; } + *p++ = '\0'; } check_length: @@ -1041,47 +1066,49 @@ #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ - static const char* - sfnt_get_ps_name( TT_Face face ) + FT_CALLBACK_DEF( const char* ) + sfnt_get_ps_name( FT_Face face ) /* TT_Face */ { + TT_Face ttface = (TT_Face)face; + FT_Int found, win, apple; const char* result = NULL; - if ( face->postscript_name ) - return face->postscript_name; + if ( ttface->postscript_name ) + return ttface->postscript_name; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( face->blend && - ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) ) + if ( ttface->blend && + ( FT_IS_NAMED_INSTANCE( face ) || + FT_IS_VARIATION( face ) ) ) { - face->postscript_name = sfnt_get_var_ps_name( face ); - return face->postscript_name; + ttface->postscript_name = sfnt_get_var_ps_name( ttface ); + return ttface->postscript_name; } #endif /* scan the name table to see whether we have a Postscript name here, */ /* either in Macintosh or Windows platform encodings */ - found = sfnt_get_name_id( face, TT_NAME_ID_PS_NAME, &win, &apple ); + found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple ); if ( !found ) return NULL; /* prefer Windows entries over Apple */ if ( win != -1 ) - result = get_win_string( face->root.memory, - face->name_table.stream, - face->name_table.names + win, + result = get_win_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + win, sfnt_is_postscript, 1 ); if ( !result && apple != -1 ) - result = get_apple_string( face->root.memory, - face->name_table.stream, - face->name_table.names + apple, + result = get_apple_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + apple, sfnt_is_postscript, 1 ); - face->postscript_name = result; + ttface->postscript_name = result; return result; } @@ -1090,7 +1117,7 @@ FT_DEFINE_SERVICE_PSFONTNAMEREC( sfnt_service_ps_name, - (FT_PsName_GetFunc)sfnt_get_ps_name /* get_ps_font_name */ + sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ ) @@ -1100,14 +1127,14 @@ FT_DEFINE_SERVICE_TTCMAPSREC( tt_service_get_cmap_info, - (TT_CMap_Info_GetFunc)tt_get_cmap_info /* get_cmap_info */ + tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ ) #ifdef TT_CONFIG_OPTION_BDF static FT_Error - sfnt_get_charset_id( TT_Face face, + sfnt_get_charset_id( FT_Face face, const char* *acharset_encoding, const char* *acharset_registry ) { @@ -1145,8 +1172,8 @@ FT_DEFINE_SERVICE_BDFRec( sfnt_service_bdf, - (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */ - (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop /* get_property */ + sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */ + tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */ ) @@ -1214,10 +1241,24 @@ #define PUT_COLOR_LAYERS( a ) NULL #endif +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_SUPPORT( a ) a +#else +#define PUT_SVG_SUPPORT( a ) NULL +#endif + +#define PUT_COLOR_LAYERS_V1( a ) PUT_COLOR_LAYERS( a ) + #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #define PUT_PS_NAMES( a ) a #else #define PUT_PS_NAMES( a ) NULL +#endif + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#define PUT_GPOS_KERNING( a ) a +#else +#define PUT_GPOS_KERNING( a ) NULL #endif FT_DEFINE_SFNT_INTERFACE( @@ -1243,6 +1284,8 @@ tt_face_free_name, /* TT_Free_Table_Func free_name */ tt_face_load_kern, /* TT_Load_Table_Func load_kern */ + PUT_GPOS_KERNING( tt_face_load_gpos ), + /* TT_Load_Table_Func load_gpos */ tt_face_load_gasp, /* TT_Load_Table_Func load_gasp */ tt_face_load_pclt, /* TT_Load_Table_Func load_init */ @@ -1261,6 +1304,9 @@ /* since version 2.1.8 */ tt_face_get_kerning, /* TT_Face_GetKerningFunc get_kerning */ + PUT_GPOS_KERNING( tt_face_get_gpos_kerning ), + /* TT_Face_GetKerningFunc get_gpos_kerning */ + /* since version 2.2 */ tt_face_load_font_dir, /* TT_Load_Table_Func load_font_dir */ tt_face_load_hmtx, /* TT_Load_Metrics_Func load_hmtx */ @@ -1272,9 +1318,9 @@ /* TT_Free_Table_Func free_eblc */ PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), - /* TT_Set_SBit_Strike_Func set_sbit_strike */ + /* TT_Set_SBit_Strike_Func set_sbit_strike */ PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), - /* TT_Load_Strike_Metrics_Func load_strike_metrics */ + /* TT_Load_Strike_Metrics_Func load_strike_metrics */ PUT_COLOR_LAYERS( tt_face_load_cpal ), /* TT_Load_Table_Func load_cpal */ @@ -1288,13 +1334,32 @@ /* TT_Set_Palette_Func set_palette */ PUT_COLOR_LAYERS( tt_face_get_colr_layer ), /* TT_Get_Colr_Layer_Func get_colr_layer */ + + PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ), + /* TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ), + /* TT_Get_Color_Glyph_ClipBox_Func get_clipbox */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ), + /* TT_Get_Paint_Layers_Func get_paint_layers */ + PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ), + /* TT_Get_Paint get_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint ), + /* TT_Get_Colorline_Stops_Func get_colorline_stops */ + PUT_COLOR_LAYERS( tt_face_colr_blend_layer ), /* TT_Blend_Colr_Func colr_blend */ tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ tt_face_get_name, /* TT_Get_Name_Func get_name */ - sfnt_get_name_id /* TT_Get_Name_ID_Func get_name_id */ + sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */ + + PUT_SVG_SUPPORT( tt_face_load_svg ), + /* TT_Load_Table_Func load_svg */ + PUT_SVG_SUPPORT( tt_face_free_svg ), + /* TT_Free_Table_Func free_svg */ + PUT_SVG_SUPPORT( tt_face_load_svg_doc ) + /* TT_Load_Svg_Doc_Func load_svg_doc */ ) @@ -1310,9 +1375,9 @@ (const void*)&sfnt_interface, /* module specific interface */ - (FT_Module_Constructor)NULL, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) sfnt_get_interface /* get_interface */ + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + sfnt_get_interface /* FT_Module_Requester get_interface */ ) diff --git a/src/thirdparty/freetype2/src/sfnt/sfdriver.h b/src/thirdparty/freetype2/src/sfnt/sfdriver.h index 8c174634b..be4e33166 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfdriver.h +++ b/src/thirdparty/freetype2/src/sfnt/sfdriver.h @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define SFDRIVER_H_ -#include -#include FT_MODULE_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/sferrors.h b/src/thirdparty/freetype2/src/sfnt/sferrors.h index 43e148d29..2da4ac776 100644 --- a/src/thirdparty/freetype2/src/sfnt/sferrors.h +++ b/src/thirdparty/freetype2/src/sfnt/sferrors.h @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef SFERRORS_H_ #define SFERRORS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX SFNT_Err_ #define FT_ERR_BASE FT_Mod_Err_SFNT -#include FT_ERRORS_H +#include #endif /* SFERRORS_H_ */ diff --git a/src/thirdparty/freetype2/src/sfnt/sfobjs.c b/src/thirdparty/freetype2/src/sfnt/sfobjs.c index 6edf3ae1d..6af35787e 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfobjs.c +++ b/src/thirdparty/freetype2/src/sfnt/sfobjs.c @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,22 +16,22 @@ */ -#include #include "sfobjs.h" #include "ttload.h" #include "ttcmap.h" #include "ttkern.h" #include "sfwoff.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 FT_SFNT_NAMES_H +#include "sfwoff2.h" +#include +#include +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_METRICS_VARIATIONS_H +#include +#include #endif #include "sferrors.h" @@ -40,6 +40,10 @@ #include "ttbdf.h" #endif +#ifdef TT_CONFIG_OPTION_GPOS_KERNING +#include "ttgpos.h" +#endif + /************************************************************************** * @@ -65,7 +69,7 @@ len = (FT_UInt)entry->stringLength / 2; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -100,7 +104,7 @@ len = (FT_UInt)entry->stringLength; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -341,7 +345,9 @@ /* synthesized into a TTC with one offset table. */ static FT_Error sfnt_open_font( FT_Stream stream, - TT_Face face ) + TT_Face face, + FT_Int* face_instance_index, + FT_Long* woff2_num_faces ) { FT_Memory memory = stream->memory; FT_Error error; @@ -358,17 +364,27 @@ FT_FRAME_END }; +#ifndef FT_CONFIG_OPTION_USE_BROTLI + FT_UNUSED( face_instance_index ); + FT_UNUSED( woff2_num_faces ); +#endif + face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_BROTLI ) retry: +#endif + offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; +#ifdef FT_CONFIG_OPTION_USE_ZLIB if ( tag == TTAG_wOFF ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); @@ -384,6 +400,28 @@ stream = face->root.stream; goto retry; } +#endif + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + if ( tag == TTAG_wOF2 ) + { + FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" )); + + if ( FT_STREAM_SEEK( offset ) ) + return error; + + error = woff2_open_font( stream, + face, + face_instance_index, + woff2_num_faces ); + if ( error ) + return error; + + /* Swap out stream and retry! */ + stream = face->root.stream; + goto retry; + } +#endif if ( tag != 0x00010000UL && tag != TTAG_ttcf && @@ -425,7 +463,7 @@ return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ - if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + if ( FT_QNEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) @@ -443,7 +481,7 @@ face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; - if ( FT_NEW( face->ttc_header.offsets ) ) + if ( FT_QNEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; @@ -461,9 +499,10 @@ FT_Parameter* params ) { FT_Error error; - FT_Library library = face->root.driver->root.library; + FT_Library library = face->root.driver->root.library; SFNT_Service sfnt; FT_Int face_index; + FT_Long woff2_num_faces = 0; /* for now, parameters are unused */ @@ -499,38 +538,50 @@ 0 ); } - if ( !face->var ) + if ( !face->tt_var ) { /* we want the metrics variations interface */ /* from the `truetype' module only */ FT_Module tt_module = FT_Get_Module( library, "truetype" ); - face->var = ft_module_get_service( tt_module, - FT_SERVICE_ID_METRICS_VARIATIONS, - 0 ); + face->tt_var = ft_module_get_service( tt_module, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); } + + if ( !face->face_var ) + face->face_var = ft_module_get_service( + &face->root.driver->root, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); #endif FT_TRACE2(( "SFNT driver\n" )); - error = sfnt_open_font( stream, face ); + error = sfnt_open_font( stream, + face, + &face_instance_index, + &woff2_num_faces ); if ( error ) return error; /* Stream may have changed in sfnt_open_font. */ stream = face->root.stream; - FT_TRACE2(( "sfnt_init_face: %08p (index %d)\n", - face, + FT_TRACE2(( "sfnt_init_face: %p (index %d)\n", + (void *)face, face_instance_index )); face_index = FT_ABS( face_instance_index ) & 0xFFFF; /* value -(N+1) requests information on index N */ - if ( face_instance_index < 0 ) + if ( face_instance_index < 0 && face_index > 0 ) face_index--; + /* Note that `face_index` is also used to enumerate elements */ + /* of containers like a Mac Resource; this means we must */ + /* check whether we actually have a TTC. */ if ( face_index >= face->ttc_header.count ) { if ( face_instance_index >= 0 ) @@ -618,8 +669,8 @@ */ if ( ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) && - !( FT_ALLOC( default_values, num_axes * 4 ) || - FT_ALLOC( instance_values, num_axes * 4 ) ) ) + !( FT_QALLOC( default_values, num_axes * 4 ) || + FT_QALLOC( instance_values, num_axes * 4 ) ) ) { /* the current stream position is 16 bytes after the table start */ FT_ULong array_start = FT_STREAM_POS() - 16 + offset; @@ -654,6 +705,9 @@ instance_offset += instance_size; } + /* named instance indices start with value 1 */ + face->var_default_named_instance = i + 1; + if ( i == num_instances ) { /* no default instance in named instance table; */ @@ -689,6 +743,10 @@ face->root.num_faces = face->ttc_header.count; face->root.face_index = face_instance_index; + /* `num_faces' for a WOFF2 needs to be handled separately. */ + if ( woff2_num_faces ) + face->root.num_faces = woff2_num_faces; + return error; } @@ -742,17 +800,23 @@ FT_Int num_params, FT_Parameter* params ) { - FT_Error error; + FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES - FT_Error psnames_error; + FT_Error psnames_error; #endif - FT_Bool has_outline; - FT_Bool is_apple_sbit; - FT_Bool is_apple_sbix; - FT_Bool has_CBLC; - FT_Bool has_CBDT; - FT_Bool ignore_typographic_family = FALSE; - FT_Bool ignore_typographic_subfamily = FALSE; + + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + FT_Bool has_CBLC; + FT_Bool has_CBDT; + FT_Bool has_EBLC; + FT_Bool has_bloc; + FT_Bool has_sbix; + + FT_Bool ignore_typographic_family = FALSE; + FT_Bool ignore_typographic_subfamily = FALSE; + FT_Bool ignore_sbix = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; @@ -771,6 +835,8 @@ ignore_typographic_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY ) ignore_typographic_subfamily = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_SBIX ) + ignore_sbix = TRUE; } } @@ -791,7 +857,8 @@ /* it doesn't contain outlines. */ /* */ - FT_TRACE2(( "sfnt_load_face: %08p\n\n", face )); + FT_TRACE2(( "sfnt_load_face: %p\n", (void *)face )); + FT_TRACE2(( "\n" )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL @@ -805,14 +872,17 @@ tt_face_lookup_table( face, TTAG_CFF2 ) ); #endif - is_apple_sbit = 0; - is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); + /* check which sbit formats are present */ + has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); + has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); + has_EBLC = !face->goto_table( face, TTAG_EBLC, stream, 0 ); + has_bloc = !face->goto_table( face, TTAG_bloc, stream, 0 ); + has_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); - /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' - * outline rendered on top. We don't support that yet, so just ignore - * the 'glyf' outline and advertise it as a bitmap-only font. */ - if ( is_apple_sbix ) - has_outline = FALSE; + is_apple_sbit = FALSE; + + if ( ignore_sbix ) + has_sbix = FALSE; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ @@ -824,16 +894,13 @@ /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ - if ( !is_apple_sbit || is_apple_sbix ) + if ( !is_apple_sbit || has_sbix ) { LOAD_( head ); if ( error ) goto Exit; } - has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); - has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); - /* Ignore outlines for CBLC/CBDT fonts. */ if ( has_CBLC || has_CBDT ) has_outline = FALSE; @@ -943,7 +1010,11 @@ /* the optional tables */ /* embedded bitmap support */ - if ( sfnt->load_eblc ) + /* TODO: Replace this clumsy check for all possible sbit tables */ + /* with something better (for example, by passing a parameter */ + /* to suppress 'sbix' loading). */ + if ( sfnt->load_eblc && + ( has_CBLC || has_EBLC || has_bloc || has_sbix ) ) LOAD_( eblc ); /* colored glyph support */ @@ -953,11 +1024,19 @@ LOAD_( colr ); } + /* OpenType-SVG glyph support */ + if ( sfnt->load_svg ) + LOAD_( svg ); + /* consider the pclt, kerning, and gasp tables as optional */ LOAD_( pclt ); LOAD_( gasp ); LOAD_( kern ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + LOAD_( gpos ); +#endif + face->root.num_glyphs = face->max_profile.numGlyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ @@ -995,6 +1074,16 @@ GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + + if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) ) + goto Exit; + } +#endif + /* now set up root fields */ { FT_Face root = &face->root; @@ -1007,11 +1096,19 @@ */ if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX || - face->colr ) + face->colr || + face->svg ) flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ if ( has_outline == TRUE ) - flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + { + /* by default (and for backward compatibility) we handle */ + /* fonts with an 'sbix' table as bitmap-only */ + if ( has_sbix ) + flags |= FT_FACE_FLAG_SBIX; /* with 'sbix' bitmaps */ + else + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + } /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ @@ -1033,20 +1130,18 @@ flags |= FT_FACE_FLAG_VERTICAL; /* kerning available ? */ - if ( TT_FACE_HAS_KERNING( face ) ) + if ( face->kern_avail_bits +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + || face->num_gpos_lookups_kerning +#endif + ) 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 ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) - { - if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && - tt_face_lookup_table( face, TTAG_gvar ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; - if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; - } + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; @@ -1120,9 +1215,10 @@ } /* synthesize Unicode charmap if one is missing */ - if ( !has_unicode ) + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) { - FT_CharMapRec cmaprec; + FT_CharMapRec cmaprec; cmaprec.face = root; @@ -1159,7 +1255,7 @@ if ( count > 0 ) { - FT_Memory memory = face->root.stream->memory; + FT_Memory memory = face->root.memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; @@ -1178,7 +1274,7 @@ /* of `FT_Face', we map `available_sizes' indices to strike */ /* indices */ if ( FT_NEW_ARRAY( root->available_sizes, count ) || - FT_NEW_ARRAY( sbit_strike_map, count ) ) + FT_QNEW_ARRAY( sbit_strike_map, count ) ) goto Exit; bsize_idx = 0; @@ -1207,7 +1303,7 @@ } /* reduce array size to the actually used elements */ - (void)FT_RENEW_ARRAY( sbit_strike_map, count, bsize_idx ); + FT_MEM_QRENEW_ARRAY( sbit_strike_map, count, bsize_idx ); /* from now on, all strike indices are mapped */ /* using `sbit_strike_map' */ @@ -1233,7 +1329,8 @@ * * Set up metrics. */ - if ( FT_IS_SCALABLE( root ) ) + if ( FT_IS_SCALABLE( root ) || + FT_HAS_SBIX( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ @@ -1372,6 +1469,12 @@ sfnt->free_cpal( face ); sfnt->free_colr( face ); } + +#ifdef FT_CONFIG_OPTION_SVG + /* free SVG data */ + if ( sfnt->free_svg ) + sfnt->free_svg( face ); +#endif } #ifdef TT_CONFIG_OPTION_BDF @@ -1382,6 +1485,11 @@ /* freeing the kerning table */ tt_face_done_kern( face ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + /* freeing the GPOS table */ + tt_face_done_gpos( face ); +#endif + /* freeing the collection table */ FT_FREE( face->ttc_header.offsets ); face->ttc_header.count = 0; @@ -1431,6 +1539,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_FREE( face->var_postscript_prefix ); + FT_FREE( face->non_var_style_name ); #endif /* freeing glyph color palette data */ diff --git a/src/thirdparty/freetype2/src/sfnt/sfobjs.h b/src/thirdparty/freetype2/src/sfnt/sfobjs.h index 3fbf2dd6b..8c38b7279 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfobjs.h +++ b/src/thirdparty/freetype2/src/sfnt/sfobjs.h @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define SFOBJS_H_ -#include -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_OBJECTS_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/sfwoff.c b/src/thirdparty/freetype2/src/sfnt/sfwoff.c index ca4821a20..015c7b78b 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfwoff.c +++ b/src/thirdparty/freetype2/src/sfnt/sfwoff.c @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,15 @@ */ -#include #include "sfwoff.h" -#include FT_TRUETYPE_TAGS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_GZIP_H +#include +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_ZLIB /************************************************************************** @@ -62,12 +65,11 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_offsets( const void* a, const void* b ) { @@ -110,7 +112,7 @@ FT_ULong sfnt_offset; FT_Int nn; - FT_ULong old_tag = 0; + FT_Tag old_tag = 0; static const FT_Frame_Field woff_header_fields[] = { @@ -148,6 +150,7 @@ /* Miscellaneous checks. */ if ( woff.length != stream->size || woff.num_tables == 0 || + woff.num_tables > 0xFFFU || 44 + woff.num_tables * 20UL >= woff.length || 12 + woff.num_tables * 16UL >= woff.totalSfntSize || ( woff.totalSfntSize & 3 ) != 0 || @@ -161,29 +164,18 @@ } /* Don't trust `totalSfntSize' before thorough checks. */ - if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) || - FT_NEW( sfnt_stream ) ) + if ( FT_QALLOC( sfnt, 12 ) || FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; /* Write sfnt header. */ { - FT_UInt searchRange, entrySelector, rangeShift, x; + FT_Int entrySelector = FT_MSB( woff.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff.num_tables * 16 - searchRange; - x = woff.num_tables; - entrySelector = 0; - while ( x ) - { - x >>= 1; - entrySelector += 1; - } - entrySelector--; - - searchRange = ( 1 << entrySelector ) * 16; - rangeShift = woff.num_tables * 16 - searchRange; - WRITE_ULONG ( sfnt_header, woff.flavor ); WRITE_USHORT( sfnt_header, woff.num_tables ); WRITE_USHORT( sfnt_header, searchRange ); @@ -195,13 +187,13 @@ /* tag value, the tables themselves are not. We thus have to */ /* sort them by offset and check that they don't overlap. */ - if ( FT_NEW_ARRAY( tables, woff.num_tables ) || - FT_NEW_ARRAY( indices, woff.num_tables ) ) + if ( FT_QNEW_ARRAY( tables, woff.num_tables ) || + FT_QNEW_ARRAY( indices, woff.num_tables ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset compLen origLen checksum\n" - " -------------------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset compLen origLen checksum\n" )); + FT_TRACE2(( " -------------------------------------------\n" )); if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) goto Exit; @@ -327,9 +319,7 @@ } /* Now use `totalSfntSize'. */ - if ( FT_REALLOC( sfnt, - 12 + woff.num_tables * 16UL, - woff.totalSfntSize ) ) + if ( FT_QREALLOC( sfnt, 12, woff.totalSfntSize ) ) goto Exit; sfnt_header = sfnt + 12; @@ -361,8 +351,6 @@ } else { -#ifdef FT_CONFIG_OPTION_USE_ZLIB - /* Uncompress with zlib. */ FT_ULong output_len = table->OrigLength; @@ -371,20 +359,13 @@ sfnt + table->OrigOffset, &output_len, stream->cursor, table->CompLength ); if ( error ) - goto Exit; + goto Exit1; if ( output_len != table->OrigLength ) { FT_ERROR(( "woff_font_open: compressed table length mismatch\n" )); error = FT_THROW( Invalid_Table ); - goto Exit; + goto Exit1; } - -#else /* !FT_CONFIG_OPTION_USE_ZLIB */ - - error = FT_THROW( Unimplemented_Feature ); - goto Exit; - -#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ } FT_FRAME_EXIT(); @@ -424,11 +405,22 @@ } return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; } #undef WRITE_USHORT #undef WRITE_ULONG +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + /* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/sfwoff.h b/src/thirdparty/freetype2/src/sfnt/sfwoff.h index 15495c32a..df7ace5c2 100644 --- a/src/thirdparty/freetype2/src/sfnt/sfwoff.h +++ b/src/thirdparty/freetype2/src/sfnt/sfwoff.h @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,19 +20,21 @@ #define SFWOFF_H_ -#include -#include FT_INTERNAL_SFNT_H -#include FT_INTERNAL_OBJECTS_H +#include +#include FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_ZLIB FT_LOCAL( FT_Error ) woff_open_font( FT_Stream stream, TT_Face face ); +#endif + FT_END_HEADER #endif /* SFWOFF_H_ */ diff --git a/src/thirdparty/freetype2/src/sfnt/sfwoff2.c b/src/thirdparty/freetype2/src/sfnt/sfwoff2.c new file mode 100644 index 000000000..5acbbaa2a --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/sfwoff2.c @@ -0,0 +1,2380 @@ +/**************************************************************************** + * + * sfwoff2.c + * + * WOFF2 format management (base). + * + * Copyright (C) 2019-2025 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 "sfwoff2.h" +#include "woff2tags.h" +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include + + + /************************************************************************** + * + * 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 sfwoff2 + + /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */ +#define MAX_SFNT_SIZE ( 1 << 26 ) + +#define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) ) + +#define READ_BASE128( var ) FT_SET_ERROR( ReadBase128( stream, &var ) ) + + /* `var' should be FT_ULong */ +#define ROUND4( var ) ( ( var + 3 ) & ~3UL ) + +#define WRITE_USHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_ULONG( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 24 ); \ + *(p)++ = (FT_Byte)( (v) >> 16 ); \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SHORT( p, v ) \ + do \ + { \ + *(p)++ = (FT_Byte)( (v) >> 8 ); \ + *(p)++ = (FT_Byte)( (v) >> 0 ); \ + \ + } while ( 0 ) + +#define WRITE_SFNT_BUF( buf, s ) \ + write_buf( &sfnt, sfnt_size, &dest_offset, buf, s, memory ) + +#define WRITE_SFNT_BUF_AT( offset, buf, s ) \ + write_buf( &sfnt, sfnt_size, &offset, buf, s, memory ) + +#define N_CONTOUR_STREAM 0 +#define N_POINTS_STREAM 1 +#define FLAG_STREAM 2 +#define GLYPH_STREAM 3 +#define COMPOSITE_STREAM 4 +#define BBOX_STREAM 5 +#define INSTRUCTION_STREAM 6 + +#define HAVE_OVERLAP_SIMPLE_BITMAP 0x1 + + + static void + stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->close = NULL; + } + + + FT_COMPARE_DEF( int ) + compare_tags( const void* a, + const void* b ) + { + WOFF2_Table table1 = *(WOFF2_Table*)a; + WOFF2_Table table2 = *(WOFF2_Table*)b; + + FT_Tag tag1 = table1->Tag; + FT_Tag tag2 = table2->Tag; + + + if ( tag1 > tag2 ) + return 1; + else if ( tag1 < tag2 ) + return -1; + else + return 0; + } + + + static FT_Error + Read255UShort( FT_Stream stream, + FT_UShort* value ) + { + const FT_Byte oneMoreByteCode1 = 255; + const FT_Byte oneMoreByteCode2 = 254; + const FT_Byte wordCode = 253; + const FT_UShort lowestUCode = 253; + + FT_Error error = FT_Err_Ok; + FT_Byte code; + FT_Byte result_byte = 0; + FT_UShort result_short = 0; + + + if ( FT_READ_BYTE( code ) ) + return error; + if ( code == wordCode ) + { + /* Read next two bytes and store `FT_UShort' value. */ + if ( FT_READ_USHORT( result_short ) ) + return error; + *value = result_short; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode1 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode; + return FT_Err_Ok; + } + else if ( code == oneMoreByteCode2 ) + { + if ( FT_READ_BYTE( result_byte ) ) + return error; + *value = result_byte + lowestUCode * 2; + return FT_Err_Ok; + } + else + { + *value = code; + return FT_Err_Ok; + } + } + + + static FT_Error + ReadBase128( FT_Stream stream, + FT_ULong* value ) + { + FT_ULong result = 0; + FT_Int i; + FT_Byte code; + FT_Error error = FT_Err_Ok; + + + for ( i = 0; i < 5; ++i ) + { + code = 0; + if ( FT_READ_BYTE( code ) ) + return error; + + /* Leading zeros are invalid. */ + if ( i == 0 && code == 0x80 ) + return FT_THROW( Invalid_Table ); + + /* If any of top seven bits are set then we're about to overflow. */ + if ( result & 0xfe000000 ) + return FT_THROW( Invalid_Table ); + + result = ( result << 7 ) | ( code & 0x7f ); + + /* Spin until most significant bit of data byte is false. */ + if ( ( code & 0x80 ) == 0 ) + { + *value = result; + return FT_Err_Ok; + } + } + + /* Make sure not to exceed the size bound. */ + return FT_THROW( Invalid_Table ); + } + + + /* Extend memory of `dst_bytes' buffer and copy data from `src'. */ + static FT_Error + write_buf( FT_Byte** dst_bytes, + FT_ULong* dst_size, + FT_ULong* offset, + FT_Byte* src, + FT_ULong size, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + /* We are reallocating memory for `dst', so its pointer may change. */ + FT_Byte* dst = *dst_bytes; + + + /* Check whether we are within limits. */ + if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) + return FT_THROW( Array_Too_Large ); + + /* Reallocate `dst'. */ + if ( ( *offset + size ) > *dst_size ) + { + FT_TRACE6(( "Reallocating %lu to %lu.\n", + *dst_size, (*offset + size) )); + if ( FT_QREALLOC( dst, + (FT_ULong)( *dst_size ), + (FT_ULong)( *offset + size ) ) ) + goto Exit; + + *dst_size = *offset + size; + } + + /* Copy data. */ + ft_memcpy( dst + *offset, src, size ); + + *offset += size; + /* Set pointer of `dst' to its correct value. */ + *dst_bytes = dst; + + Exit: + return error; + } + + + /* Pad buffer to closest multiple of 4. */ + static FT_Error + pad4( FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte zeroes[] = { 0, 0, 0 }; + FT_ULong pad_bytes; + + + if ( dest_offset + 3 < dest_offset ) + return FT_THROW( Invalid_Table ); + + pad_bytes = ROUND4( dest_offset ) - dest_offset; + if ( pad_bytes > 0 ) + { + if ( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) ) + return FT_THROW( Invalid_Table ); + } + + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + return FT_Err_Ok; + } + + + /* Calculate table checksum of `buf'. */ + static FT_ULong + compute_ULong_sum( FT_Byte* buf, + FT_ULong size ) + { + FT_ULong checksum = 0; + FT_ULong aligned_size = size & ~3UL; + FT_ULong i; + FT_Int shift; + + + for ( i = 0; i < aligned_size; i += 4 ) + checksum += FT_NEXT_ULONG( buf ); + + /* remaining bytes can be shifted and added one at a time */ + for ( shift = 24; i < size; i++, shift -= 8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( buf ) << shift; + + return checksum; + } + + + static FT_Error + woff2_decompress( FT_Byte* dst, + FT_ULong dst_size, + const FT_Byte* src, + FT_ULong src_size ) + { + /* this cast is only of importance on 32bit systems; */ + /* we don't validate it */ + FT_Offset uncompressed_size = (FT_Offset)dst_size; + BrotliDecoderResult result; + + + result = BrotliDecoderDecompress( src_size, + src, + &uncompressed_size, + dst ); + + if ( result != BROTLI_DECODER_RESULT_SUCCESS || + uncompressed_size != dst_size ) + { + FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); + return FT_Err_Ok; + } + + + static WOFF2_Table + find_table( WOFF2_Table* tables, + FT_UShort num_tables, + FT_Tag tag ) + { + FT_Int i; + + + for ( i = 0; i < num_tables; i++ ) + { + if ( tables[i]->Tag == tag ) + return tables[i]; + } + return NULL; + } + + + /* Read `numberOfHMetrics' field from `hhea' table. */ + static FT_Error + read_num_hmetrics( FT_Stream stream, + FT_UShort* num_hmetrics ) + { + FT_Error error = FT_Err_Ok; + FT_UShort num_metrics; + + + if ( FT_STREAM_SKIP( 34 ) ) + return FT_THROW( Invalid_Table ); + + if ( FT_READ_USHORT( num_metrics ) ) + return FT_THROW( Invalid_Table ); + + *num_hmetrics = num_metrics; + + return error; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + with_sign( FT_Byte flag, + FT_Int base_val ) + { + /* Precondition: 0 <= base_val < 65536 (to avoid overflow). */ + return ( flag & 1 ) ? base_val : -base_val; + } + + + /* An auxiliary function for overflow-safe addition. */ + static FT_Int + safe_int_addition( FT_Int a, + FT_Int b, + FT_Int* result ) + { + if ( ( ( a > 0 ) && ( b > FT_INT_MAX - a ) ) || + ( ( a < 0 ) && ( b < FT_INT_MIN - a ) ) ) + return FT_THROW( Invalid_Table ); + + *result = a + b; + return FT_Err_Ok; + } + + + /* + * Decode variable-length (flag, xCoordinate, yCoordinate) triplet for a + * simple glyph. See + * + * https://www.w3.org/TR/WOFF2/#triplet_decoding + */ + static FT_Error + triplet_decode( const FT_Byte* flags_in, + const FT_Byte* in, + FT_ULong in_size, + FT_ULong n_points, + WOFF2_Point result, + FT_ULong* in_bytes_used ) + { + FT_Int x = 0; + FT_Int y = 0; + FT_Int dx; + FT_Int dy; + FT_Int b0, b1, b2; + + FT_ULong triplet_index = 0; + FT_ULong data_bytes; + + FT_UInt i; + + + if ( n_points > in_size ) + return FT_THROW( Invalid_Table ); + + for ( i = 0; i < n_points; ++i ) + { + FT_Byte flag = flags_in[i]; + FT_Bool on_curve = !( flag >> 7 ); + + + flag &= 0x7f; + if ( flag < 84 ) + data_bytes = 1; + else if ( flag < 120 ) + data_bytes = 2; + else if ( flag < 124 ) + data_bytes = 3; + else + data_bytes = 4; + + /* Overflow checks */ + if ( triplet_index + data_bytes > in_size || + triplet_index + data_bytes < triplet_index ) + return FT_THROW( Invalid_Table ); + + if ( flag < 10 ) + { + dx = 0; + dy = with_sign( flag, + ( ( flag & 14 ) << 7 ) + in[triplet_index] ); + } + else if ( flag < 20 ) + { + dx = with_sign( flag, + ( ( ( flag - 10 ) & 14 ) << 7 ) + + in[triplet_index] ); + dy = 0; + } + else if ( flag < 84 ) + { + b0 = flag - 20; + b1 = in[triplet_index]; + dx = with_sign( flag, + 1 + ( b0 & 0x30 ) + ( b1 >> 4 ) ); + dy = with_sign( flag >> 1, + 1 + ( ( b0 & 0x0c ) << 2 ) + ( b1 & 0x0f ) ); + } + else if ( flag < 120 ) + { + b0 = flag - 84; + dx = with_sign( flag, + 1 + ( ( b0 / 12 ) << 8 ) + in[triplet_index] ); + dy = with_sign( flag >> 1, + 1 + ( ( ( b0 % 12 ) >> 2 ) << 8 ) + + in[triplet_index + 1] ); + } + else if ( flag < 124 ) + { + b2 = in[triplet_index + 1]; + dx = with_sign( flag, + ( in[triplet_index] << 4 ) + ( b2 >> 4 ) ); + dy = with_sign( flag >> 1, + ( ( b2 & 0x0f ) << 8 ) + in[triplet_index + 2] ); + } + else + { + dx = with_sign( flag, + ( in[triplet_index] << 8 ) + + in[triplet_index + 1] ); + dy = with_sign( flag >> 1, + ( in[triplet_index + 2] << 8 ) + + in[triplet_index + 3] ); + } + + triplet_index += data_bytes; + + if ( safe_int_addition( x, dx, &x ) ) + return FT_THROW( Invalid_Table ); + + if ( safe_int_addition( y, dy, &y ) ) + return FT_THROW( Invalid_Table ); + + result[i].x = x; + result[i].y = y; + result[i].on_curve = on_curve; + } + + *in_bytes_used = triplet_index; + return FT_Err_Ok; + } + + + /* Store decoded points in glyph buffer. */ + static FT_Error + store_points( FT_ULong n_points, + const WOFF2_Point points, + FT_UShort n_contours, + FT_UShort instruction_len, + FT_Bool have_overlap, + FT_Byte* dst, + FT_ULong dst_size, + FT_ULong* glyph_size ) + { + FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; + FT_Byte last_flag = 0xFFU; + FT_Byte repeat_count = 0; + FT_Int last_x = 0; + FT_Int last_y = 0; + FT_UInt x_bytes = 0; + FT_UInt y_bytes = 0; + FT_UInt xy_bytes; + FT_UInt i; + FT_UInt x_offset; + FT_UInt y_offset; + FT_Byte* pointer; + + + for ( i = 0; i < n_points; ++i ) + { + const WOFF2_PointRec point = points[i]; + + FT_Byte flag = point.on_curve ? GLYF_ON_CURVE : 0; + FT_Int dx = point.x - last_x; + FT_Int dy = point.y - last_y; + + + if ( i == 0 && have_overlap ) + flag |= GLYF_OVERLAP_SIMPLE; + + if ( dx == 0 ) + flag |= GLYF_THIS_X_IS_SAME; + else if ( dx > -256 && dx < 256 ) + { + flag |= GLYF_X_SHORT | ( dx > 0 ? GLYF_THIS_X_IS_SAME : 0 ); + x_bytes += 1; + } + else + x_bytes += 2; + + if ( dy == 0 ) + flag |= GLYF_THIS_Y_IS_SAME; + else if ( dy > -256 && dy < 256 ) + { + flag |= GLYF_Y_SHORT | ( dy > 0 ? GLYF_THIS_Y_IS_SAME : 0 ); + y_bytes += 1; + } + else + y_bytes += 2; + + if ( flag == last_flag && repeat_count != 255 ) + { + dst[flag_offset - 1] |= GLYF_REPEAT; + repeat_count++; + } + else + { + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = flag; + repeat_count = 0; + } + + last_x = point.x; + last_y = point.y; + last_flag = flag; + } + + if ( repeat_count != 0 ) + { + if ( flag_offset >= dst_size ) + return FT_THROW( Invalid_Table ); + + dst[flag_offset++] = repeat_count; + } + + xy_bytes = x_bytes + y_bytes; + if ( xy_bytes < x_bytes || + flag_offset + xy_bytes < flag_offset || + flag_offset + xy_bytes > dst_size ) + return FT_THROW( Invalid_Table ); + + x_offset = flag_offset; + y_offset = flag_offset + x_bytes; + last_x = 0; + last_y = 0; + + for ( i = 0; i < n_points; ++i ) + { + FT_Int dx = points[i].x - last_x; + FT_Int dy = points[i].y - last_y; + + + if ( dx == 0 ) + ; + else if ( dx > -256 && dx < 256 ) + dst[x_offset++] = (FT_Byte)FT_ABS( dx ); + else + { + pointer = dst + x_offset; + WRITE_SHORT( pointer, dx ); + x_offset += 2; + } + + last_x += dx; + + if ( dy == 0 ) + ; + else if ( dy > -256 && dy < 256 ) + dst[y_offset++] = (FT_Byte)FT_ABS( dy ); + else + { + pointer = dst + y_offset; + WRITE_SHORT( pointer, dy ); + y_offset += 2; + } + + last_y += dy; + } + + *glyph_size = y_offset; + return FT_Err_Ok; + } + + + static void + compute_bbox( FT_ULong n_points, + const WOFF2_Point points, + FT_Byte* dst, + FT_UShort* src_x_min ) + { + FT_Int x_min = 0; + FT_Int y_min = 0; + FT_Int x_max = 0; + FT_Int y_max = 0; + + FT_UInt i; + + FT_ULong offset; + FT_Byte* pointer; + + + if ( n_points > 0 ) + { + x_min = points[0].x; + y_min = points[0].y; + x_max = points[0].x; + y_max = points[0].y; + } + + for ( i = 1; i < n_points; ++i ) + { + FT_Int x = points[i].x; + FT_Int y = points[i].y; + + + x_min = FT_MIN( x, x_min ); + y_min = FT_MIN( y, y_min ); + x_max = FT_MAX( x, x_max ); + y_max = FT_MAX( y, y_max ); + } + + /* Write values to `glyf' record. */ + offset = 2; + pointer = dst + offset; + + WRITE_SHORT( pointer, x_min ); + WRITE_SHORT( pointer, y_min ); + WRITE_SHORT( pointer, x_max ); + WRITE_SHORT( pointer, y_max ); + + *src_x_min = (FT_UShort)x_min; + } + + + static FT_Error + compositeGlyph_size( FT_Stream stream, + FT_ULong offset, + FT_ULong* size, + FT_Bool* have_instructions ) + { + FT_Error error = FT_Err_Ok; + FT_ULong start_offset = offset; + FT_Bool we_have_inst = FALSE; + FT_UShort flags = FLAG_MORE_COMPONENTS; + + + if ( FT_STREAM_SEEK( start_offset ) ) + goto Exit; + while ( flags & FLAG_MORE_COMPONENTS ) + { + FT_ULong arg_size; + + + if ( FT_READ_USHORT( flags ) ) + goto Exit; + we_have_inst |= ( flags & FLAG_WE_HAVE_INSTRUCTIONS ) != 0; + /* glyph index */ + arg_size = 2; + if ( flags & FLAG_ARG_1_AND_2_ARE_WORDS ) + arg_size += 4; + else + arg_size += 2; + + if ( flags & FLAG_WE_HAVE_A_SCALE ) + arg_size += 2; + else if ( flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE ) + arg_size += 4; + else if ( flags & FLAG_WE_HAVE_A_TWO_BY_TWO ) + arg_size += 8; + + if ( FT_STREAM_SKIP( arg_size ) ) + goto Exit; + } + + *size = FT_STREAM_POS() - start_offset; + *have_instructions = we_have_inst; + + Exit: + return error; + } + + + /* Store loca values (provided by `reconstruct_glyf') to output stream. */ + static FT_Error + store_loca( FT_ULong* loca_values, + FT_ULong loca_values_size, + FT_UShort index_format, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte* loca_buf = NULL; + FT_Byte* dst = NULL; + + FT_UInt i = 0; + FT_ULong loca_buf_size; + + const FT_ULong offset_size = index_format ? 4 : 2; + + + if ( ( loca_values_size << 2 ) >> 2 != loca_values_size ) + goto Fail; + + loca_buf_size = loca_values_size * offset_size; + if ( FT_QALLOC( loca_buf, loca_buf_size ) ) + goto Fail; + + dst = loca_buf; + for ( i = 0; i < loca_values_size; i++ ) + { + FT_ULong value = loca_values[i]; + + + if ( index_format ) + WRITE_ULONG( dst, value ); + else + WRITE_USHORT( dst, ( value >> 1 ) ); + } + + *checksum = compute_ULong_sum( loca_buf, loca_buf_size ); + /* Write `loca' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( loca_buf ); + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + FT_FREE( loca_buf ); + + return error; + } + + + static FT_Error + reconstruct_glyf( FT_Stream stream, + FT_ULong* glyf_checksum, + FT_ULong* loca_checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + WOFF2_Info info, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + + /* current position in stream */ + const FT_ULong pos = FT_STREAM_POS(); + + FT_UInt num_substreams = 7; + + FT_UShort option_flags; + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong expected_loca_length; + FT_UInt offset; + FT_UInt i; + FT_ULong points_size; + FT_ULong glyph_buf_size; + FT_ULong bbox_bitmap_offset; + FT_ULong bbox_bitmap_length; + FT_ULong overlap_bitmap_offset = 0; + FT_ULong overlap_bitmap_length = 0; + + const FT_ULong glyf_start = *out_offset; + FT_ULong dest_offset = *out_offset; + + WOFF2_Substream substreams = NULL; + + FT_ULong* loca_values = NULL; + FT_UShort* n_points_arr = NULL; + FT_Byte* glyph_buf = NULL; + WOFF2_Point points = NULL; + + + if ( FT_QNEW_ARRAY( substreams, num_substreams ) ) + goto Fail; + + if ( FT_STREAM_SKIP( 2 ) ) + goto Fail; + if ( FT_READ_USHORT( option_flags ) ) + goto Fail; + if ( FT_READ_USHORT( num_glyphs ) ) + goto Fail; + if ( FT_READ_USHORT( index_format ) ) + goto Fail; + + FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n", + option_flags, num_glyphs, index_format )); + + info->num_glyphs = num_glyphs; + + /* Calculate expected length of loca and compare. */ + /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */ + /* index_format = 0 => Short version `loca'. */ + /* index_format = 1 => Long version `loca'. */ + expected_loca_length = ( index_format ? 4 : 2 ) * + ( (FT_ULong)num_glyphs + 1 ); + if ( info->loca_table->dst_length != expected_loca_length ) + goto Fail; + + offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 ); + if ( offset > info->glyf_table->TransformLength ) + goto Fail; + + for ( i = 0; i < num_substreams; ++i ) + { + FT_ULong substream_size; + + + if ( FT_READ_ULONG( substream_size ) ) + goto Fail; + if ( substream_size > info->glyf_table->TransformLength - offset ) + goto Fail; + + substreams[i].start = pos + offset; + substreams[i].offset = pos + offset; + substreams[i].size = substream_size; + + FT_TRACE5(( " Substream %u: offset = %lu; size = %lu;\n", + i, substreams[i].offset, substreams[i].size )); + offset += substream_size; + } + + if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP ) + { + /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */ + overlap_bitmap_length = ( num_glyphs + 7U ) >> 3; + if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset ) + goto Fail; + + overlap_bitmap_offset = pos + offset; + + FT_TRACE5(( " Overlap bitmap: offset = %lu; size = %lu;\n", + overlap_bitmap_offset, overlap_bitmap_length )); + offset += overlap_bitmap_length; + } + + if ( FT_QNEW_ARRAY( loca_values, num_glyphs + 1 ) ) + goto Fail; + + points_size = 0; + bbox_bitmap_offset = substreams[BBOX_STREAM].offset; + + /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ + bbox_bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; + /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */ + substreams[BBOX_STREAM].offset += bbox_bitmap_length; + + glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; + if ( FT_QALLOC( glyph_buf, glyph_buf_size ) ) + goto Fail; + + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + goto Fail; + + for ( i = 0; i < num_glyphs; ++i ) + { + FT_ULong glyph_size = 0; + FT_UShort n_contours = 0; + FT_Bool have_bbox = FALSE; + FT_Byte bbox_bitmap; + FT_ULong bbox_offset; + FT_UShort x_min = 0; + + + /* Set `have_bbox'. */ + bbox_offset = bbox_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( bbox_offset ) || + FT_READ_BYTE( bbox_bitmap ) ) + goto Fail; + if ( bbox_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_bbox = TRUE; + + /* Read value from `nContourStream'. */ + if ( FT_STREAM_SEEK( substreams[N_CONTOUR_STREAM].offset ) || + FT_READ_USHORT( n_contours ) ) + goto Fail; + substreams[N_CONTOUR_STREAM].offset += 2; + + if ( n_contours == 0xffff ) + { + /* composite glyph */ + FT_Bool have_instructions = FALSE; + FT_UShort instruction_size = 0; + FT_ULong composite_size = 0; + FT_ULong size_needed; + FT_Byte* pointer = NULL; + + + /* Composite glyphs must have explicit bbox. */ + if ( !have_bbox ) + goto Fail; + + if ( compositeGlyph_size( stream, + substreams[COMPOSITE_STREAM].offset, + &composite_size, + &have_instructions) ) + goto Fail; + + if ( have_instructions ) + { + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + } + + size_needed = 12 + composite_size + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + + substreams[BBOX_STREAM].offset += 8; + glyph_size += 8; + + if ( FT_STREAM_SEEK( substreams[COMPOSITE_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, composite_size ) ) + goto Fail; + + substreams[COMPOSITE_STREAM].offset += composite_size; + glyph_size += composite_size; + + if ( have_instructions ) + { + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + } + } + else if ( n_contours > 0 ) + { + /* simple glyph */ + FT_ULong total_n_points = 0; + FT_UShort n_points_contour; + FT_UInt j; + FT_ULong flag_size; + FT_ULong triplet_size; + FT_ULong triplet_bytes_used; + FT_Bool have_overlap = FALSE; + FT_Byte overlap_bitmap; + FT_ULong overlap_offset; + FT_Byte* flags_buf = NULL; + FT_Byte* triplet_buf = NULL; + FT_UShort instruction_size; + FT_ULong size_needed; + FT_Int end_point; + FT_UInt contour_ix; + + FT_Byte* pointer = NULL; + + + /* Set `have_overlap`. */ + if ( overlap_bitmap_offset ) + { + overlap_offset = overlap_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( overlap_offset ) || + FT_READ_BYTE( overlap_bitmap ) ) + goto Fail; + if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_overlap = TRUE; + } + + if ( FT_QNEW_ARRAY( n_points_arr, n_contours ) ) + goto Fail; + + if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) ) + goto Fail; + + for ( j = 0; j < n_contours; ++j ) + { + if ( READ_255USHORT( n_points_contour ) ) + goto Fail; + n_points_arr[j] = n_points_contour; + /* Prevent negative/overflow. */ + if ( total_n_points + n_points_contour < total_n_points ) + goto Fail; + total_n_points += n_points_contour; + } + substreams[N_POINTS_STREAM].offset = FT_STREAM_POS(); + + flag_size = total_n_points; + if ( flag_size > substreams[FLAG_STREAM].size ) + goto Fail; + + flags_buf = stream->base + substreams[FLAG_STREAM].offset; + triplet_buf = stream->base + substreams[GLYPH_STREAM].offset; + + if ( substreams[GLYPH_STREAM].size < + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ) ) + goto Fail; + + triplet_size = substreams[GLYPH_STREAM].size - + ( substreams[GLYPH_STREAM].offset - + substreams[GLYPH_STREAM].start ); + triplet_bytes_used = 0; + + /* Create array to store point information. */ + points_size = total_n_points; + if ( FT_QNEW_ARRAY( points, points_size ) ) + goto Fail; + + if ( triplet_decode( flags_buf, + triplet_buf, + triplet_size, + total_n_points, + points, + &triplet_bytes_used ) ) + goto Fail; + + substreams[FLAG_STREAM].offset += flag_size; + substreams[GLYPH_STREAM].offset += triplet_bytes_used; + + if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || + READ_255USHORT( instruction_size ) ) + goto Fail; + + substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); + + if ( total_n_points >= ( 1 << 27 ) ) + goto Fail; + + size_needed = 12 + + ( 2 * n_contours ) + + ( 5 * total_n_points ) + + instruction_size; + if ( glyph_buf_size < size_needed ) + { + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) + goto Fail; + glyph_buf_size = size_needed; + } + + pointer = glyph_buf + glyph_size; + WRITE_USHORT( pointer, n_contours ); + glyph_size += 2; + + if ( have_bbox ) + { + /* Read x_min for current glyph. */ + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_READ_USHORT( x_min ) ) + goto Fail; + /* No increment here because we read again. */ + + if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) + goto Fail; + substreams[BBOX_STREAM].offset += 8; + } + else + compute_bbox( total_n_points, points, glyph_buf, &x_min ); + + glyph_size = CONTOUR_OFFSET_END_POINT; + + pointer = glyph_buf + glyph_size; + end_point = -1; + + for ( contour_ix = 0; contour_ix < n_contours; ++contour_ix ) + { + end_point += n_points_arr[contour_ix]; + if ( end_point >= 65536 ) + goto Fail; + + WRITE_SHORT( pointer, end_point ); + glyph_size += 2; + } + + WRITE_USHORT( pointer, instruction_size ); + glyph_size += 2; + + if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || + FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) + goto Fail; + + substreams[INSTRUCTION_STREAM].offset += instruction_size; + glyph_size += instruction_size; + + if ( store_points( total_n_points, + points, + n_contours, + instruction_size, + have_overlap, + glyph_buf, + glyph_buf_size, + &glyph_size ) ) + goto Fail; + + FT_FREE( points ); + FT_FREE( n_points_arr ); + } + else + { + /* Empty glyph. */ + /* Must not have a bbox. */ + if ( have_bbox ) + { + FT_ERROR(( "Empty glyph has a bbox.\n" )); + goto Fail; + } + } + + loca_values[i] = dest_offset - glyf_start; + + if ( WRITE_SFNT_BUF( glyph_buf, glyph_size ) ) + goto Fail; + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size ); + + /* Store x_mins, may be required to reconstruct `hmtx'. */ + info->x_mins[i] = (FT_Short)x_min; + } + + info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset; + info->loca_table->dst_offset = dest_offset; + + /* `loca[n]' will be equal to the length of the `glyf' table. */ + loca_values[num_glyphs] = info->glyf_table->dst_length; + + if ( store_loca( loca_values, + num_glyphs + 1, + index_format, + loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + + info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset; + + FT_TRACE4(( " loca table info:\n" )); + FT_TRACE4(( " dst_offset = %lu\n", info->loca_table->dst_offset )); + FT_TRACE4(( " dst_length = %lu\n", info->loca_table->dst_length )); + FT_TRACE4(( " checksum = %09lx\n", *loca_checksum )); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); + + return error; + } + + + /* Get `x_mins' for untransformed `glyf' table. */ + static FT_Error + get_x_mins( FT_Stream stream, + WOFF2_Table* tables, + FT_UShort num_tables, + WOFF2_Info info, + FT_Memory memory ) + { + FT_UShort num_glyphs; + FT_UShort index_format; + FT_ULong glyf_offset; + FT_UShort glyf_offset_short; + FT_ULong loca_offset; + FT_Int i; + FT_Error error = FT_Err_Ok; + FT_ULong offset_size; + + /* At this point of time those tables might not have been read yet. */ + const WOFF2_Table maxp_table = find_table( tables, num_tables, + TTAG_maxp ); + const WOFF2_Table head_table = find_table( tables, num_tables, + TTAG_head ); + + + if ( !maxp_table ) + { + FT_ERROR(( "`maxp' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + if ( !info->loca_table ) + { + FT_ERROR(( "`loca' table is missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Read `numGlyphs' field from `maxp' table. */ + if ( FT_STREAM_SEEK( maxp_table->src_offset ) || FT_STREAM_SKIP( 8 ) ) + return error; + + if ( FT_READ_USHORT( num_glyphs ) ) + return error; + + info->num_glyphs = num_glyphs; + + /* Read `indexToLocFormat' field from `head' table. */ + if ( FT_STREAM_SEEK( head_table->src_offset ) || + FT_STREAM_SKIP( 50 ) ) + return error; + + if ( FT_READ_USHORT( index_format ) ) + return error; + + offset_size = index_format ? 4 : 2; + + /* Create `x_mins' array. */ + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) + return error; + + loca_offset = info->loca_table->src_offset; + + for ( i = 0; i < num_glyphs; ++i ) + { + if ( FT_STREAM_SEEK( loca_offset ) ) + return error; + + loca_offset += offset_size; + + if ( index_format ) + { + if ( FT_READ_ULONG( glyf_offset ) ) + return error; + } + else + { + if ( FT_READ_USHORT( glyf_offset_short ) ) + return error; + + glyf_offset = (FT_ULong)( glyf_offset_short ); + glyf_offset = glyf_offset << 1; + } + + glyf_offset += info->glyf_table->src_offset; + + if ( FT_STREAM_SEEK( glyf_offset ) || FT_STREAM_SKIP( 2 ) ) + return error; + + if ( FT_READ_SHORT( info->x_mins[i] ) ) + return error; + } + + return error; + } + + + static FT_Error + reconstruct_hmtx( FT_Stream stream, + FT_UShort num_glyphs, + FT_UShort num_hmetrics, + FT_Short* x_mins, + FT_ULong* checksum, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_ULong* out_offset, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + FT_Byte* sfnt = *sfnt_bytes; + FT_ULong dest_offset = *out_offset; + + FT_Byte hmtx_flags; + FT_Bool has_proportional_lsbs, has_monospace_lsbs; + FT_ULong hmtx_table_size; + FT_Int i; + + FT_UShort* advance_widths = NULL; + FT_Short* lsbs = NULL; + FT_Byte* hmtx_table = NULL; + FT_Byte* dst = NULL; + + + if ( FT_READ_BYTE( hmtx_flags ) ) + goto Fail; + + has_proportional_lsbs = ( hmtx_flags & 1 ) == 0; + has_monospace_lsbs = ( hmtx_flags & 2 ) == 0; + + /* Bits 2-7 are reserved and MUST be zero. */ + if ( ( hmtx_flags & 0xFC ) != 0 ) + goto Fail; + + /* Are you REALLY transformed? */ + if ( has_proportional_lsbs && has_monospace_lsbs ) + goto Fail; + + /* Cannot have a transformed `hmtx' without `glyf'. */ + if ( ( num_hmetrics > num_glyphs ) || + ( num_hmetrics < 1 ) ) + goto Fail; + + /* Must have at least one entry. */ + if ( num_hmetrics < 1 ) + goto Fail; + + if ( FT_QNEW_ARRAY( advance_widths, num_hmetrics ) || + FT_QNEW_ARRAY( lsbs, num_glyphs ) ) + goto Fail; + + /* Read `advanceWidth' stream. Always present. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_UShort advance_width; + + + if ( FT_READ_USHORT( advance_width ) ) + goto Fail; + + advance_widths[i] = advance_width; + } + + /* lsb values for proportional glyphs. */ + for ( i = 0; i < num_hmetrics; i++ ) + { + FT_Short lsb; + + + if ( has_proportional_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* lsb values for monospaced glyphs. */ + for ( i = num_hmetrics; i < num_glyphs; i++ ) + { + FT_Short lsb; + + + if ( has_monospace_lsbs ) + { + if ( FT_READ_SHORT( lsb ) ) + goto Fail; + } + else + lsb = x_mins[i]; + + lsbs[i] = lsb; + } + + /* Build the hmtx table. */ + hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs; + if ( FT_QALLOC( hmtx_table, hmtx_table_size ) ) + goto Fail; + + dst = hmtx_table; + FT_TRACE6(( "hmtx values: \n" )); + for ( i = 0; i < num_glyphs; i++ ) + { + if ( i < num_hmetrics ) + { + WRITE_SHORT( dst, advance_widths[i] ); + FT_TRACE6(( "%d ", advance_widths[i] )); + } + + WRITE_SHORT( dst, lsbs[i] ); + FT_TRACE6(( "%d ", lsbs[i] )); + } + FT_TRACE6(( "\n" )); + + *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size ); + /* Write `hmtx' table to sfnt buffer. */ + if ( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) ) + goto Fail; + + /* Set pointer `sfnt_bytes' to its correct value. */ + *sfnt_bytes = sfnt; + *out_offset = dest_offset; + + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + return error; + + Fail: + FT_FREE( advance_widths ); + FT_FREE( lsbs ); + FT_FREE( hmtx_table ); + + if ( !error ) + error = FT_THROW( Invalid_Table ); + + return error; + } + + + static FT_Error + reconstruct_font( FT_Byte* transformed_buf, + FT_ULong transformed_buf_size, + WOFF2_Table* indices, + WOFF2_Header woff2, + WOFF2_Info info, + FT_Byte** sfnt_bytes, + FT_ULong* sfnt_size, + FT_Memory memory ) + { + /* Memory management of `transformed_buf' is handled by the caller. */ + + FT_Error error = FT_Err_Ok; + FT_Stream stream = NULL; + FT_Byte* buf_cursor = NULL; + FT_Byte table_entry[16]; + + /* We are reallocating memory for `sfnt', so its pointer may change. */ + FT_Byte* sfnt = *sfnt_bytes; + + FT_UShort num_tables = woff2->num_tables; + FT_ULong dest_offset = 12 + num_tables * 16UL; + + FT_ULong checksum = 0; + FT_ULong loca_checksum = 0; + FT_Int nn = 0; + FT_UShort num_hmetrics = 0; + FT_ULong font_checksum = info->header_checksum; + FT_Bool is_glyf_xform = FALSE; + + FT_ULong table_entry_offset = 12; + + + /* A few table checks before reconstruction. */ + /* `glyf' must be present with `loca'. */ + info->glyf_table = find_table( indices, num_tables, TTAG_glyf ); + info->loca_table = find_table( indices, num_tables, TTAG_loca ); + + if ( ( info->glyf_table == NULL ) ^ ( info->loca_table == NULL ) ) + { + FT_ERROR(( "One of `glyf'/`loca' tables missing.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Both `glyf' and `loca' must have same transformation. */ + if ( info->glyf_table != NULL ) + { + if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) != + ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) ) + { + FT_ERROR(( "Transformation mismatch" + " between `glyf' and `loca' table." )); + return FT_THROW( Invalid_Table ); + } + } + + /* Create a stream for the uncompressed buffer. */ + if ( FT_NEW( stream ) ) + goto Fail; + FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); + + FT_ASSERT( FT_STREAM_POS() == 0 ); + + /* Reconstruct/copy tables to output stream. */ + for ( nn = 0; nn < num_tables; nn++ ) + { + WOFF2_TableRec table = *( indices[nn] ); + + + FT_TRACE3(( "Seeking to %lu with table size %lu.\n", + table.src_offset, table.src_length )); + FT_TRACE3(( "Table tag: %c%c%c%c.\n", + (FT_Char)( table.Tag >> 24 ), + (FT_Char)( table.Tag >> 16 ), + (FT_Char)( table.Tag >> 8 ), + (FT_Char)( table.Tag ) )); + + if ( FT_STREAM_SEEK( table.src_offset ) ) + goto Fail; + + if ( table.src_offset + table.src_length > transformed_buf_size ) + goto Fail; + + /* Get stream size for fields of `hmtx' table. */ + if ( table.Tag == TTAG_hhea ) + { + if ( read_num_hmetrics( stream, &num_hmetrics ) ) + goto Fail; + } + + info->num_hmetrics = num_hmetrics; + + checksum = 0; + if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) + { + /* Check whether `head' is at least 12 bytes. */ + if ( table.Tag == TTAG_head ) + { + if ( table.src_length < 12 ) + goto Fail; + + buf_cursor = transformed_buf + table.src_offset + 8; + /* Set checkSumAdjustment = 0 */ + WRITE_ULONG( buf_cursor, 0 ); + } + + table.dst_offset = dest_offset; + + checksum = compute_ULong_sum( transformed_buf + table.src_offset, + table.src_length ); + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + + if ( WRITE_SFNT_BUF( transformed_buf + table.src_offset, + table.src_length ) ) + goto Fail; + } + else + { + FT_TRACE3(( "This table is transformed.\n" )); + + if ( table.Tag == TTAG_glyf ) + { + is_glyf_xform = TRUE; + table.dst_offset = dest_offset; + + if ( reconstruct_glyf( stream, + &checksum, + &loca_checksum, + &sfnt, + sfnt_size, + &dest_offset, + info, + memory ) ) + goto Fail; + + FT_TRACE4(( "Checksum = %09lx.\n", checksum )); + } + + else if ( table.Tag == TTAG_loca ) + checksum = loca_checksum; + + else if ( table.Tag == TTAG_hmtx ) + { + /* If glyf is not transformed and hmtx is, handle separately. */ + if ( !is_glyf_xform ) + { + if ( get_x_mins( stream, indices, num_tables, info, memory ) ) + goto Fail; + } + + table.dst_offset = dest_offset; + + if ( reconstruct_hmtx( stream, + info->num_glyphs, + info->num_hmetrics, + info->x_mins, + &checksum, + &sfnt, + sfnt_size, + &dest_offset, + memory ) ) + goto Fail; + } + else + { + /* Unknown transform. */ + FT_ERROR(( "Unknown table transform.\n" )); + goto Fail; + } + } + + font_checksum += checksum; + + buf_cursor = &table_entry[0]; + WRITE_ULONG( buf_cursor, table.Tag ); + WRITE_ULONG( buf_cursor, checksum ); + WRITE_ULONG( buf_cursor, table.dst_offset ); + WRITE_ULONG( buf_cursor, table.dst_length ); + + WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 ); + + /* Update checksum. */ + font_checksum += compute_ULong_sum( table_entry, 16 ); + + if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) + goto Fail; + + /* Sanity check. */ + if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset ) + { + FT_ERROR(( "Table was partially written.\n" )); + goto Fail; + } + } + + /* Update `head' checkSumAdjustment. */ + info->head_table = find_table( indices, num_tables, TTAG_head ); + if ( !info->head_table ) + { + FT_ERROR(( "`head' table is missing.\n" )); + goto Fail; + } + + if ( info->head_table->dst_length < 12 ) + goto Fail; + + buf_cursor = sfnt + info->head_table->dst_offset + 8; + font_checksum = 0xB1B0AFBA - font_checksum; + + WRITE_ULONG( buf_cursor, font_checksum ); + + FT_TRACE2(( "Final checksum = %09lx.\n", font_checksum )); + + woff2->actual_sfnt_size = dest_offset; + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; + + FT_Stream_Close( stream ); + FT_FREE( stream ); + + return error; + } + + + /* Replace `face->root.stream' with a stream containing the extracted */ + /* SFNT of a WOFF2 font. */ + + FT_LOCAL_DEF( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_instance_index, + FT_Long* num_faces ) + { + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + FT_Int face_index; + + WOFF2_HeaderRec woff2; + WOFF2_InfoRec info = { 0, 0, 0, NULL, NULL, NULL, NULL }; + WOFF2_Table tables = NULL; + WOFF2_Table* indices = NULL; + WOFF2_Table* temp_indices = NULL; + WOFF2_Table last_table; + + FT_Int nn; + FT_ULong j; + FT_ULong flags; + FT_UShort xform_version; + FT_ULong src_offset = 0; + + FT_UInt glyf_index; + FT_UInt loca_index; + FT_UInt32 file_offset; + + FT_Byte* sfnt = NULL; + FT_Stream sfnt_stream = NULL; + FT_ULong sfnt_size; + + FT_Byte* uncompressed_buf = NULL; + + static const FT_Frame_Field woff2_header_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE WOFF2_HeaderRec + + FT_FRAME_START( 48 ), + FT_FRAME_ULONG ( signature ), + FT_FRAME_ULONG ( flavor ), + FT_FRAME_ULONG ( length ), + FT_FRAME_USHORT ( num_tables ), + FT_FRAME_SKIP_BYTES( 2 ), + FT_FRAME_ULONG ( totalSfntSize ), + FT_FRAME_ULONG ( totalCompressedSize ), + FT_FRAME_SKIP_BYTES( 2 * 2 ), + FT_FRAME_ULONG ( metaOffset ), + FT_FRAME_ULONG ( metaLength ), + FT_FRAME_ULONG ( metaOrigLength ), + FT_FRAME_ULONG ( privOffset ), + FT_FRAME_ULONG ( privLength ), + FT_FRAME_END + }; + + + FT_ASSERT( stream == face->root.stream ); + FT_ASSERT( FT_STREAM_POS() == 0 ); + + face_index = FT_ABS( *face_instance_index ) & 0xFFFF; + + /* Read WOFF2 Header. */ + if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) ) + return error; + + FT_TRACE4(( "signature -> 0x%lX\n", woff2.signature )); + FT_TRACE2(( "flavor -> 0x%08lx\n", woff2.flavor )); + FT_TRACE4(( "length -> %lu\n", woff2.length )); + FT_TRACE2(( "num_tables -> %hu\n", woff2.num_tables )); + FT_TRACE4(( "totalSfntSize -> %lu\n", woff2.totalSfntSize )); + FT_TRACE4(( "metaOffset -> %lu\n", woff2.metaOffset )); + FT_TRACE4(( "metaLength -> %lu\n", woff2.metaLength )); + FT_TRACE4(( "privOffset -> %lu\n", woff2.privOffset )); + FT_TRACE4(( "privLength -> %lu\n", woff2.privLength )); + + /* Make sure we don't recurse back here. */ + if ( woff2.flavor == TTAG_wOF2 ) + return FT_THROW( Invalid_Table ); + + /* Miscellaneous checks. */ + if ( woff2.length != stream->size || + woff2.num_tables == 0 || + woff2.num_tables > 0xFFFU || + 48 + woff2.num_tables * 20UL >= woff2.length || + ( woff2.metaOffset == 0 && ( woff2.metaLength != 0 || + woff2.metaOrigLength != 0 ) ) || + ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 ) || + ( woff2.metaOffset >= woff2.length ) || + ( woff2.length - woff2.metaOffset < woff2.metaLength ) || + ( woff2.privOffset == 0 && woff2.privLength != 0 ) || + ( woff2.privOffset >= woff2.length ) || + ( woff2.length - woff2.privOffset < woff2.privLength ) ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 header\n" )); + return FT_THROW( Invalid_Table ); + } + + FT_TRACE2(( "woff2_open_font: WOFF2 Header is valid.\n" )); + + woff2.ttc_fonts = NULL; + + /* Read table directory. */ + if ( FT_QNEW_ARRAY( tables, woff2.num_tables ) || + FT_QNEW_ARRAY( indices, woff2.num_tables ) ) + goto Exit; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag flags transform origLen transformLen offset\n" )); + FT_TRACE2(( " -----------------------------------------------------------\n" )); + /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ + + for ( nn = 0; nn < woff2.num_tables; nn++ ) + { + WOFF2_Table table = tables + nn; + + + if ( FT_READ_BYTE( table->FlagByte ) ) + goto Exit; + + if ( ( table->FlagByte & 0x3f ) == 0x3f ) + { + if ( FT_READ_ULONG( table->Tag ) ) + goto Exit; + } + else + { + table->Tag = woff2_known_tags( table->FlagByte & 0x3f ); + if ( !table->Tag ) + { + FT_ERROR(( "woff2_open_font: Unknown table tag." )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + flags = 0; + xform_version = ( table->FlagByte >> 6 ) & 0x03; + + /* 0 means xform for glyph/loca, non-0 for others. */ + if ( table->Tag == TTAG_glyf || table->Tag == TTAG_loca ) + { + if ( xform_version == 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + } + else if ( xform_version != 0 ) + flags |= WOFF2_FLAGS_TRANSFORM; + + flags |= xform_version; + + if ( READ_BASE128( table->dst_length ) ) + goto Exit; + + table->TransformLength = table->dst_length; + + if ( ( flags & WOFF2_FLAGS_TRANSFORM ) != 0 ) + { + if ( READ_BASE128( table->TransformLength ) ) + goto Exit; + + if ( table->Tag == TTAG_loca && table->TransformLength ) + { + FT_ERROR(( "woff2_open_font: Invalid loca `transformLength'.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( src_offset + table->TransformLength < src_offset ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 table directory.\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + table->flags = flags; + table->src_offset = src_offset; + table->src_length = table->TransformLength; + src_offset += table->TransformLength; + table->dst_offset = 0; + + FT_TRACE2(( " %c%c%c%c %08d %08d %08lu %08lu %08lu\n", + (FT_Char)( table->Tag >> 24 ), + (FT_Char)( table->Tag >> 16 ), + (FT_Char)( table->Tag >> 8 ), + (FT_Char)( table->Tag ), + table->FlagByte & 0x3f, + ( table->FlagByte >> 6 ) & 0x03, + table->dst_length, + table->TransformLength, + table->src_offset )); + + indices[nn] = table; + } + + /* End of last table is uncompressed size. */ + last_table = indices[woff2.num_tables - 1]; + + woff2.uncompressed_size = last_table->src_offset + + last_table->src_length; + if ( woff2.uncompressed_size < last_table->src_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE2(( "Table directory parsed.\n" )); + + /* Check for and read collection directory. */ + woff2.num_fonts = 1; + woff2.header_version = 0; + + if ( woff2.flavor == TTAG_ttcf ) + { + FT_TRACE2(( "Font is a TTC, reading collection directory.\n" )); + + if ( FT_READ_ULONG( woff2.header_version ) ) + goto Exit; + + if ( woff2.header_version != 0x00010000 && + woff2.header_version != 0x00020000 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( READ_255USHORT( woff2.num_fonts ) ) + goto Exit; + + if ( !woff2.num_fonts ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + FT_TRACE4(( "Number of fonts in TTC: %d\n", woff2.num_fonts )); + + /* pre-zero pointers within in case of failure */ + if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) ) + goto Exit; + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + nn; + + + if ( READ_255USHORT( ttc_font->num_tables ) ) + goto Exit; + if ( FT_READ_ULONG( ttc_font->flavor ) ) + goto Exit; + + if ( FT_QNEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE5(( "Number of tables in font %d: %d\n", + nn, ttc_font->num_tables )); + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( " Indices: " )); +#endif + + glyf_index = 0; + loca_index = 0; + + for ( j = 0; j < ttc_font->num_tables; j++ ) + { + FT_UShort table_index; + WOFF2_Table table; + + + if ( READ_255USHORT( table_index ) ) + goto Exit; + + FT_TRACE6(( "%hu ", table_index )); + if ( table_index >= woff2.num_tables ) + { + FT_ERROR(( "woff2_open_font: invalid table index\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + ttc_font->table_indices[j] = table_index; + + table = indices[table_index]; + if ( table->Tag == TTAG_loca ) + loca_index = table_index; + if ( table->Tag == TTAG_glyf ) + glyf_index = table_index; + } + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( ttc_font->num_tables ) + FT_TRACE6(( "\n" )); +#endif + + /* glyf and loca must be consecutive */ + if ( glyf_index > 0 || loca_index > 0 ) + { + if ( glyf_index > loca_index || + loca_index - glyf_index != 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + } + + /* Collection directory reading complete. */ + FT_TRACE2(( "WOFF2 collection directory is valid.\n" )); + } + else + woff2.ttc_fonts = NULL; + + woff2.compressed_offset = FT_STREAM_POS(); + file_offset = ROUND4( woff2.compressed_offset + + woff2.totalCompressedSize ); + + /* Some more checks before we start reading the tables. */ + if ( file_offset > woff2.length ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + if ( woff2.metaOffset ) + { + if ( file_offset != woff2.metaOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.metaOffset + woff2.metaLength ); + } + + if ( woff2.privOffset ) + { + if ( file_offset != woff2.privOffset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + file_offset = ROUND4( woff2.privOffset + woff2.privLength ); + } + + if ( file_offset != ( ROUND4( woff2.length ) ) ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Validate requested face index. */ + *num_faces = woff2.num_fonts; + /* value -(N+1) requests information on index N */ + if ( *face_instance_index < 0 && face_index > 0 ) + face_index--; + + if ( face_index >= woff2.num_fonts ) + { + if ( *face_instance_index >= 0 ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + else + face_index = 0; + } + + /* Only retain tables of the requested face in a TTC. */ + if ( woff2.header_version ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; + + + if ( ttc_font->num_tables == 0 || ttc_font->num_tables > 0xFFFU ) + { + FT_ERROR(( "woff2_open_font: invalid WOFF2 CollectionFontEntry\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* Create a temporary array. */ + if ( FT_QNEW_ARRAY( temp_indices, + ttc_font->num_tables ) ) + goto Exit; + + FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + temp_indices[nn] = indices[ttc_font->table_indices[nn]]; + + /* Resize array to required size. */ + if ( FT_QRENEW_ARRAY( indices, + woff2.num_tables, + ttc_font->num_tables ) ) + goto Exit; + + for ( nn = 0; nn < ttc_font->num_tables; nn++ ) + indices[nn] = temp_indices[nn]; + + FT_FREE( temp_indices ); + + /* Change header values. */ + woff2.flavor = ttc_font->flavor; + woff2.num_tables = ttc_font->num_tables; + } + + /* We need to allocate this much at the minimum. */ + sfnt_size = 12 + woff2.num_tables * 16UL; + /* This is what we normally expect. */ + /* Initially trust `totalSfntSize' and change later as required. */ + if ( woff2.totalSfntSize > sfnt_size ) + { + /* However, adjust the value to something reasonable. */ + + /* Factor 64 is heuristic. */ + if ( ( woff2.totalSfntSize >> 6 ) > woff2.length ) + sfnt_size = woff2.length << 6; + else + sfnt_size = woff2.totalSfntSize; + + if ( sfnt_size >= MAX_SFNT_SIZE ) + sfnt_size = MAX_SFNT_SIZE; + +#ifdef FT_DEBUG_LEVEL_TRACE + if ( sfnt_size != woff2.totalSfntSize ) + FT_TRACE4(( "adjusting estimate of uncompressed font size" + " to %lu bytes\n", + sfnt_size )); +#endif + } + + /* Write sfnt header. */ + if ( FT_QALLOC( sfnt, sfnt_size ) || + FT_NEW( sfnt_stream ) ) + goto Exit; + + { + FT_Byte* sfnt_header = sfnt; + + FT_Int entrySelector = FT_MSB( woff2.num_tables ); + FT_Int searchRange = ( 1 << entrySelector ) * 16; + FT_Int rangeShift = woff2.num_tables * 16 - searchRange; + + + WRITE_ULONG ( sfnt_header, woff2.flavor ); + WRITE_USHORT( sfnt_header, woff2.num_tables ); + WRITE_USHORT( sfnt_header, searchRange ); + WRITE_USHORT( sfnt_header, entrySelector ); + WRITE_USHORT( sfnt_header, rangeShift ); + } + + info.header_checksum = compute_ULong_sum( sfnt, 12 ); + + /* Sort tables by tag. */ + ft_qsort( indices, + woff2.num_tables, + sizeof ( WOFF2_Table ), + compare_tags ); + + /* reject fonts that have multiple tables with the same tag */ + for ( nn = 1; nn < woff2.num_tables; nn++ ) + { + FT_Tag tag = indices[nn]->Tag; + + + if ( tag == indices[nn - 1]->Tag ) + { + FT_ERROR(( "woff2_open_font:" + " multiple tables with tag `%c%c%c%c'.\n", + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + + if ( woff2.uncompressed_size < 1 ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + /* We must not blindly trust `uncompressed_size` since its */ + /* value might be corrupted. If it is too large, reject the */ + /* font. In other words, we don't accept a WOFF2 font that */ + /* expands to something larger than MAX_SFNT_SIZE. If ever */ + /* necessary, this limit can be easily adjusted. */ + if ( woff2.uncompressed_size > MAX_SFNT_SIZE ) + { + FT_ERROR(( "Uncompressed font too large.\n" )); + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + /* Allocate memory for uncompressed table data. */ + if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) || + FT_FRAME_ENTER( woff2.totalCompressedSize ) ) + goto Exit; + + /* Uncompress the stream. */ + error = woff2_decompress( uncompressed_buf, + woff2.uncompressed_size, + stream->cursor, + woff2.totalCompressedSize ); + + FT_FRAME_EXIT(); + + if ( error ) + goto Exit; + + error = reconstruct_font( uncompressed_buf, + woff2.uncompressed_size, + indices, + &woff2, + &info, + &sfnt, + &sfnt_size, + memory ); + + if ( error ) + goto Exit; + + /* Resize `sfnt' to actual size of sfnt stream. */ + if ( woff2.actual_sfnt_size < sfnt_size ) + { + FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n", + sfnt_size, woff2.actual_sfnt_size )); + if ( FT_QREALLOC( sfnt, + (FT_ULong)( sfnt_size ), + (FT_ULong)( woff2.actual_sfnt_size ) ) ) + goto Exit; + } + + /* `reconstruct_font' has done all the work. */ + /* Swap out stream and return. */ + FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.actual_sfnt_size ); + sfnt_stream->memory = stream->memory; + sfnt_stream->close = stream_close; + + FT_Stream_Free( + face->root.stream, + ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); + + face->root.stream = sfnt_stream; + face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; + + /* Set face_index to 0 or -1. */ + if ( *face_instance_index >= 0 ) + *face_instance_index = 0; + else + *face_instance_index = -1; + + FT_TRACE2(( "woff2_open_font: SFNT synthesized.\n" )); + + Exit: + FT_FREE( tables ); + FT_FREE( indices ); + FT_FREE( uncompressed_buf ); + FT_FREE( info.x_mins ); + + if ( woff2.ttc_fonts ) + { + WOFF2_TtcFont ttc_font = woff2.ttc_fonts; + + + for ( nn = 0; nn < woff2.num_fonts; nn++ ) + { + FT_FREE( ttc_font->table_indices ); + ttc_font++; + } + + FT_FREE( woff2.ttc_fonts ); + } + + if ( error ) + { + FT_FREE( sfnt ); + if ( sfnt_stream ) + { + FT_Stream_Close( sfnt_stream ); + FT_FREE( sfnt_stream ); + } + } + + return error; + } + + +#undef READ_255USHORT +#undef READ_BASE128 +#undef ROUND4 +#undef WRITE_USHORT +#undef WRITE_ULONG +#undef WRITE_SHORT +#undef WRITE_SFNT_BUF +#undef WRITE_SFNT_BUF_AT + +#undef N_CONTOUR_STREAM +#undef N_POINTS_STREAM +#undef FLAG_STREAM +#undef GLYPH_STREAM +#undef COMPOSITE_STREAM +#undef BBOX_STREAM +#undef INSTRUCTION_STREAM + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff2_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/sfwoff2.h b/src/thirdparty/freetype2/src/sfnt/sfwoff2.h new file mode 100644 index 000000000..588761d0c --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/sfwoff2.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * + * sfwoff2.h + * + * WOFFF2 format management (specification). + * + * Copyright (C) 2019-2025 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 SFWOFF2_H_ +#define SFWOFF2_H_ + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + /* Leave the first byte open to store `flag_byte'. */ +#define WOFF2_FLAGS_TRANSFORM 1 << 8 + +#define WOFF2_SFNT_HEADER_SIZE 12 +#define WOFF2_SFNT_ENTRY_SIZE 16 + + /* Suggested maximum size for output. */ +#define WOFF2_DEFAULT_MAX_SIZE 30 * 1024 * 1024 + + /* 98% of Google Fonts have no glyph above 5k bytes. */ +#define WOFF2_DEFAULT_GLYPH_BUF 5120 + + /* Composite glyph flags. */ + /* See `CompositeGlyph.java' in `sfntly' for full definitions. */ +#define FLAG_ARG_1_AND_2_ARE_WORDS 1 << 0 +#define FLAG_WE_HAVE_A_SCALE 1 << 3 +#define FLAG_MORE_COMPONENTS 1 << 5 +#define FLAG_WE_HAVE_AN_X_AND_Y_SCALE 1 << 6 +#define FLAG_WE_HAVE_A_TWO_BY_TWO 1 << 7 +#define FLAG_WE_HAVE_INSTRUCTIONS 1 << 8 + + /* Simple glyph flags */ +#define GLYF_ON_CURVE 1 << 0 +#define GLYF_X_SHORT 1 << 1 +#define GLYF_Y_SHORT 1 << 2 +#define GLYF_REPEAT 1 << 3 +#define GLYF_THIS_X_IS_SAME 1 << 4 +#define GLYF_THIS_Y_IS_SAME 1 << 5 +#define GLYF_OVERLAP_SIMPLE 1 << 6 + + /* Other constants */ +#define CONTOUR_OFFSET_END_POINT 10 + + + FT_LOCAL( FT_Error ) + woff2_open_font( FT_Stream stream, + TT_Face face, + FT_Int* face_index, + FT_Long* num_faces ); + +#endif /* FT_CONFIG_OPTION_USE_BROTLI */ + +FT_END_HEADER + +#endif /* SFWOFF2_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttbdf.c b/src/thirdparty/freetype2/src/sfnt/ttbdf.c index 853599fc4..78a33fa30 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttbdf.c +++ b/src/thirdparty/freetype2/src/sfnt/ttbdf.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (body). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,10 +16,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #include "ttbdf.h" #include "sferrors.h" @@ -137,13 +136,14 @@ FT_LOCAL_DEF( FT_Error ) - tt_face_find_bdf_prop( TT_Face face, + tt_face_find_bdf_prop( FT_Face face, /* TT_Face */ const char* property_name, BDF_PropertyRec *aprop ) { - TT_BDF bdf = &face->bdf; - FT_Size size = FT_FACE( face )->size; - FT_Error error = FT_Err_Ok; + TT_Face ttface = (TT_Face)face; + TT_BDF bdf = &ttface->bdf; + FT_Size size = face->size; + FT_Error error = FT_Err_Ok; FT_Byte* p; FT_UInt count; FT_Byte* strike; @@ -154,7 +154,7 @@ if ( bdf->loaded == 0 ) { - error = tt_face_load_bdf_props( face, FT_FACE( face )->stream ); + error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) ); if ( error ) goto Exit; } @@ -249,7 +249,7 @@ #else /* !TT_CONFIG_OPTION_BDF */ /* ANSI C doesn't like empty source files */ - typedef int _tt_bdf_dummy; + typedef int tt_bdf_dummy_; #endif /* !TT_CONFIG_OPTION_BDF */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttbdf.h b/src/thirdparty/freetype2/src/sfnt/ttbdf.h index e4164e61f..abcce2cc6 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttbdf.h +++ b/src/thirdparty/freetype2/src/sfnt/ttbdf.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (specification). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define TTBDF_H_ -#include #include "ttload.h" -#include FT_BDF_H +#include FT_BEGIN_HEADER @@ -35,7 +34,7 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) - tt_face_find_bdf_prop( TT_Face face, + tt_face_find_bdf_prop( FT_Face face, const char* property_name, BDF_PropertyRec *aprop ); diff --git a/src/thirdparty/freetype2/src/sfnt/ttcmap.c b/src/thirdparty/freetype2/src/sfnt/ttcmap.c index 683f3b181..91b023442 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcmap.c +++ b/src/thirdparty/freetype2/src/sfnt/ttcmap.c @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,14 +16,13 @@ */ -#include -#include FT_INTERNAL_DEBUG_H +#include -#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */ +#include "sferrors.h" /* must come before `ftvalid.h' */ -#include FT_INTERNAL_VALIDATE_H -#include FT_INTERNAL_STREAM_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include +#include +#include #include "ttload.h" #include "ttcmap.h" #include "ttpost.h" @@ -60,10 +59,14 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap_init( TT_CMap cmap, - FT_Byte* table ) + tt_cmap_init( FT_CMap cmap, /* TT_CMap */ + void* table_ ) { - cmap->data = table; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->data = table; return FT_Err_Ok; } @@ -129,21 +132,23 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap0_char_index( TT_CMap cmap, + tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; return char_code < 256 ? table[6 + char_code] : 0; } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap0_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 charcode = *pchar_code; FT_UInt32 result = 0; FT_UInt gindex = 0; @@ -166,14 +171,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap0_get_info( TT_CMap cmap, + tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 0; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -454,10 +460,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap2_char_index( TT_CMap cmap, + tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* subheader; @@ -466,7 +473,7 @@ if ( subheader ) { FT_Byte* p = subheader; - FT_UInt idx = (FT_UInt)(char_code & 0xFF); + FT_UInt idx = (FT_UInt)( char_code & 0xFF ); FT_UInt start, count; FT_Int delta; FT_UInt offset; @@ -492,11 +499,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap2_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pcharcode ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt gindex = 0; FT_UInt32 result = 0; FT_UInt32 charcode = *pcharcode + 1; @@ -580,14 +588,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap2_get_info( TT_CMap cmap, + tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 2; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -707,18 +716,20 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_init( TT_CMap4 cmap, - FT_Byte* table ) + tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */ + void* table_ ) { + TT_CMap4 ttcmap = (TT_CMap4)cmap; + FT_Byte* table = (FT_Byte*)table_; FT_Byte* p; - cmap->cmap.data = table; + ttcmap->cmap.data = table; - p = table + 6; - cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; - cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; - cmap->cur_gindex = 0; + p = table + 6; + ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + ttcmap->cur_gindex = 0; return FT_Err_Ok; } @@ -756,7 +767,7 @@ cmap->cur_start == 0xFFFFU && cmap->cur_end == 0xFFFFU ) { - TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; @@ -789,15 +800,12 @@ static void tt_cmap4_next( TT_CMap4 cmap ) { - TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt charcode; - if ( cmap->cur_charcode >= 0xFFFFUL ) - goto Fail; - charcode = (FT_UInt)cmap->cur_charcode + 1; if ( charcode < cmap->cur_start ) @@ -883,7 +891,6 @@ charcode = cmap->cur_start; } - Fail: cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; cmap->cur_gindex = 0; } @@ -917,6 +924,16 @@ length = (FT_UInt)( valid->limit - table ); } + /* it also happens that the `length' field is too small; */ + /* this is easy to correct */ + if ( length < (FT_UInt)( valid->limit - table ) ) + { + if ( valid->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + + length = (FT_UInt)( valid->limit - table ); + } + if ( length < 16 ) FT_INVALID_TOO_SHORT; @@ -1088,32 +1105,26 @@ FT_UInt32* pcharcode, FT_Bool next ) { - TT_Face face = (TT_Face)cmap->cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt i, num_segs; - FT_UInt32 charcode = *pcharcode; + FT_UInt32 charcode = *pcharcode + next; FT_UInt gindex = 0; FT_Byte* p; FT_Byte* q; p = cmap->data + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); - - num_segs = num_segs2 >> 1; + num_segs = TT_PEEK_USHORT( p ) >> 1; if ( !num_segs ) return 0; - if ( next ) - charcode++; - - if ( charcode > 0xFFFFU ) - return 0; + num_segs2 = num_segs << 1; /* linear search */ p = cmap->data + 14; /* ends table */ @@ -1223,37 +1234,30 @@ FT_UInt32* pcharcode, FT_Bool next ) { - TT_Face face = (TT_Face)cmap->cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt max, min, mid, num_segs; - FT_UInt charcode = (FT_UInt)*pcharcode; + FT_UInt charcode = (FT_UInt)*pcharcode + next; FT_UInt gindex = 0; FT_Byte* p; p = cmap->data + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + num_segs = TT_PEEK_USHORT( p ) >> 1; - if ( !num_segs2 ) + if ( !num_segs ) return 0; - num_segs = num_segs2 >> 1; - - /* make compiler happy */ - mid = num_segs; - end = 0xFFFFU; - - if ( next ) - charcode++; + num_segs2 = num_segs << 1; min = 0; max = num_segs; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 14 + mid * 2; @@ -1436,6 +1440,7 @@ break; } } + while ( min < max ); if ( next ) { @@ -1445,12 +1450,8 @@ /* 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 ( charcode > end && ++mid == num_segs ) + return 0; if ( tt_cmap4_set_range( cmap4, mid ) ) { @@ -1465,7 +1466,6 @@ cmap4->cur_gindex = gindex; else { - cmap4->cur_charcode = charcode; tt_cmap4_next( cmap4 ); gindex = cmap4->cur_gindex; } @@ -1480,31 +1480,35 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap4_char_index( TT_CMap cmap, + tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { + TT_CMap ttcmap = (TT_CMap)cmap; + + if ( char_code >= 0x10000UL ) return 0; - if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) - return tt_cmap4_char_map_linear( cmap, &char_code, 0 ); + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 ); else - return tt_cmap4_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap4_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { + TT_CMap ttcmap = (TT_CMap)cmap; 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 ); + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 ); else { TT_CMap4 cmap4 = (TT_CMap4)cmap; @@ -1519,7 +1523,7 @@ *pchar_code = cmap4->cur_charcode; } else - gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 ); } return gindex; @@ -1527,14 +1531,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_get_info( TT_CMap cmap, + tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 4; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -1631,10 +1636,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap6_char_index( TT_CMap cmap, + tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 6; FT_UInt start = TT_NEXT_USHORT( p ); @@ -1652,11 +1658,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap6_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 result = 0; FT_UInt32 char_code = *pchar_code + 1; FT_UInt gindex = 0; @@ -1697,14 +1704,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap6_get_info( TT_CMap cmap, + tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 6; - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + cmap_info->language = TT_PEEK_USHORT( p ); return FT_Err_Ok; } @@ -1891,10 +1899,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap8_char_index( TT_CMap cmap, + tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); @@ -1923,15 +1932,16 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap8_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Face face = cmap->cmap.charmap.face; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); FT_UInt32 result = 0; FT_UInt32 char_code; FT_UInt gindex = 0; - FT_Byte* table = cmap->data; + FT_Byte* table = ttcmap->data; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); FT_UInt32 start, end, start_id; @@ -1991,14 +2001,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap8_get_info( TT_CMap cmap, + tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 8; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2095,10 +2106,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap10_char_index( TT_CMap cmap, + tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); @@ -2121,11 +2133,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap10_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 char_code; FT_UInt gindex = 0; FT_Byte* p = table + 12; @@ -2163,14 +2176,15 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap10_get_info( TT_CMap cmap, + tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 10; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2244,15 +2258,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_init( TT_CMap12 cmap, - FT_Byte* table ) + tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Byte* table = (FT_Byte*)table_; - table += 12; - cmap->num_groups = FT_PEEK_ULONG( table ); - cmap->valid = 0; + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; return FT_Err_Ok; } @@ -2322,23 +2340,21 @@ /* cmap->cur_group should be set up properly by caller */ /* */ static void - tt_cmap12_next( TT_CMap12 cmap ) + tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */ { - FT_Face face = cmap->cmap.cmap.charmap.face; - FT_Byte* p; - FT_ULong start, end, start_id, char_code; - FT_ULong n; - FT_UInt gindex; + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Face face = FT_CMAP_FACE( 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 = ttcmap->cur_charcode + 1; - char_code = cmap->cur_charcode + 1; - - for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) { - p = cmap->cmap.data + 16 + 12 * n; + p = ttcmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_PEEK_ULONG( p ); @@ -2370,16 +2386,16 @@ if ( gindex >= (FT_UInt)face->num_glyphs ) continue; - cmap->cur_charcode = char_code; - cmap->cur_gindex = gindex; - cmap->cur_group = n; + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; return; } } Fail: - cmap->valid = 0; + ttcmap->valid = 0; } @@ -2391,7 +2407,7 @@ 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 char_code = *pchar_code + next; FT_UInt32 start, end, start_id; FT_UInt32 max, min, mid; @@ -2399,23 +2415,11 @@ if ( !num_groups ) return 0; - /* make compiler happy */ - mid = num_groups; - end = 0xFFFFFFFFUL; - - if ( next ) - { - if ( char_code >= 0xFFFFFFFFUL ) - return 0; - - char_code++; - } - min = 0; max = num_groups; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; @@ -2439,22 +2443,19 @@ break; } } + while ( min < max ); if ( next ) { - FT_Face face = cmap->cmap.charmap.face; + FT_Face face = FT_CMAP_FACE( cmap ); 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; - } + if ( char_code > end && ++mid == num_groups ) + return 0; cmap12->valid = 1; cmap12->cur_charcode = char_code; @@ -2465,7 +2466,7 @@ if ( !gindex ) { - tt_cmap12_next( cmap12 ); + tt_cmap12_next( FT_CMAP( cmap12 ) ); if ( cmap12->valid ) gindex = cmap12->cur_gindex; @@ -2481,25 +2482,28 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap12_char_index( TT_CMap cmap, + tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - return tt_cmap12_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap12_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */ FT_UInt32 *pchar_code ) { TT_CMap12 cmap12 = (TT_CMap12)cmap; FT_UInt gindex; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + /* no need to search */ if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) { - tt_cmap12_next( cmap12 ); + tt_cmap12_next( FT_CMAP( cmap12 ) ); if ( cmap12->valid ) { gindex = cmap12->cur_gindex; @@ -2509,21 +2513,22 @@ gindex = 0; } else - gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); return gindex; } FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_get_info( TT_CMap cmap, + tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 12; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2597,15 +2602,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap13_init( TT_CMap13 cmap, - FT_Byte* table ) + tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Byte* table = (FT_Byte*)table_; - table += 12; - cmap->num_groups = FT_PEEK_ULONG( table ); - cmap->valid = 0; + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; return FT_Err_Ok; } @@ -2670,23 +2679,21 @@ /* cmap->cur_group should be set up properly by caller */ /* */ static void - tt_cmap13_next( TT_CMap13 cmap ) + tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */ { - FT_Face face = cmap->cmap.cmap.charmap.face; - FT_Byte* p; - FT_ULong start, end, glyph_id, char_code; - FT_ULong n; - FT_UInt gindex; + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, glyph_id, char_code; + FT_ULong n; + FT_UInt gindex; - if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) - goto Fail; + char_code = ttcmap->cur_charcode + 1; - char_code = cmap->cur_charcode + 1; - - for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) { - p = cmap->cmap.data + 16 + 12 * n; + p = ttcmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); glyph_id = TT_PEEK_ULONG( p ); @@ -2700,17 +2707,16 @@ if ( gindex && gindex < (FT_UInt)face->num_glyphs ) { - cmap->cur_charcode = char_code; - cmap->cur_gindex = gindex; - cmap->cur_group = n; + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; return; } } } - Fail: - cmap->valid = 0; + ttcmap->valid = 0; } @@ -2722,7 +2728,7 @@ 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 char_code = *pchar_code + next; FT_UInt32 start, end; FT_UInt32 max, min, mid; @@ -2730,23 +2736,11 @@ if ( !num_groups ) return 0; - /* make compiler happy */ - mid = num_groups; - end = 0xFFFFFFFFUL; - - if ( next ) - { - if ( char_code >= 0xFFFFFFFFUL ) - return 0; - - char_code++; - } - min = 0; max = num_groups; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; @@ -2765,6 +2759,7 @@ break; } } + while ( min < max ); if ( next ) { @@ -2775,12 +2770,8 @@ /* 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; - } + if ( char_code > end && ++mid == num_groups ) + return 0; cmap13->valid = 1; cmap13->cur_charcode = char_code; @@ -2791,7 +2782,7 @@ if ( !gindex ) { - tt_cmap13_next( cmap13 ); + tt_cmap13_next( FT_CMAP( cmap13 ) ); if ( cmap13->valid ) gindex = cmap13->cur_gindex; @@ -2807,25 +2798,28 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap13_char_index( TT_CMap cmap, + tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - return tt_cmap13_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap13_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */ FT_UInt32 *pchar_code ) { TT_CMap13 cmap13 = (TT_CMap13)cmap; FT_UInt gindex; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + /* no need to search */ if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) { - tt_cmap13_next( cmap13 ); + tt_cmap13_next( FT_CMAP( cmap13 ) ); if ( cmap13->valid ) { gindex = cmap13->cur_gindex; @@ -2835,21 +2829,22 @@ gindex = 0; } else - gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); return gindex; } FT_CALLBACK_DEF( FT_Error ) - tt_cmap13_get_info( TT_CMap cmap, + tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 13; - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + cmap_info->language = TT_PEEK_ULONG( p ); return FT_Err_Ok; } @@ -2960,14 +2955,15 @@ FT_CALLBACK_DEF( void ) - tt_cmap14_done( TT_CMap14 cmap ) + tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */ { - FT_Memory memory = cmap->memory; + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Memory memory = ttcmap->memory; - cmap->max_results = 0; - if ( memory && cmap->results ) - FT_FREE( cmap->results ); + ttcmap->max_results = 0; + if ( memory && ttcmap->results ) + FT_FREE( ttcmap->results ); } @@ -2995,15 +2991,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap14_init( TT_CMap14 cmap, - FT_Byte* table ) + tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Byte* table = (FT_Byte*)table_; - table += 6; - cmap->num_selectors = FT_PEEK_ULONG( table ); - cmap->max_results = 0; - cmap->results = NULL; + + ttcmap->cmap.data = table; + + table += 6; + ttcmap->num_selectors = FT_PEEK_ULONG( table ); + ttcmap->max_results = 0; + ttcmap->results = NULL; return FT_Err_Ok; } @@ -3133,7 +3133,7 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap14_char_index( TT_CMap cmap, + tt_cmap14_char_index( FT_CMap cmap, FT_UInt32 char_code ) { FT_UNUSED( cmap ); @@ -3144,8 +3144,8 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap14_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_next( FT_CMap cmap, FT_UInt32 *pchar_code ) { FT_UNUSED( cmap ); @@ -3157,7 +3157,7 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap14_get_info( TT_CMap cmap, + tt_cmap14_get_info( FT_CharMap cmap, TT_CMapInfo *cmap_info ) { FT_UNUSED( cmap ); @@ -3271,12 +3271,16 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap14_char_var_index( TT_CMap cmap, - TT_CMap ucmap, + tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */ + FT_CMap ucmap, /* TT_CMap */ FT_UInt32 charcode, FT_UInt32 variantSelector ) { - FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap ttucmap = (TT_CMap)ucmap; + + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); FT_ULong defOff; FT_ULong nondefOff; @@ -3287,16 +3291,16 @@ defOff = TT_NEXT_ULONG( p ); nondefOff = TT_PEEK_ULONG( p ); - if ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) { /* This is the default variant of this charcode. GID not stored */ /* here; stored in the normal Unicode charmap instead. */ - return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode ); + return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode ); } if ( nondefOff != 0 ) - return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, + return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, charcode ); return 0; @@ -3304,11 +3308,13 @@ FT_CALLBACK_DEF( FT_Int ) - tt_cmap14_char_var_isdefault( TT_CMap cmap, + tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */ FT_UInt32 charcode, FT_UInt32 variantSelector ) { - FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); FT_ULong defOff; FT_ULong nondefOff; @@ -3319,13 +3325,13 @@ defOff = TT_NEXT_ULONG( p ); nondefOff = TT_NEXT_ULONG( p ); - if ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) return 1; - if ( nondefOff != 0 && - tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, - charcode ) != 0 ) + if ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ) != 0 ) return 0; return -1; @@ -3333,12 +3339,13 @@ FT_CALLBACK_DEF( FT_UInt32* ) - tt_cmap14_variants( TT_CMap cmap, + tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */ FT_Memory memory ) { + TT_CMap ttcmap = (TT_CMap)cmap; TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 count = cmap14->num_selectors; - FT_Byte* p = cmap->data + 10; + FT_Byte* p = ttcmap->data + 10; FT_UInt32* result; FT_UInt32 i; @@ -3359,13 +3366,14 @@ FT_CALLBACK_DEF( FT_UInt32 * ) - tt_cmap14_char_variants( TT_CMap cmap, + tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */ FT_Memory memory, FT_UInt32 charCode ) { - TT_CMap14 cmap14 = (TT_CMap14) cmap; + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 count = cmap14->num_selectors; - FT_Byte* p = cmap->data + 10; + FT_Byte* p = ttcmap->data + 10; FT_UInt32* q; @@ -3379,12 +3387,12 @@ FT_ULong nondefOff = TT_NEXT_ULONG( p ); - if ( ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, - charCode ) ) || - ( nondefOff != 0 && - tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, - charCode ) != 0 ) ) + if ( ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, + charCode ) ) || + ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charCode ) != 0 ) ) { q[0] = varSel; q++; @@ -3480,15 +3488,16 @@ FT_CALLBACK_DEF( FT_UInt32 * ) - tt_cmap14_variant_chars( TT_CMap cmap, + tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */ FT_Memory memory, FT_UInt32 variantSelector ) { - FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6, - variantSelector ); - FT_Int i; - FT_ULong defOff; - FT_ULong nondefOff; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_Int i; + FT_ULong defOff; + FT_ULong nondefOff; if ( !p ) @@ -3501,16 +3510,16 @@ return NULL; if ( defOff == 0 ) - return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, memory ); else if ( nondefOff == 0 ) - return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, memory ); else { /* Both a default and a non-default glyph set? That's probably not */ /* good font design, but the spec allows for it... */ - TT_CMap14 cmap14 = (TT_CMap14) cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 numRanges; FT_UInt32 numMappings; FT_UInt32 duni; @@ -3522,18 +3531,18 @@ FT_UInt32 *ret; - p = cmap->data + nondefOff; - dp = cmap->data + defOff; + p = ttcmap->data + nondefOff; + dp = ttcmap->data + defOff; numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); dcnt = tt_cmap14_def_char_count( dp ); numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); if ( numMappings == 0 ) - return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, memory ); if ( dcnt == 0 ) - return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, memory ); if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) @@ -3655,9 +3664,10 @@ #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_CALLBACK_DEF( const char * ) - tt_get_glyph_name( TT_Face face, + tt_get_glyph_name( void* face_, /* TT_Face */ FT_UInt idx ) { + TT_Face face = (TT_Face)face_; FT_String* PSname = NULL; @@ -3668,12 +3678,13 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap_unicode_init( PS_Unicodes unicodes, - FT_Pointer pointer ) + tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; FT_UNUSED( pointer ); @@ -3684,17 +3695,18 @@ return psnames->unicodes_init( memory, unicodes, face->root.num_glyphs, - (PS_GetGlyphNameFunc)&tt_get_glyph_name, + &tt_get_glyph_name, (PS_FreeGlyphNameFunc)NULL, (FT_Pointer)face ); } FT_CALLBACK_DEF( void ) - tt_cmap_unicode_done( PS_Unicodes unicodes ) + tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ { - FT_Face face = FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); FT_FREE( unicodes->maps ); @@ -3703,23 +3715,25 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap_unicode_char_index( PS_Unicodes unicodes, - FT_UInt32 char_code ) + tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_index( unicodes, char_code ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap_unicode_char_next( PS_Unicodes unicodes, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_next( unicodes, pchar_code ); @@ -3752,6 +3766,7 @@ static const TT_CMap_Class tt_cmap_classes[] = { +#undef TTCMAPCITEM #define TTCMAPCITEM( a ) &a, #include "ttcmapc.h" NULL, @@ -3764,29 +3779,33 @@ 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_Byte* const table = face->cmap_table; + FT_Byte* limit; FT_UInt volatile num_cmaps; - FT_Byte* volatile p = table; + FT_Byte* volatile p = table; FT_Library library = FT_FACE_LIBRARY( face ); FT_UNUSED( library ); - if ( !p || p + 4 > limit ) + if ( !p || face->cmap_size < 4 ) return FT_THROW( Invalid_Table ); - /* only recognize format 0 */ - if ( TT_NEXT_USHORT( p ) != 0 ) - { - FT_ERROR(( "tt_face_build_cmaps:" - " unsupported `cmap' table format = %d\n", - TT_PEEK_USHORT( p - 2 ) )); - return FT_THROW( Invalid_Table ); - } + /* Version 1.8.3 of the OpenType specification contains the following */ + /* (https://learn.microsoft.com/typography/opentype/spec/cmap): */ + /* */ + /* The 'cmap' table version number remains at 0x0000 for fonts that */ + /* make use of the newer subtable formats. */ + /* */ + /* This essentially means that a version format test is useless. */ + + /* ignore format */ + p += 2; num_cmaps = TT_NEXT_USHORT( p ); + FT_TRACE4(( "tt_face_build_cmaps: %u cmaps\n", num_cmaps )); + limit = table + face->cmap_size; for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) { FT_CharMapRec charmap; @@ -3865,13 +3884,14 @@ } - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) tt_get_cmap_info( FT_CharMap charmap, TT_CMapInfo *cmap_info ) { - FT_CMap cmap = (FT_CMap)charmap; + FT_CMap cmap = FT_CMAP( charmap ); TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + if ( clazz->get_cmap_info ) return clazz->get_cmap_info( charmap, cmap_info ); else diff --git a/src/thirdparty/freetype2/src/sfnt/ttcmap.h b/src/thirdparty/freetype2/src/sfnt/ttcmap.h index 36801c939..645e9e37e 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcmap.h +++ b/src/thirdparty/freetype2/src/sfnt/ttcmap.h @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define TTCMAP_H_ -#include -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_INTERNAL_VALIDATE_H -#include FT_SERVICE_TT_CMAP_H +#include +#include +#include FT_BEGIN_HEADER @@ -91,6 +90,11 @@ FT_BEGIN_HEADER }; +#undef TTCMAPCITEM +#define TTCMAPCITEM( a ) FT_CALLBACK_TABLE const TT_CMap_ClassRec a; +#include "ttcmapc.h" + + typedef struct TT_ValidatorRec_ { FT_ValidatorRec validator; diff --git a/src/thirdparty/freetype2/src/sfnt/ttcmapc.h b/src/thirdparty/freetype2/src/sfnt/ttcmapc.h index ace9e69ca..65807bb73 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcmapc.h +++ b/src/thirdparty/freetype2/src/sfnt/ttcmapc.h @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2019 by + * Copyright (C) 2009-2025 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/sfnt/ttcolr.c b/src/thirdparty/freetype2/src/sfnt/ttcolr.c index 6b537d95b..ad9ad6f27 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcolr.c +++ b/src/thirdparty/freetype2/src/sfnt/ttcolr.c @@ -4,8 +4,8 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright (C) 2018-2025 by + * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang . * @@ -27,12 +27,16 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include FT_COLOR_H +#include +#include +#include +#include +#include +#include +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include +#endif #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -40,12 +44,52 @@ /* NOTE: These are the table sizes calculated through the specs. */ -#define BASE_GLYPH_SIZE 6 -#define LAYER_SIZE 4 -#define COLR_HEADER_SIZE 14 +#define BASE_GLYPH_SIZE 6U +#define BASE_GLYPH_PAINT_RECORD_SIZE 6U +#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U +#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U +#define COLOR_STOP_SIZE 6U +#define VAR_IDX_BASE_SIZE 4U +#define LAYER_SIZE 4U +/* https://learn.microsoft.com/typography/opentype/spec/colr#colr-header */ +/* 3 * uint16 + 2 * Offset32 */ +#define COLRV0_HEADER_SIZE 14U +/* COLRV0_HEADER_SIZE + 5 * Offset32 */ +#define COLRV1_HEADER_SIZE 34U - typedef struct BaseGlyphRecord_ +#define ENSURE_READ_BYTES( byte_size ) \ + if ( p < colr->paints_start_v1 || \ + p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \ + return 0 + + + typedef enum FT_PaintFormat_Internal_ + { + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM = 13, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE = 15, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE = 17, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER = 19, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM = 21, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER = 23, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE = 25, + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER = 27, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29, + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31, + + } FT_PaintFormat_Internal; + + + typedef struct BaseGlyphRecord_ { FT_UShort gid; FT_UShort first_layer_index; @@ -54,7 +98,16 @@ } BaseGlyphRecord; - typedef struct Colr_ + typedef struct BaseGlyphV1Record_ + { + FT_UShort gid; + /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */ + FT_ULong paint_offset; + + } BaseGlyphV1Record; + + + typedef struct Colr_ { FT_UShort version; FT_UShort num_base_glyphs; @@ -63,7 +116,29 @@ FT_Byte* base_glyphs; FT_Byte* layers; - /* The memory which backs up the `COLR' table. */ + FT_ULong num_base_glyphs_v1; + /* Points at beginning of BaseGlyphV1List. */ + FT_Byte* base_glyphs_v1; + + FT_ULong num_layers_v1; + FT_Byte* layers_v1; + + FT_Byte* clip_list; + + /* + * Paint tables start at the minimum of the end of the LayerList and the + * end of the BaseGlyphList. Record this location in a field here for + * safety checks when accessing paint tables. + */ + FT_Byte* paints_start_v1; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Item Variation Store for variable 'COLR' v1. */ + GX_ItemVarStoreRec var_store; + GX_DeltaSetIdxMapRec delta_set_idx_map; +#endif + + /* The memory that backs up the `COLR' table. */ void* table; FT_ULong table_size; @@ -89,11 +164,18 @@ FT_Byte* table = NULL; FT_Byte* p = NULL; + /* Needed for reading array lengths in referenced tables. */ + FT_Byte* p1 = NULL; Colr* colr = NULL; FT_ULong base_glyph_offset, layer_offset; + FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1; + FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset; FT_ULong table_size; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong colr_offset_in_stream; +#endif /* `COLR' always needs `CPAL' */ @@ -104,8 +186,12 @@ if ( error ) goto NoColr; - if ( table_size < COLR_HEADER_SIZE ) - goto InvalidTable; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr_offset_in_stream = FT_STREAM_POS(); +#endif + + if ( table_size < COLRV0_HEADER_SIZE ) + goto NoColr; if ( FT_FRAME_EXTRACT( table_size, table ) ) goto NoColr; @@ -116,26 +202,152 @@ goto NoColr; colr->version = FT_NEXT_USHORT( p ); - if ( colr->version != 0 ) + if ( colr->version != 0 && colr->version != 1 ) goto InvalidTable; colr->num_base_glyphs = FT_NEXT_USHORT( p ); base_glyph_offset = FT_NEXT_ULONG( p ); - if ( base_glyph_offset >= table_size ) + if ( table_size <= base_glyph_offset ) goto InvalidTable; - if ( colr->num_base_glyphs * BASE_GLYPH_SIZE > - table_size - base_glyph_offset ) + if ( ( table_size - base_glyph_offset ) / BASE_GLYPH_SIZE + < colr->num_base_glyphs ) goto InvalidTable; layer_offset = FT_NEXT_ULONG( p ); colr->num_layers = FT_NEXT_USHORT( p ); - if ( layer_offset >= table_size ) + if ( table_size <= layer_offset ) goto InvalidTable; - if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) + if ( ( table_size - layer_offset ) / LAYER_SIZE + < colr->num_layers ) goto InvalidTable; + if ( colr->version == 1 ) + { + if ( table_size < COLRV1_HEADER_SIZE ) + goto InvalidTable; + + base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); + + if ( table_size - 4 <= base_glyphs_offset_v1 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); + num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); + + if ( ( table_size - base_glyphs_offset_v1 ) / BASE_GLYPH_PAINT_RECORD_SIZE + < num_base_glyphs_v1 ) + goto InvalidTable; + + colr->num_base_glyphs_v1 = num_base_glyphs_v1; + colr->base_glyphs_v1 = p1; + + layer_offset_v1 = FT_NEXT_ULONG( p ); + + if ( table_size <= layer_offset_v1 ) + goto InvalidTable; + + if ( layer_offset_v1 ) + { + if ( table_size - 4 <= layer_offset_v1 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + layer_offset_v1 ); + num_layers_v1 = FT_PEEK_ULONG( p1 ); + + if ( ( table_size - layer_offset_v1 ) / LAYER_V1_LIST_PAINT_OFFSET_SIZE + < num_layers_v1 ) + goto InvalidTable; + + colr->num_layers_v1 = num_layers_v1; + colr->layers_v1 = p1; + + colr->paints_start_v1 = + FT_MIN( colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE, + colr->layers_v1 + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ); + } + else + { + colr->num_layers_v1 = 0; + colr->layers_v1 = 0; + colr->paints_start_v1 = + colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE; + } + + clip_list_offset = FT_NEXT_ULONG( p ); + + if ( table_size <= clip_list_offset ) + goto InvalidTable; + + if ( clip_list_offset ) + colr->clip_list = (FT_Byte*)( table + clip_list_offset ); + else + colr->clip_list = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr->var_store.dataCount = 0; + colr->var_store.varData = NULL; + colr->var_store.axisCount = 0; + colr->var_store.regionCount = 0; + colr->var_store.varRegionList = 0; + + colr->delta_set_idx_map.mapCount = 0; + colr->delta_set_idx_map.outerIndex = NULL; + colr->delta_set_idx_map.innerIndex = NULL; + + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) + { + FT_ULong var_idx_map_offset, var_store_offset; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + var_idx_map_offset = FT_NEXT_ULONG( p ); + + if ( var_idx_map_offset >= table_size ) + goto InvalidTable; + + var_store_offset = FT_NEXT_ULONG( p ); + if ( table_size <= var_store_offset ) + goto InvalidTable; + + if ( var_store_offset ) + { + /* If variation info has not been initialized yet, try doing so, */ + /* otherwise loading the variation store will fail as it */ + /* requires access to `blend` for checking the number of axes. */ + if ( !face->blend ) + if ( mm->get_mm_var( FT_FACE( face ), NULL ) ) + goto InvalidTable; + + /* Try loading `VarIdxMap` and `VarStore`. */ + error = mm->load_item_var_store( + FT_FACE( face ), + colr_offset_in_stream + var_store_offset, + &colr->var_store ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + + if ( colr->var_store.axisCount && var_idx_map_offset ) + { + error = mm->load_delta_set_idx_map( + FT_FACE( face ), + colr_offset_in_stream + var_idx_map_offset, + &colr->delta_set_idx_map, + &colr->var_store, + table_size ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + } + colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); colr->layers = (FT_Byte*)( table + layer_offset ); colr->table = table; @@ -146,6 +358,18 @@ return FT_Err_Ok; InvalidTable: +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + error = FT_THROW( Invalid_Table ); NoColr: @@ -167,6 +391,17 @@ if ( colr ) { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif FT_FRAME_RELEASE( colr->table ); FT_FREE( colr ); } @@ -175,17 +410,17 @@ static FT_Bool find_base_glyph_record( FT_Byte* base_glyph_begin, - FT_Int num_base_glyph, + FT_UInt num_base_glyph, FT_UInt glyph_id, BaseGlyphRecord* record ) { - FT_Int min = 0; - FT_Int max = num_base_glyph - 1; + FT_UInt min = 0; + FT_UInt max = num_base_glyph; - while ( min <= max ) + while ( min < max ) { - FT_Int mid = min + ( max - min ) / 2; + FT_UInt mid = min + ( max - min ) / 2; FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE; FT_UShort gid = FT_NEXT_USHORT( p ); @@ -194,7 +429,7 @@ if ( gid < glyph_id ) min = mid + 1; else if (gid > glyph_id ) - max = mid - 1; + max = mid; else { record->gid = gid; @@ -249,7 +484,9 @@ iterator->p = colr->layers + offset; } - if ( iterator->layer >= iterator->num_layers ) + if ( iterator->layer >= iterator->num_layers || + iterator->p < colr->layers || + iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) ) return 0; *aglyph_index = FT_NEXT_USHORT( iterator->p ); @@ -266,6 +503,1241 @@ } + static FT_Bool + read_color_line( Colr* colr, + FT_Byte* color_line_p, + FT_ColorLine* colorline, + FT_Bool read_variable ) + { + FT_Byte* p = color_line_p; + FT_PaintExtend paint_extend; + + + ENSURE_READ_BYTES( 3 ); + + paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p ); + if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT ) + return 0; + + colorline->extend = paint_extend; + + colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p ); + colorline->color_stop_iterator.p = p; + colorline->color_stop_iterator.current_color_stop = 0; + colorline->color_stop_iterator.read_variable = read_variable; + + return 1; + } + + + /* + * Read a paint offset for `FT_Paint*` objects that have them and check + * whether it is within reasonable limits within the font and the COLR + * table. + * + * Return 1 on success, 0 on failure. + */ + static FT_Bool + get_child_table_pointer ( Colr* colr, + FT_Byte* paint_base, + FT_Byte** p, + FT_Byte** child_table_pointer ) + { + FT_UInt32 paint_offset; + FT_Byte* child_table_p; + + + if ( !child_table_pointer ) + return 0; + + if ( *p < colr->paints_start_v1 || + *p > (FT_Byte*)colr->table + colr->table_size - 1 - 3 ) + return 0; + + paint_offset = FT_NEXT_UOFF3( *p ); + if ( !paint_offset ) + return 0; + + child_table_p = (FT_Byte*)( paint_base + paint_offset ); + + if ( child_table_p < colr->paints_start_v1 || + child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *child_table_pointer = child_table_p; + return 1; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + static FT_Bool + get_deltas_for_var_index_base ( TT_Face face, + Colr* colr, + FT_ULong var_index_base, + FT_UInt num_deltas, + FT_ItemVarDelta* deltas ) + { + FT_UInt outer_index = 0; + FT_UInt inner_index = 0; + FT_ULong loop_var_index = var_index_base; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt i = 0; + + + if ( var_index_base == 0xFFFFFFFF ) + { + for ( i = 0; i < num_deltas; ++i ) + deltas[i] = 0; + return 1; + } + + for ( i = 0; i < num_deltas; ++i ) + { + loop_var_index = var_index_base + i; + + if ( colr->delta_set_idx_map.innerIndex ) + { + if ( loop_var_index >= colr->delta_set_idx_map.mapCount ) + loop_var_index = colr->delta_set_idx_map.mapCount - 1; + + outer_index = colr->delta_set_idx_map.outerIndex[loop_var_index]; + inner_index = colr->delta_set_idx_map.innerIndex[loop_var_index]; + } + else + { + outer_index = 0; + inner_index = loop_var_index; + } + + deltas[i] = mm->get_item_delta( FT_FACE( face ), &colr->var_store, + outer_index, inner_index ); + } + + return 1; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static FT_Bool + read_paint( TT_Face face, + Colr* colr, + FT_Byte* p, + FT_COLR_Paint* apaint ) + { + FT_Byte* paint_base = p; + FT_Byte* child_table_p = NULL; + FT_Bool do_read_var = FALSE; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong var_index_base = 0; + /* Longest varIndexBase offset is 5 in the spec. */ + FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 }; +#else + FT_UNUSED( face ); +#endif + + + if ( !p || !colr || !colr->table ) + return 0; + + /* The last byte of the 'COLR' table is at 'size-1'; subtract 1 of */ + /* that to account for the expected format byte we are going to read. */ + if ( p < colr->paints_start_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 2 ) + return 0; + + apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); + + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) + { + /* Initialize layer iterator/ */ + FT_Byte num_layers; + FT_UInt32 first_layer_index; + + + ENSURE_READ_BYTES( 5 ); + num_layers = FT_NEXT_BYTE( p ); + if ( num_layers > colr->num_layers_v1 ) + return 0; + + first_layer_index = FT_NEXT_ULONG( p ); + if ( first_layer_index + num_layers > colr->num_layers_v1 ) + return 0; + + apaint->u.colr_layers.layer_iterator.num_layers = num_layers; + apaint->u.colr_layers.layer_iterator.layer = 0; + /* TODO: Check whether pointer is outside colr? */ + apaint->u.colr_layers.layer_iterator.p = + colr->layers_v1 + + LAYER_V1_LIST_NUM_LAYERS_SIZE + + LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); + apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SOLID; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) + { + ENSURE_READ_BYTES(2); + apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + /* + * Grouped below here are all paint formats that have an offset to a + * child paint table as the first entry (for example, a color line or a + * child paint table). Retrieve that and determine whether that paint + * offset is valid first. + */ + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.linear_gradient.colorline, + do_read_var ) ) + return 0; + + /* + * In order to support variations expose these as FT_Fixed 16.16 + * values so that we can support fractional values after + * interpolation. + */ + ENSURE_READ_BYTES( 12 ); + apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.linear_gradient.p0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.linear_gradient.p0.y += INT_TO_FIXED( item_deltas[1] ); + apaint->u.linear_gradient.p1.x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.linear_gradient.p1.y += INT_TO_FIXED( item_deltas[3] ); + apaint->u.linear_gradient.p2.x += INT_TO_FIXED( item_deltas[4] ); + apaint->u.linear_gradient.p2.y += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) ) + { + FT_Pos tmp; + + + if ( !read_color_line( colr, + child_table_p, + &apaint->u.radial_gradient.colorline, + do_read_var ) ) + return 0; + + + /* In the OpenType specification, `r0` and `r1` are defined as */ + /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ + /* format we convert to `FWORD` and replace negative values with */ + /* (32bit) `FT_INT_MAX`. */ + + ENSURE_READ_BYTES( 12 ); + + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp; + + apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.radial_gradient.c0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.radial_gradient.c0.y += INT_TO_FIXED( item_deltas[1] ); + + // TODO: Anything to be done about UFWORD deltas here? + apaint->u.radial_gradient.r0 += INT_TO_FIXED( item_deltas[2] ); + + apaint->u.radial_gradient.c1.x += INT_TO_FIXED( item_deltas[3] ); + apaint->u.radial_gradient.c1.y += INT_TO_FIXED( item_deltas[4] ); + + apaint->u.radial_gradient.r1 += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.sweep_gradient.colorline, + do_read_var) ) + return 0; + + ENSURE_READ_BYTES( 8 ); + + apaint->u.sweep_gradient.center.x = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.center.y = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + apaint->u.sweep_gradient.start_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.end_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + // TODO: Handle overflow? + apaint->u.sweep_gradient.center.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.sweep_gradient.center.y += INT_TO_FIXED( item_deltas[1] ); + + apaint->u.sweep_gradient.start_angle += + F2DOT14_TO_FIXED( item_deltas[2] ); + apaint->u.sweep_gradient.end_angle += + F2DOT14_TO_FIXED( item_deltas[3] ); + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT; + + return 1; + } + + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.glyph.paint.p = child_table_p; + apaint->u.glyph.paint.insert_root_transform = 0; + apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + apaint->u.transform.paint.p = child_table_p; + apaint->u.transform.paint.insert_root_transform = 0; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + p = child_table_p; + + /* + * The following matrix coefficients are encoded as + * OpenType 16.16 fixed-point values. + */ + ENSURE_READ_BYTES( 24 ); + apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.dy = FT_NEXT_LONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.transform.affine.xx += (FT_Fixed)item_deltas[0]; + apaint->u.transform.affine.yx += (FT_Fixed)item_deltas[1]; + apaint->u.transform.affine.xy += (FT_Fixed)item_deltas[2]; + apaint->u.transform.affine.yy += (FT_Fixed)item_deltas[3]; + apaint->u.transform.affine.dx += (FT_Fixed)item_deltas[4]; + apaint->u.transform.affine.dy += (FT_Fixed)item_deltas[5]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + apaint->u.translate.paint.p = child_table_p; + apaint->u.translate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.translate.dx += INT_TO_FIXED( item_deltas[0] ); + apaint->u.translate.dy += INT_TO_FIXED( item_deltas[1] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSLATE; + + return 1; + } + + else if ( apaint->format >= FT_COLR_PAINTFORMAT_SCALE && + (FT_PaintFormat_Internal)apaint->format <= + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.paint.p = child_table_p; + apaint->u.scale.paint.insert_root_transform = 0; + + /* All scale paints get at least one scale value. */ + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + /* Non-uniform ones read an extra y value. */ + if ( apaint->format == FT_COLR_PAINTFORMAT_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + apaint->u.scale.scale_y = apaint->u.scale.scale_x; + + /* Scale paints that have a center read center coordinates, */ + /* otherwise the center is (0,0). */ + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + } + else + { + apaint->u.scale.center_x = 0; + apaint->u.scale.center_y = 0; + } + + /* Base values set, now handle variations. */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[3] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 3, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } +#endif + + /* FT 'COLR' v1 API output format always returns fully defined */ + /* structs; we thus set the format to the public API value. */ + apaint->format = FT_COLR_PAINTFORMAT_SCALE; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + apaint->u.rotate.paint.p = child_table_p; + apaint->u.rotate.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 2 ); + apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.rotate.center_x = 0; + apaint->u.rotate.center_y = 0; + } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + FT_UInt num_deltas = 0; + + + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + num_deltas = 3; + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ) + num_deltas = 1; + + if ( num_deltas > 0 ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, + num_deltas, item_deltas ) ) + return 0; + + apaint->u.rotate.angle += F2DOT14_TO_FIXED( item_deltas[0] ); + + if ( num_deltas == 3 ) + { + apaint->u.rotate.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.rotate.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_ROTATE; + + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + apaint->u.skew.paint.p = child_table_p; + apaint->u.skew.paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.skew.center_x = 0; + apaint->u.skew.center_y = 0; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.skew.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.skew.center_y += INT_TO_FIXED( item_deltas[3] ); + } + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SKEW; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE ) + { + FT_UInt composite_mode; + + + apaint->u.composite.source_paint.p = child_table_p; + apaint->u.composite.source_paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 1 ); + composite_mode = FT_NEXT_BYTE( p ); + if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) + return 0; + + apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + apaint->u.composite.backdrop_paint.p = + child_table_p; + apaint->u.composite.backdrop_paint.insert_root_transform = + 0; + + return 1; + } + + return 0; + } + + + static FT_Bool + find_base_glyph_v1_record( FT_Byte * base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphV1Record *record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UShort gid; + + /* + * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; + * skip `numBaseGlyphV1Records` by adding 4 to start binary search + * in the array of `BaseGlyphV1Record`. + */ + FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; + + gid = FT_NEXT_USHORT( p ); + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->paint_offset = FT_NEXT_ULONG ( p ); + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* opaque_paint ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphV1Record base_glyph_v1_record; + FT_Byte* p; + + if ( !colr || !colr->table ) + return 0; + + if ( colr->version < 1 || !colr->num_base_glyphs_v1 || + !colr->base_glyphs_v1 ) + return 0; + + if ( opaque_paint->p ) + return 0; + + if ( !find_base_glyph_v1_record( colr->base_glyphs_v1, + colr->num_base_glyphs_v1, + base_glyph, + &base_glyph_v1_record ) ) + return 0; + + if ( !base_glyph_v1_record.paint_offset || + base_glyph_v1_record.paint_offset > colr->table_size ) + return 0; + + p = (FT_Byte*)( colr->base_glyphs_v1 + + base_glyph_v1_record.paint_offset ); + if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p; + + if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM ) + opaque_paint->insert_root_transform = 1; + else + opaque_paint->insert_root_transform = 0; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + Colr* colr; + + FT_Byte *p, *p1, *clip_base, *limit; + + FT_Byte clip_list_format; + FT_ULong num_clip_boxes, i; + FT_UShort gid_start, gid_end; + FT_UInt32 clip_box_offset; + FT_Byte format; + + const FT_Byte num_corners = 4; + FT_Vector corners[4]; + FT_Byte j; + FT_BBox font_clip_box; + + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + if ( !colr->clip_list ) + return 0; + + p = colr->clip_list; + + /* Limit points to the first byte after the end of the color table. */ + /* Thus, in subsequent limit checks below we need to check whether the */ + /* read pointer is strictly greater than a position offset by certain */ + /* field sizes to the left of that position. */ + limit = (FT_Byte*)colr->table + colr->table_size; + + /* Check whether we can extract one `uint8` and one `uint32`. */ + if ( p > limit - ( 1 + 4 ) ) + return 0; + + clip_base = p; + clip_list_format = FT_NEXT_BYTE ( p ); + + /* Format byte used here to be able to upgrade ClipList for >16bit */ + /* glyph ids; for now we can expect it to be 1. */ + if ( !( clip_list_format == 1 ) ) + return 0; + + num_clip_boxes = FT_NEXT_ULONG( p ); + + /* Check whether we can extract two `uint16` and one `Offset24`, */ + /* `num_clip_boxes` times. */ + if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes || + p > limit - ( 2 + 2 + 3 ) * num_clip_boxes ) + return 0; + + for ( i = 0; i < num_clip_boxes; ++i ) + { + gid_start = FT_NEXT_USHORT( p ); + gid_end = FT_NEXT_USHORT( p ); + clip_box_offset = FT_NEXT_UOFF3( p ); + + if ( base_glyph >= gid_start && base_glyph <= gid_end ) + { + p1 = (FT_Byte*)( clip_base + clip_box_offset ); + + /* Check whether we can extract one `uint8`. */ + if ( p1 > limit - 1 ) + return 0; + + format = FT_NEXT_BYTE( p1 ); + + if ( format > 2 ) + return 0; + + /* Check whether we can extract four `FWORD`. */ + if ( p1 > limit - ( 2 + 2 + 2 + 2 ) ) + return 0; + + /* `face->root.size->metrics.x_scale` and `y_scale` are factors */ + /* that scale a font unit value in integers to a 26.6 fixed value */ + /* according to the requested size, see for example */ + /* `ft_recompute_scaled_metrics`. */ + font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.x_scale ); + font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ), + face->root.size->metrics.y_scale ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( format == 2 ) + { + FT_ULong var_index_base = 0; + /* varIndexBase offset for clipbox is 3 at most. */ + FT_ItemVarDelta item_deltas[4] = { 0, 0, 0, 0 }; + + + /* Check whether we can extract a 32-bit varIndexBase now. */ + if ( p1 > limit - 4 ) + return 0; + + var_index_base = FT_NEXT_ULONG( p1 ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + font_clip_box.xMin += + FT_MulFix( item_deltas[0], face->root.size->metrics.x_scale ); + font_clip_box.yMin += + FT_MulFix( item_deltas[1], face->root.size->metrics.y_scale ); + font_clip_box.xMax += + FT_MulFix( item_deltas[2], face->root.size->metrics.x_scale ); + font_clip_box.yMax += + FT_MulFix( item_deltas[3], face->root.size->metrics.y_scale ); + } +#endif + + /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */ + /* them. If we we would only transform two corner points and */ + /* span a rectangle based on those, the rectangle may become too */ + /* small to cover the glyph. */ + corners[0].x = font_clip_box.xMin; + corners[1].x = font_clip_box.xMin; + corners[2].x = font_clip_box.xMax; + corners[3].x = font_clip_box.xMax; + + corners[0].y = font_clip_box.yMin; + corners[1].y = font_clip_box.yMax; + corners[2].y = font_clip_box.yMax; + corners[3].y = font_clip_box.yMin; + + for ( j = 0; j < num_corners; ++j ) + { + if ( face->root.internal->transform_flags & 1 ) + FT_Vector_Transform( &corners[j], + &face->root.internal->transform_matrix ); + + if ( face->root.internal->transform_flags & 2 ) + { + corners[j].x += face->root.internal->transform_delta.x; + corners[j].y += face->root.internal->transform_delta.y; + } + } + + clip_box->bottom_left = corners[0]; + clip_box->top_left = corners[1]; + clip_box->top_right = corners[2]; + clip_box->bottom_right = corners[3]; + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* opaque_paint ) + { + FT_Byte* p = NULL; + FT_Byte* p_first_layer = NULL; + FT_Byte* p_paint = NULL; + FT_UInt32 paint_offset; + + Colr* colr; + + + if ( iterator->layer == iterator->num_layers ) + return 0; + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + /* + * We have an iterator pointing at a paint offset as part of the + * `paintOffset` array in `LayerV1List`. + */ + p = iterator->p; + + /* + * Do a cursor sanity check of the iterator. Counting backwards from + * where it stands, we need to end up at a position after the beginning + * of the `LayerV1List` table and not after the end of the + * `LayerV1List`. + */ + p_first_layer = p - + iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE - + LAYER_V1_LIST_NUM_LAYERS_SIZE; + if ( p_first_layer < (FT_Byte*)colr->layers_v1 ) + return 0; + if ( p_first_layer >= (FT_Byte*)( + colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) ) + return 0; + + /* + * Before reading, ensure that `p` is within 'COLR' v1 and we can read a + * 4-byte ULONG. + */ + if ( p < colr->layers_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 4 ) + return 0; + + paint_offset = + FT_NEXT_ULONG( p ); + opaque_paint->insert_root_transform = + 0; + + p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset ); + + if ( p_paint < colr->paints_start_v1 || + p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p_paint; + + iterator->p = p; + + iterator->layer++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator *iterator ) + { + Colr* colr = (Colr*)face->colr; + + FT_Byte* p; + FT_ULong var_index_base; + FT_Byte* last_entry_p = NULL; + FT_UInt entry_size = COLOR_STOP_SIZE; + + + if ( !colr || !colr->table || !iterator ) + return 0; + + if ( iterator->current_color_stop >= iterator->num_color_stops ) + return 0; + + if ( iterator->read_variable ) + entry_size += VAR_IDX_BASE_SIZE; + + /* Calculate the start pointer for the last to-be-read (Var)ColorStop */ + /* and check whether we can read a full (Var)ColorStop at that */ + /* position by comparing it to the position that is the size of one */ + /* (Var)ColorStop before the end of the 'COLR' table. */ + last_entry_p = + iterator->p + ( iterator->num_color_stops - 1 - + iterator->current_color_stop ) * entry_size; + if ( iterator->p < colr->paints_start_v1 || + last_entry_p > (FT_Byte*)colr->table + + colr->table_size - entry_size ) + return 0; + + /* Iterator points at first `ColorStop` of `ColorLine`. */ + p = iterator->p; + + color_stop->stop_offset = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + color_stop->color.palette_index = FT_NEXT_USHORT( p ); + + color_stop->color.alpha = FT_NEXT_SHORT( p ); + + if ( iterator->read_variable ) + { + /* Pointer p needs to be advanced independently of whether we intend */ + /* to take variable deltas into account or not. Otherwise iteration */ + /* would fail due to wrong offsets. */ + var_index_base = FT_NEXT_ULONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Int item_deltas[2]; + + + if ( !get_deltas_for_var_index_base( face, colr, + var_index_base, + 2, + item_deltas ) ) + return 0; + + color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] ); + color_stop->color.alpha += (FT_F2Dot14)item_deltas[1]; + } +#else + FT_UNUSED( var_index_base ); +#endif + } + + iterator->p = p; + iterator->current_color_stop++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + Colr* colr = (Colr*)face->colr; + FT_OpaquePaint next_paint; + FT_Matrix ft_root_scale; + + if ( !colr || !colr->base_glyphs_v1 || !colr->table ) + return 0; + + if ( opaque_paint.insert_root_transform ) + { + /* 'COLR' v1 glyph information is returned in unscaled coordinates, + * i.e., `FT_Size` is not applied or multiplied into the values. When + * client applications draw color glyphs, they can request to include + * a top-level transform, which includes the active `x_scale` and + * `y_scale` information for scaling the glyph, as well the additional + * transform and translate configured through `FT_Set_Transform`. + * This allows client applications to apply this top-level transform + * to the graphics context first and only once, then have gradient and + * contour scaling applied correctly when performing the additional + * drawing operations for subsequenct paints. Prepare this initial + * transform here. + */ + paint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + next_paint.p = opaque_paint.p; + next_paint.insert_root_transform = 0; + paint->u.transform.paint = next_paint; + + /* `x_scale` and `y_scale` are in 26.6 format, representing the scale + * factor to get from font units to requested size. However, expected + * return values are in 16.16, so we shift accordingly with rounding. + */ + ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6; + ft_root_scale.xy = 0; + ft_root_scale.yx = 0; + ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6; + + if ( face->root.internal->transform_flags & 1 ) + FT_Matrix_Multiply( &face->root.internal->transform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.xx = ft_root_scale.xx; + paint->u.transform.affine.xy = ft_root_scale.xy; + paint->u.transform.affine.yx = ft_root_scale.yx; + paint->u.transform.affine.yy = ft_root_scale.yy; + + /* The translation is specified in 26.6 format and, according to the + * documentation of `FT_Set_Translate`, is performed on the character + * size given in the last call to `FT_Set_Char_Size`. The + * 'PaintTransform' paint table's `FT_Affine23` format expects + * values in 16.16 format, thus we need to shift by 10 bits. + */ + if ( face->root.internal->transform_flags & 2 ) + { + paint->u.transform.affine.dx = + face->root.internal->transform_delta.x * ( 1 << 10 ); + paint->u.transform.affine.dy = + face->root.internal->transform_delta.y * ( 1 << 10 ); + } + else + { + paint->u.transform.affine.dx = 0; + paint->u.transform.affine.dy = 0; + } + + return 1; + } + + return read_paint( face, colr, opaque_paint.p, paint ); + } + + FT_LOCAL_DEF( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, @@ -444,7 +1916,7 @@ #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_colr_dummy; + typedef int tt_colr_dummy_; #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttcolr.h b/src/thirdparty/freetype2/src/sfnt/ttcolr.h index 817489a85..3913acc74 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcolr.h +++ b/src/thirdparty/freetype2/src/sfnt/ttcolr.h @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -22,7 +22,6 @@ #define __TTCOLR_H__ -#include #include "ttload.h" @@ -43,6 +42,32 @@ FT_BEGIN_HEADER FT_UInt *acolor_index, FT_LayerIterator* iterator ); + FT_LOCAL( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + FT_LOCAL( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, diff --git a/src/thirdparty/freetype2/src/sfnt/ttcpal.c b/src/thirdparty/freetype2/src/sfnt/ttcpal.c index 3482169a8..6d1208f6a 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcpal.c +++ b/src/thirdparty/freetype2/src/sfnt/ttcpal.c @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -27,11 +27,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include FT_COLOR_H +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -40,8 +39,8 @@ /* NOTE: These are the table sizes calculated through the specs. */ -#define CPAL_V0_HEADER_BASE_SIZE 12 -#define COLOR_SIZE 4 +#define CPAL_V0_HEADER_BASE_SIZE 12U +#define COLOR_SIZE 4U /* all data from `CPAL' not covered in FT_Palette_Data */ @@ -140,7 +139,7 @@ 3U * 4 > table_size ) goto InvalidTable; - p += face->palette_data.num_palettes * 2; + p += face->palette_data.num_palettes * 2U; type_offset = FT_NEXT_ULONG( p ); label_offset = FT_NEXT_ULONG( p ); @@ -150,7 +149,7 @@ { if ( type_offset >= table_size ) goto InvalidTable; - if ( face->palette_data.num_palettes * 2 > + if ( face->palette_data.num_palettes * 2U > table_size - type_offset ) goto InvalidTable; @@ -171,7 +170,7 @@ { if ( label_offset >= table_size ) goto InvalidTable; - if ( face->palette_data.num_palettes * 2 > + if ( face->palette_data.num_palettes * 2U > table_size - label_offset ) goto InvalidTable; @@ -192,7 +191,7 @@ { if ( entry_label_offset >= table_size ) goto InvalidTable; - if ( face->palette_data.num_palette_entries * 2 > + if ( face->palette_data.num_palette_entries * 2U > table_size - entry_label_offset ) goto InvalidTable; @@ -304,7 +303,7 @@ #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_cpal_dummy; + typedef int tt_cpal_dummy_; #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttcpal.h b/src/thirdparty/freetype2/src/sfnt/ttcpal.h index d1b244f3e..a0b4c9d92 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttcpal.h +++ b/src/thirdparty/freetype2/src/sfnt/ttcpal.h @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2019 by + * Copyright (C) 2018-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -22,7 +22,6 @@ #define __TTCPAL_H__ -#include #include "ttload.h" diff --git a/src/thirdparty/freetype2/src/sfnt/ttgpos.c b/src/thirdparty/freetype2/src/sfnt/ttgpos.c new file mode 100644 index 000000000..4ff54933f --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/ttgpos.c @@ -0,0 +1,982 @@ +/**************************************************************************** + * + * ttgpos.c + * + * Routines to parse and access the 'GPOS' table for simple kerning (body). + * + * Copyright (C) 2025 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 +#include + +#include +#include + +#include "ttgpos.h" + + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + + + /************************************************************************** + * + * 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 ttgpos + + + /*********************************/ + /******** ********/ + /******** GPOS validation ********/ + /******** ********/ + /*********************************/ + + static FT_Bool + tt_face_validate_coverage( FT_Byte* table, + FT_Byte* table_limit, + FT_UInt max_num_coverage_indices ) + { + FT_UInt format; + + FT_Byte* p = table; + FT_Byte* limit; + + FT_Long last_id = -1; + + + if ( table_limit < p + 4 ) + return FALSE; + + format = FT_NEXT_USHORT( p ); + if ( format == 1 ) + { + FT_UInt glyphCount = FT_NEXT_USHORT( p ); + + + if ( glyphCount > max_num_coverage_indices ) + return FALSE; + + limit = p + glyphCount * 2; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt id = FT_NEXT_USHORT( p ); + + + if ( last_id >= id ) + return FALSE; + last_id = id; + } + } + else if ( format == 2 ) + { + FT_UInt rangeCount = FT_NEXT_USHORT( p ); + + + limit = p + rangeCount * 6; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt startGlyphID = FT_NEXT_USHORT( p ); + FT_UInt endGlyphID = FT_NEXT_USHORT( p ); + FT_UInt startCoverageIndex = FT_NEXT_USHORT( p ); + + + if ( startGlyphID > endGlyphID ) + return FALSE; + + if ( last_id >= startGlyphID ) + return FALSE; + last_id = endGlyphID; + + /* XXX: Is this modulo 65536 arithmetic? */ + if ( startCoverageIndex + endGlyphID - startGlyphID >= + max_num_coverage_indices ) + return FALSE; + } + } + else + return FALSE; + + return TRUE; + } + + + static FT_Bool + tt_face_validate_class_def( FT_Byte* table, + FT_Byte* table_limit, + FT_UInt num_classes ) + { + FT_UInt format; + + FT_Byte* p = table; + FT_Byte* limit; + + FT_UInt max_class_value = 0; + + + if ( table_limit < p + 2 ) + return FALSE; + + format = FT_NEXT_USHORT( p ); + if ( format == 1 ) + { + FT_UInt glyphCount; + + + if ( table_limit < p + 4 ) + return FALSE; + + p += 2; /* Skip `startGlyphID`. */ + + glyphCount = FT_NEXT_USHORT( p ); + limit = p + glyphCount * 2; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt class_value = FT_NEXT_USHORT( p ); + + + if ( class_value > max_class_value ) + max_class_value = class_value; + } + } + else if ( format == 2 ) + { + FT_UInt classRangeCount; + FT_Long last_id = -1; + + + if ( table_limit < p + 2 ) + return FALSE; + + classRangeCount = FT_NEXT_USHORT( p ); + limit = p + classRangeCount * 6; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt startGlyphID = FT_NEXT_USHORT( p ); + FT_UInt endGlyphID = FT_NEXT_USHORT( p ); + FT_UInt class_value = FT_NEXT_USHORT( p ); + + + if ( startGlyphID > endGlyphID ) + return FALSE; + + if ( last_id >= startGlyphID ) + return FALSE; + last_id = endGlyphID; + + if ( class_value > max_class_value ) + max_class_value = class_value; + } + } + else + return FALSE; + + if ( max_class_value + 1 != num_classes ) + return FALSE; + + return TRUE; + } + + + static FT_Bool + tt_face_validate_feature( FT_Byte* table, + FT_Byte* table_limit, + FT_UInt use_lookup_table_size, + FT_Byte* use_lookup_table ) + { + FT_UInt lookupIndexCount; + + FT_Byte* p = table; + FT_Byte* limit; + + + if ( table_limit < p + 4 ) + return FALSE; + + p += 2; /* Skip `featureParamsOffset`. */ + + lookupIndexCount = FT_NEXT_USHORT( p ); + limit = p + lookupIndexCount * 2; + if ( table_limit < limit ) + return FALSE; + + while ( p < limit ) + { + FT_UInt lookup_index = FT_NEXT_USHORT( p ); + + + if ( lookup_index >= use_lookup_table_size ) + return FALSE; + + use_lookup_table[lookup_index] = TRUE; + } + + return TRUE; + } + + + static FT_Bool + tt_face_validate_feature_table( FT_Byte* table, + FT_Byte* table_limit, + FT_UInt use_lookup_table_size, + FT_Byte* use_lookup_table ) + { + FT_UInt featureCount; + + FT_Byte* p = table; + FT_Byte* limit; + + + if ( table_limit < p + 2 ) + return FALSE; + + featureCount = FT_NEXT_USHORT( p ); + limit = p + featureCount * 6; + if ( table_limit < limit ) + return FALSE; + + /* We completely ignore GPOS script information */ + /* and collect lookup tables of all 'kern' features. */ + while ( p < limit ) + { + FT_ULong featureTag = FT_NEXT_ULONG( p ); + FT_UInt featureOffset = FT_NEXT_USHORT( p ); + + + if ( featureTag == TTAG_kern ) + { + if ( !tt_face_validate_feature( table + featureOffset, + table_limit, + use_lookup_table_size, + use_lookup_table ) ) + return FALSE; + } + } + + return TRUE; + } + + + static FT_Bool + tt_face_validate_pair_set( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_UInt pairValueCount; + + FT_Byte* p = table; + FT_Byte* limit; + + FT_Long last_id = -1; + + + if ( table_limit < p + 2 ) + return FALSE; + + /* For our purposes, the first value record only contains X advances */ + /* while the second one is empty; a `PairValue` record has thus a */ + /* size of four bytes. */ + pairValueCount = FT_NEXT_USHORT( p ); + limit = p + pairValueCount * 4; + if ( table_limit < limit ) + return FALSE; + + /* We validate the order of `secondGlyph` so that binary search works. */ + while ( p < limit ) + { + FT_UInt id = FT_NEXT_USHORT( p ); + + + if ( last_id >= id ) + return FALSE; + + last_id = id; + + p += 2; /* Skip `valueRecord1`. */ + } + + return TRUE; + } + + + static FT_Bool + tt_face_validate_pair_pos1( FT_Byte* table, + FT_Byte* table_limit, + FT_Bool* is_fitting ) + { + FT_Byte* coverage; + FT_UInt valueFormat1; + FT_UInt valueFormat2; + + /* Subtable format is already checked. */ + FT_Byte* p = table + 2; + FT_Byte* limit; + + + /* The six bytes for the coverage table offset */ + /* and the value formats are already checked. */ + coverage = table + FT_NEXT_USHORT( p ); + + /* For the limited purpose of accessing the simplest type of kerning */ + /* (similar to what FreeType's 'kern' table handling provides) we */ + /* only consider tables that contains X advance values for the first */ + /* glyph and no data for the second glyph. */ + valueFormat1 = FT_NEXT_USHORT( p ); + valueFormat2 = FT_NEXT_USHORT( p ); + if ( valueFormat1 == 0x4 && valueFormat2 == 0 ) + { + FT_UInt pairSetCount; + + + if ( table_limit < p + 2 ) + return FALSE; + + pairSetCount = FT_NEXT_USHORT( p ); + limit = p + pairSetCount * 2; + if ( table_limit < limit ) + return FALSE; + + if ( !tt_face_validate_coverage( coverage, + table_limit, + pairSetCount ) ) + return FALSE; + + while ( p < limit ) + { + FT_Byte* pair_set = table + FT_NEXT_USHORT( p ); + + + if ( !tt_face_validate_pair_set( pair_set, table_limit ) ) + return FALSE; + } + + *is_fitting = TRUE; + } + + return TRUE; + } + + + static FT_Bool + tt_face_validate_pair_pos2( FT_Byte* table, + FT_Byte* table_limit, + FT_Bool* is_fitting ) + { + FT_Byte* coverage; + FT_UInt valueFormat1; + FT_UInt valueFormat2; + + /* Subtable format is already checked. */ + FT_Byte* p = table + 2; + FT_Byte* limit; + + + /* The six bytes for the coverage table offset */ + /* and the value formats are already checked. */ + coverage = table + FT_NEXT_USHORT( p ); + + valueFormat1 = FT_NEXT_USHORT( p ); + valueFormat2 = FT_NEXT_USHORT( p ); + if ( valueFormat1 == 0x4 && valueFormat2 == 0 ) + { + FT_Byte* class_def1; + FT_Byte* class_def2; + FT_UInt class1Count; + FT_UInt class2Count; + + + /* The number of coverage indices is not relevant here. */ + if ( !tt_face_validate_coverage( coverage, table_limit, FT_UINT_MAX ) ) + return FALSE; + + if ( table_limit < p + 8 ) + return FALSE; + + class_def1 = table + FT_NEXT_USHORT( p ); + class_def2 = table + FT_NEXT_USHORT( p ); + class1Count = FT_NEXT_USHORT( p ); + class2Count = FT_NEXT_USHORT( p ); + + if ( !tt_face_validate_class_def( class_def1, + table_limit, + class1Count ) ) + return FALSE; + if ( !tt_face_validate_class_def( class_def2, + table_limit, + class2Count ) ) + return FALSE; + + /* For our purposes, the first value record only contains */ + /* X advances while the second one is empty. */ + limit = p + class1Count * class2Count * 2; + if ( table_limit < limit ) + return FALSE; + + *is_fitting = TRUE; + } + + return TRUE; + } + + + /* The return value is the number of fitting subtables. */ + static FT_UInt + tt_face_validate_lookup_table( FT_Byte* table, + FT_Byte* table_limit ) + { + FT_UInt lookupType; + FT_UInt real_lookupType = 0; + FT_UInt subtableCount; + + FT_Byte* p = table; + FT_Byte* limit; + + FT_UInt num_fitting_subtables = 0; + + + if ( table_limit < p + 6 ) + return 0; + + lookupType = FT_NEXT_USHORT( p ); + + p += 2; /* Skip `lookupFlag`. */ + + subtableCount = FT_NEXT_USHORT( p ); + limit = p + subtableCount * 2; + if ( table_limit < limit ) + return 0; + + while ( p < limit ) + { + FT_Byte* subtable = table + FT_NEXT_USHORT( p ); + FT_UInt format; + + FT_Bool is_fitting = FALSE; + + + if ( lookupType == 9 ) + { + /* Positioning extension. */ + FT_Byte* q = subtable; + + + if ( table_limit < q + 8 ) + return 0; + + if ( FT_NEXT_USHORT( q ) != 1 ) /* format */ + return 0; + + if ( real_lookupType == 0 ) + real_lookupType = FT_NEXT_USHORT( q ); + else if ( real_lookupType != FT_NEXT_USHORT( q ) ) + return 0; + + subtable += FT_PEEK_ULONG( q ); + } + else + real_lookupType = lookupType; + + /* Ensure the first eight bytes of the subtable formats. */ + if ( table_limit < subtable + 8 ) + return 0; + + format = FT_PEEK_USHORT( subtable ); + + if ( real_lookupType == 2 ) + { + if ( format == 1 ) + { + if ( !tt_face_validate_pair_pos1( subtable, + table_limit, + &is_fitting ) ) + return 0; + } + else if ( format == 2 ) + { + if ( !tt_face_validate_pair_pos2( subtable, + table_limit, + &is_fitting ) ) + return 0; + } + else + return 0; + } + else + return 0; + + if ( is_fitting ) + num_fitting_subtables++; + } + + return num_fitting_subtables; + } + + + static void + tt_face_get_subtable_offsets( FT_Byte* table, + FT_Byte* gpos, + FT_UInt32* gpos_lookups_kerning, + FT_UInt* idx ) + { + FT_UInt lookupType; + FT_UInt subtableCount; + + FT_Byte* p = table; + FT_Byte* limit; + + + lookupType = FT_NEXT_USHORT( p ); + + p += 2; + + subtableCount = FT_NEXT_USHORT( p ); + limit = p + subtableCount * 2; + while ( p < limit ) + { + FT_Byte* subtable = table + FT_NEXT_USHORT( p ); + FT_UInt valueFormat1; + FT_UInt valueFormat2; + + + if ( lookupType == 9 ) + subtable += FT_PEEK_ULONG( subtable + 4 ); + + /* Table offsets for `valueFormat[12]` values */ + /* are identical for both subtable formats. */ + valueFormat1 = FT_PEEK_USHORT( subtable + 4 ); + valueFormat2 = FT_PEEK_USHORT( subtable + 6 ); + if ( valueFormat1 == 0x4 && valueFormat2 == 0 ) + { + /* We store offsets relative to the start of the GPOS table. */ + gpos_lookups_kerning[(*idx)++] = (FT_UInt32)( subtable - gpos ); + } + } + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_gpos( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_ULong gpos_length; + FT_Byte* gpos; + FT_Byte* gpos_limit; + + FT_UInt32* gpos_lookups_kerning; + + FT_UInt featureListOffset; + + FT_UInt lookupListOffset; + FT_Byte* lookup_list; + FT_UInt lookupCount; + + FT_UInt i; + + FT_Byte* use_lookup_table = NULL; + FT_UInt num_fitting_subtables; + + FT_Byte* p; + FT_Byte* limit; + + + face->gpos_table = NULL; + face->gpos_lookups_kerning = NULL; + face->num_gpos_lookups_kerning = 0; + + gpos = NULL; + gpos_lookups_kerning = NULL; + + error = face->goto_table( face, TTAG_GPOS, stream, &gpos_length ); + if ( error ) + goto Fail; + + if ( FT_FRAME_EXTRACT( gpos_length, gpos ) ) + goto Fail; + + if ( gpos_length < 10 ) + goto Fail; + + gpos_limit = gpos + gpos_length; + + /* We first need the number of GPOS lookups. */ + lookupListOffset = FT_PEEK_USHORT( gpos + 8 ); + + lookup_list = gpos + lookupListOffset; + p = lookup_list; + if ( gpos_limit < p + 2 ) + goto Fail; + + lookupCount = FT_NEXT_USHORT( p ); + limit = p + lookupCount * 2; + if ( gpos_limit < limit ) + goto Fail; + + /* Allocate an auxiliary array for Boolean values that */ + /* gets filled while walking over all 'kern' features. */ + if ( FT_NEW_ARRAY( use_lookup_table, lookupCount ) ) + goto Fail; + + featureListOffset = FT_PEEK_USHORT( gpos + 6 ); + + if ( !tt_face_validate_feature_table( gpos + featureListOffset, + gpos_limit, + lookupCount, + use_lookup_table ) ) + goto Fail; + + /* Now walk over all lookup tables and get the */ + /* number of fitting subtables. */ + num_fitting_subtables = 0; + for ( i = 0; i < lookupCount; i++ ) + { + FT_UInt lookupOffset; + + + if ( !use_lookup_table[i] ) + continue; + + lookupOffset = FT_PEEK_USHORT( p + i * 2 ); + + num_fitting_subtables += + tt_face_validate_lookup_table( lookup_list + lookupOffset, + gpos_limit ); + + } + + /* Loop again over all lookup tables and */ + /* collect offsets to those subtables. */ + if ( num_fitting_subtables ) + { + FT_UInt idx; + + + if ( FT_QNEW_ARRAY( gpos_lookups_kerning, num_fitting_subtables ) ) + goto Fail; + + idx = 0; + for ( i = 0; i < lookupCount; i++ ) + { + FT_UInt lookupOffset; + + + if ( !use_lookup_table[i] ) + continue; + + lookupOffset = FT_PEEK_USHORT( p + i * 2 ); + + tt_face_get_subtable_offsets( lookup_list + lookupOffset, + gpos, + gpos_lookups_kerning, + &idx ); + } + } + + FT_FREE( use_lookup_table ); + use_lookup_table = NULL; + + face->gpos_table = gpos; + face->gpos_lookups_kerning = gpos_lookups_kerning; + face->num_gpos_lookups_kerning = num_fitting_subtables; + + Exit: + return error; + + Fail: + FT_FREE( gpos ); + FT_FREE( gpos_lookups_kerning ); + FT_FREE( use_lookup_table ); + + /* If we don't have an explicit error code, set it to a generic value. */ + if ( !error ) + error = FT_THROW( Invalid_Table ); + + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_gpos( TT_Face face ) + { + FT_Stream stream = face->root.stream; + FT_Memory memory = face->root.memory; + + + FT_FRAME_RELEASE( face->gpos_table ); + FT_FREE( face->gpos_lookups_kerning ); + } + + + /*********************************/ + /******** ********/ + /******** GPOS access ********/ + /******** ********/ + /*********************************/ + + + static FT_Long + tt_face_get_coverage_index( FT_Byte* table, + FT_UInt glyph_index ) + { + FT_Byte* p = table; + FT_UInt format = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); + + FT_UInt min, max; + + + min = 0; + max = count; + + if ( format == 1 ) + { + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UInt mid_index = FT_PEEK_USHORT( p + mid * 2 ); + + + if ( glyph_index > mid_index ) + min = mid + 1; + else if ( glyph_index < mid_index ) + max = mid; + else + return mid; + } + } + else + { + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UInt startGlyphID = FT_PEEK_USHORT( p + mid * 6 ); + FT_UInt endGlyphID = FT_PEEK_USHORT( p + mid * 6 + 2 ); + + + if ( glyph_index > endGlyphID ) + min = mid + 1; + else if ( glyph_index < startGlyphID ) + max = mid; + else + { + FT_UInt startCoverageIndex = FT_PEEK_USHORT( p + mid * 6 + 4 ); + + + return startCoverageIndex + glyph_index - startGlyphID; + } + } + } + + return -1; + } + + + static FT_UInt + tt_face_get_class( FT_Byte* table, + FT_UInt glyph_index ) + { + FT_Byte* p = table; + FT_UInt format = FT_NEXT_USHORT( p ); + + + if ( format == 1 ) + { + FT_UInt startGlyphID = FT_NEXT_USHORT( p ); + FT_UInt glyphCount = FT_NEXT_USHORT( p ); + + + /* XXX: Is this modulo 65536 arithmetic? */ + if ( startGlyphID <= glyph_index && + startGlyphID + glyphCount >= glyph_index ) + return FT_PEEK_USHORT( p + ( glyph_index - startGlyphID ) * 2 ); + } + else + { + FT_UInt count = FT_NEXT_USHORT( p ); + + FT_UInt min, max; + + + min = 0; + max = count; + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UInt startGlyphID = FT_PEEK_USHORT( p + mid * 6 ); + FT_UInt endGlyphID = FT_PEEK_USHORT( p + mid * 6 + 2 ); + + + if ( glyph_index > endGlyphID ) + min = mid + 1; + else if ( glyph_index < startGlyphID ) + max = mid; + else + return FT_PEEK_USHORT( p + mid * 6 + 4 ); + } + } + + return 0; + } + + + static FT_Bool + tt_face_get_pair_pos1_kerning( FT_Byte* table, + FT_UInt first_glyph, + FT_UInt second_glyph, + FT_Int* kerning ) + { + FT_Byte* coverage = table + FT_PEEK_USHORT( table + 2 ); + FT_Long coverage_index = tt_face_get_coverage_index( coverage, + first_glyph ); + + FT_UInt pair_set_offset; + FT_Byte* p; + FT_UInt count; + + FT_UInt min, max; + + + if ( coverage_index < 0 ) + return FALSE; + + pair_set_offset = FT_PEEK_USHORT( table + 10 + coverage_index * 2 ); + p = table + pair_set_offset; + count = FT_NEXT_USHORT( p ); + + min = 0; + max = count; + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + FT_UInt mid_index = FT_PEEK_USHORT( p + mid * 4 ); + + + if ( second_glyph > mid_index ) + min = max + 1; + else if ( second_glyph < mid_index ) + max = mid; + else + { + *kerning = FT_PEEK_SHORT( p + mid * 4 + 2 ); + + return TRUE; + } + } + + return FALSE; + } + + + static FT_Bool + tt_face_get_pair_pos2_kerning( FT_Byte* table, + FT_UInt first_glyph, + FT_UInt second_glyph, + FT_Int* kerning ) + { + FT_Byte* coverage = table + FT_PEEK_USHORT( table + 2 ); + FT_Long coverage_index = tt_face_get_coverage_index( coverage, + first_glyph ); + + FT_Byte* class_def1; + FT_Byte* class_def2; + FT_UInt first_class; + FT_UInt second_class; + FT_UInt class2Count; + + + if ( coverage_index < 0 ) + return FALSE; + + class_def1 = table + FT_PEEK_USHORT( table + 8 ); + class_def2 = table + FT_PEEK_USHORT( table + 10 ); + + class2Count = FT_PEEK_USHORT( table + 14 ); + + first_class = tt_face_get_class( class_def1, first_glyph ); + second_class = tt_face_get_class( class_def2, second_glyph ); + + *kerning = + FT_PEEK_SHORT( table + 16 + + ( first_class * class2Count + second_class ) * 2 ); + + return TRUE; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_gpos_kerning( TT_Face face, + FT_UInt first_glyph, + FT_UInt second_glyph ) + { + FT_Int kerning = 0; + + FT_UInt i; + + + /* We only have `PairPos` subtables. */ + for ( i = 0; i < face->num_gpos_lookups_kerning; i++ ) + { + FT_Byte* subtable = face->gpos_table + face->gpos_lookups_kerning[i]; + FT_Byte* p = subtable; + + FT_UInt format = FT_NEXT_USHORT( p ); + + + if ( format == 1 ) + { + if ( tt_face_get_pair_pos1_kerning( subtable, + first_glyph, + second_glyph, + &kerning ) ) + break; + } + else + { + if ( tt_face_get_pair_pos2_kerning( subtable, + first_glyph, + second_glyph, + &kerning ) ) + break; + } + } + + return kerning; + } + +#else /* !TT_CONFIG_OPTION_GPOS_KERNING */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_gpos_dummy_; + +#endif /* !TT_CONFIG_OPTION_GPOS_KERNING */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttgpos.h b/src/thirdparty/freetype2/src/sfnt/ttgpos.h new file mode 100644 index 000000000..eebc22e9e --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/ttgpos.h @@ -0,0 +1,52 @@ +/**************************************************************************** + * + * ttgpos.h + * + * Routines to parse and access the 'GPOS' table for simple kerning + * (specification). + * + * Copyright (C) 2024-2025 by + * David Saltzman + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 TTGPOS_H_ +#define TTGPOS_H_ + + +#include +#include + + +FT_BEGIN_HEADER + + +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + + FT_LOCAL( FT_Error ) + tt_face_load_gpos( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_gpos( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_gpos_kerning( TT_Face face, + FT_UInt first_glyph, + FT_UInt second_glyph ); + +#endif /* TT_CONFIG_OPTION_GPOS_KERNING */ + + +FT_END_HEADER + +#endif /* TTGPOS_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttkern.c b/src/thirdparty/freetype2/src/sfnt/ttkern.c index 8d1b78109..76618b0d3 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttkern.c +++ b/src/thirdparty/freetype2/src/sfnt/ttkern.c @@ -2,10 +2,9 @@ * * ttkern.c * - * Load the basic TrueType kerning table. This doesn't handle - * kerning data within the GPOS table at the moment. + * Routines to parse and access the 'kern' table for kerning (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,10 +16,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #include "ttkern.h" #include "sferrors.h" @@ -95,7 +93,7 @@ p_next = p; - p += 2; /* skip version */ + p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); @@ -145,7 +143,7 @@ cur_pair = FT_NEXT_ULONG( p ); - if ( cur_pair <= old_pair ) + if ( cur_pair < old_pair ) break; p += 2; @@ -188,11 +186,18 @@ FT_UInt left_glyph, FT_UInt right_glyph ) { - FT_Int result = 0; - FT_UInt count, mask; - FT_Byte* p = face->kern_table; - FT_Byte* p_limit = p + face->kern_table_size; + FT_Int result = 0; + FT_UInt count, mask; + FT_Byte* p; + FT_Byte* p_limit; + + + if ( !face->kern_table ) + return result; + + p = face->kern_table; + p_limit = p + face->kern_table_size; p += 4; mask = 0x0001; diff --git a/src/thirdparty/freetype2/src/sfnt/ttkern.h b/src/thirdparty/freetype2/src/sfnt/ttkern.h index 5f283e5e6..e0075dce6 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttkern.h +++ b/src/thirdparty/freetype2/src/sfnt/ttkern.h @@ -2,10 +2,10 @@ * * ttkern.h * - * Load the basic TrueType kerning table. This doesn't handle - * kerning data within the GPOS table at the moment. + * Routines to parse and access the 'kern' table for kerning + * (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,9 +21,8 @@ #define TTKERN_H_ -#include -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include +#include FT_BEGIN_HEADER @@ -41,8 +40,6 @@ FT_BEGIN_HEADER FT_UInt left_glyph, FT_UInt right_glyph ); -#define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) - FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/ttload.c b/src/thirdparty/freetype2/src/sfnt/ttload.c index 5443bf4b6..0c257ce4d 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttload.c +++ b/src/thirdparty/freetype2/src/sfnt/ttload.c @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,10 +17,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #include "ttload.h" #include "sferrors.h" @@ -65,8 +64,8 @@ #endif - FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ", - face, + FT_TRACE4(( "tt_face_lookup_table: %p, `%c%c%c%c' -- ", + (void *)face, (FT_Char)( tag >> 24 ), (FT_Char)( tag >> 16 ), (FT_Char)( tag >> 8 ), @@ -206,9 +205,8 @@ if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) { - nn--; FT_TRACE2(( "check_table_dir:" - " can read only %d table%s in font (instead of %d)\n", + " can read only %hu table%s in font (instead of %hu)\n", nn, nn == 1 ? "" : "s", sfnt->num_tables )); sfnt->num_tables = nn; break; @@ -218,7 +216,7 @@ if ( table.Offset > stream->size ) { - FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); continue; } else if ( table.Length > stream->size - table.Offset ) @@ -233,7 +231,7 @@ valid_entries++; else { - FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); continue; } } @@ -363,7 +361,7 @@ }; - FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); + FT_TRACE2(( "tt_face_load_font_dir: %p\n", (void *)face )); /* read the offset table */ @@ -382,7 +380,7 @@ /* load the table directory */ - FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); + FT_TRACE2(( "-- Number of tables: %10hu\n", sfnt.num_tables )); FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); if ( sfnt.format_tag != TTAG_OTTO ) @@ -397,7 +395,15 @@ } } else + { valid_entries = sfnt.num_tables; + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + } face->num_tables = valid_entries; face->format_tag = sfnt.format_tag; @@ -409,9 +415,9 @@ FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset length checksum\n" - " ----------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset length checksum\n" )); + FT_TRACE2(( " ----------------------------------\n" )); valid_entries = 0; for ( nn = 0; nn < sfnt.num_tables; nn++ ) @@ -498,7 +504,15 @@ FT_FRAME_EXIT(); - FT_TRACE2(( "table directory loaded\n\n" )); + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + FT_TRACE2(( "table directory loaded\n" )); + FT_TRACE2(( "\n" )); Exit: return error; @@ -521,7 +535,8 @@ * 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. + * the MAKE_TT_TAG macro. Use value 1 to access the table + * directory. * * offset :: * The starting offset in the table (or the file if @@ -563,7 +578,29 @@ FT_ULong size; - if ( tag != 0 ) + if ( tag == 0 ) + { + /* The whole font file. */ + size = face->root.stream->size; + } + else if ( tag == 1 ) + { + /* The currently selected font's table directory. */ + /* */ + /* Note that `face_index` is also used to enumerate elements */ + /* of containers like a Mac Resource; this means we must */ + /* check whether we actually have a TTC (with multiple table */ + /* directories). */ + FT_Long idx = face->root.face_index & 0xFFFF; + + + if ( idx >= face->ttc_header.count ) + idx = 0; + + offset += face->ttc_header.offsets[idx]; + size = 4 + 8 + 16 * face->num_tables; + } + else { /* look for tag in font directory */ table = tt_face_lookup_table( face, tag ); @@ -576,9 +613,6 @@ 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 ) { @@ -664,8 +698,8 @@ 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 )); + FT_TRACE3(( "Units per EM: %4hu\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4hd\n", header->Index_To_Loc_Format )); Exit: return error; @@ -787,15 +821,15 @@ if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) { FT_TRACE0(( "tt_face_load_maxp:" - " too much twilight points in `maxp' table;\n" - " " + " too much twilight points in `maxp' table;\n" )); + FT_TRACE0(( " " " some glyphs might be rendered incorrectly\n" )); maxProfile->maxTwilightPoints = 0xFFFFU - 4; } } - FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); + FT_TRACE3(( "numGlyphs: %hu\n", maxProfile->numGlyphs )); Exit: return error; @@ -829,6 +863,8 @@ FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; TT_NameTable table; + TT_Name names = NULL; + TT_LangTag langTags = NULL; static const FT_Frame_Field name_table_fields[] = { @@ -909,14 +945,14 @@ storage_start += 2 + 4 * table->numLangTagRecords; /* allocate language tag records array */ - if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) || - FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) + if ( FT_QNEW_ARRAY( langTags, table->numLangTagRecords ) || + FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) goto Exit; /* load language tags */ { - TT_LangTag entry = table->langTags; - TT_LangTag limit = entry + table->numLangTagRecords; + TT_LangTag entry = langTags; + TT_LangTag limit = FT_OFFSET( entry, table->numLangTagRecords ); for ( ; entry < limit; entry++ ) @@ -931,7 +967,13 @@ /* invalid entry; ignore it */ entry->stringLength = 0; } + + /* mark the string as not yet loaded */ + entry->string = NULL; } + + table->langTags = langTags; + langTags = NULL; } FT_FRAME_EXIT(); @@ -940,14 +982,15 @@ } /* allocate name records array */ - if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) || - FT_FRAME_ENTER( table->numNameRecords * 12 ) ) + if ( FT_QNEW_ARRAY( names, table->numNameRecords ) || + FT_FRAME_ENTER( table->numNameRecords * 12 ) ) goto Exit; /* load name records */ { - TT_Name entry = table->names; + TT_Name entry = names; FT_UInt count = table->numNameRecords; + FT_UInt valid = 0; for ( ; count > 0; count-- ) @@ -980,15 +1023,20 @@ } } + /* mark the string as not yet converted */ + entry->string = NULL; + + valid++; entry++; } /* reduce array size to the actually used elements */ - count = (FT_UInt)( entry - table->names ); - (void)FT_RENEW_ARRAY( table->names, - table->numNameRecords, - count ); - table->numNameRecords = count; + FT_MEM_QRENEW_ARRAY( names, + table->numNameRecords, + valid ); + table->names = names; + names = NULL; + table->numNameRecords = valid; } FT_FRAME_EXIT(); @@ -997,6 +1045,8 @@ face->num_names = (FT_UShort)table->numNameRecords; Exit: + FT_FREE( names ); + FT_FREE( langTags ); return error; } @@ -1016,7 +1066,7 @@ FT_LOCAL_DEF( void ) tt_face_free_name( TT_Face face ) { - FT_Memory memory = face->root.driver->root.memory; + FT_Memory memory = face->root.memory; TT_NameTable table = &face->name_table; @@ -1242,11 +1292,11 @@ } } - 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 )); + FT_TRACE3(( "sTypoAscender: %4hd\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4hd\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4hu\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4hu\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2hx\n", os2->fsSelection )); Exit: return error; @@ -1304,10 +1354,16 @@ if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) return error; + if ( post->FormatType != 0x00030000L && + post->FormatType != 0x00025000L && + post->FormatType != 0x00020000L && + post->FormatType != 0x00010000L ) + return FT_THROW( Invalid_Post_Table_Format ); + /* we don't load the glyph names, we do that in another */ /* module (ttpost). */ - FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType )); + FT_TRACE3(( "FormatType: 0x%lx\n", post->FormatType )); FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch ? " yes" : " no" )); @@ -1403,8 +1459,8 @@ FT_Error error; FT_Memory memory = stream->memory; - FT_UInt j,num_ranges; - TT_GaspRange gaspranges = NULL; + FT_UShort j, num_ranges; + TT_GaspRange gasp_ranges = NULL; /* the gasp table is optional */ @@ -1415,8 +1471,8 @@ if ( FT_FRAME_ENTER( 4L ) ) goto Exit; - face->gasp.version = FT_GET_USHORT(); - face->gasp.numRanges = FT_GET_USHORT(); + face->gasp.version = FT_GET_USHORT(); + num_ranges = FT_GET_USHORT(); FT_FRAME_EXIT(); @@ -1428,29 +1484,31 @@ goto Exit; } - num_ranges = face->gasp.numRanges; - FT_TRACE3(( "numRanges: %u\n", num_ranges )); + FT_TRACE3(( "numRanges: %hu\n", num_ranges )); - if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || - FT_FRAME_ENTER( num_ranges * 4L ) ) + if ( FT_QNEW_ARRAY( gasp_ranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; - gaspranges = face->gasp.gaspRanges; - for ( j = 0; j < num_ranges; j++ ) { - gaspranges[j].maxPPEM = FT_GET_USHORT(); - gaspranges[j].gaspFlag = FT_GET_USHORT(); + gasp_ranges[j].maxPPEM = FT_GET_USHORT(); + gasp_ranges[j].gaspFlag = FT_GET_USHORT(); - FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", + FT_TRACE3(( "gaspRange %hu: rangeMaxPPEM %5hu, rangeGaspBehavior 0x%hx\n", j, - gaspranges[j].maxPPEM, - gaspranges[j].gaspFlag )); + gasp_ranges[j].maxPPEM, + gasp_ranges[j].gaspFlag )); } + face->gasp.gaspRanges = gasp_ranges; + gasp_ranges = NULL; + face->gasp.numRanges = num_ranges; + FT_FRAME_EXIT(); Exit: + FT_FREE( gasp_ranges ); return error; } diff --git a/src/thirdparty/freetype2/src/sfnt/ttload.h b/src/thirdparty/freetype2/src/sfnt/ttload.h index cc18c1869..e3666c901 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttload.h +++ b/src/thirdparty/freetype2/src/sfnt/ttload.h @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,9 +21,8 @@ #define TTLOAD_H_ -#include -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/ttmtx.c b/src/thirdparty/freetype2/src/sfnt/ttmtx.c index b6725c962..541d84474 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttmtx.c +++ b/src/thirdparty/freetype2/src/sfnt/ttmtx.c @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,13 +16,12 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_SERVICE_METRICS_VARIATIONS_H +#include #endif #include "ttmtx.h" @@ -240,7 +239,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Service_MetricsVariations var = - (FT_Service_MetricsVariations)face->var; + (FT_Service_MetricsVariations)face->tt_var; #endif @@ -307,7 +306,7 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( var ) + if ( var && FT_IS_VARIATION( &face->root ) ) { FT_Face f = FT_FACE( face ); FT_Int a = (FT_Int)*aadvance; diff --git a/src/thirdparty/freetype2/src/sfnt/ttmtx.h b/src/thirdparty/freetype2/src/sfnt/ttmtx.h index 5b0b60b64..1ee84507f 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttmtx.h +++ b/src/thirdparty/freetype2/src/sfnt/ttmtx.h @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2019 by + * Copyright (C) 2006-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define TTMTX_H_ -#include -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/ttpost.c b/src/thirdparty/freetype2/src/sfnt/ttpost.c index 636a0a004..4246b6c8e 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttpost.c +++ b/src/thirdparty/freetype2/src/sfnt/ttpost.c @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,10 +25,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES @@ -54,12 +53,12 @@ #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES -#include FT_SERVICE_POSTSCRIPT_CMAPS_H +#include #define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) -#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ +#else /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ /* Otherwise, we ignore the `psnames' module, and provide our own */ @@ -153,155 +152,109 @@ }; -#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ +#endif /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ static FT_Error - load_format_20( TT_Face face, - FT_Stream stream, - FT_ULong post_limit ) + load_format_20( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; - FT_Int num_glyphs; - FT_UShort num_names; + FT_UShort n; + FT_UShort num_names = 0; FT_UShort* glyph_indices = NULL; - FT_Char** name_strings = NULL; + FT_Byte** name_strings = NULL; + FT_Byte* q; - 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 ) + if ( (FT_ULong)num_glyphs * 2 > post_len ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } - /* load the indices */ + /* load the indices and note their maximum */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2 ) ) + goto Fail; + + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) { - FT_Int n; + FT_UShort idx = FT_NEXT_USHORT( q ); - if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || - FT_FRAME_ENTER( num_glyphs * 2L ) ) - goto Fail; + if ( idx > num_names ) + num_names = idx; - for ( n = 0; n < num_glyphs; n++ ) - glyph_indices[n] = FT_GET_USHORT(); - - FT_FRAME_EXIT(); + glyph_indices[n] = idx; } - /* compute number of names stored in table */ - { - FT_Int n; + FT_FRAME_EXIT(); - - 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; - } - } - } + /* compute number of names stored in the table */ + num_names = num_names > 257 ? num_names - 257 : 0; /* now load the name strings */ + if ( num_names ) { - FT_UShort n; + FT_Byte* p; + FT_Byte* p_end; - if ( FT_NEW_ARRAY( name_strings, num_names ) ) + post_len -= (FT_ULong)num_glyphs * 2; + + if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) + + post_len + 1 ) ) goto Fail; - for ( n = 0; n < num_names; n++ ) + p = (FT_Byte*)( name_strings + num_names ); + if ( FT_STREAM_READ( p, post_len ) ) + goto Fail; + + p_end = p + post_len; + + /* convert from Pascal- to C-strings and set pointers */ + for ( n = 0; p < p_end && n < num_names; n++ ) { - FT_UInt len; + FT_UInt len = *p; - if ( FT_STREAM_POS() >= post_limit ) - break; - else - { - FT_TRACE6(( "load_format_20: %d byte left in post table\n", - post_limit - FT_STREAM_POS() )); + /* names in the Adobe Glyph List are shorter than 40 characters */ + if ( len >= 40U ) + FT_TRACE4(( "load_format_20: unusual %u-char name found\n", len )); - if ( FT_READ_BYTE( len ) ) - goto Fail1; - } - - if ( len > post_limit || - FT_STREAM_POS() > post_limit - len ) - { - FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS(); - - - FT_ERROR(( "load_format_20:" - " exceeding string length (%d)," - " truncating at end of post table (%d byte left)\n", - len, d )); - len = (FT_UInt)FT_MAX( 0, d ); - } - - if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || - FT_STREAM_READ( name_strings[n], len ) ) - goto Fail1; - - name_strings[n][len] = '\0'; + *p++ = 0; + name_strings[n] = p; + p += len; } + *p_end = 0; + /* deal with missing or insufficient string data */ if ( n < num_names ) { - FT_ERROR(( "load_format_20:" - " all entries in post table are already parsed," - " using NULL names for gid %d - %d\n", - n, num_names - 1 )); + FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n", + (FT_UShort)( num_names - n ) )); + for ( ; n < num_names; n++ ) - if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) - goto Fail1; - else - name_strings[n][0] = '\0'; + name_strings[n] = p_end; } } /* all right, set table fields and exit successfully */ - { - TT_Post_20 table = &face->postscript_names.names.format_20; + names->num_glyphs = num_glyphs; + names->num_names = num_names; + names->glyph_indices = glyph_indices; + names->glyph_names = name_strings; - - 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 FT_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 ); @@ -312,66 +265,55 @@ static FT_Error - load_format_25( TT_Face face, - FT_Stream stream, - FT_ULong post_limit ) + load_format_25( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; - FT_Int num_glyphs; - FT_Char* offset_table = NULL; - - FT_UNUSED( post_limit ); + FT_UShort n; + FT_UShort* glyph_indices = NULL; + FT_Byte* q; - if ( FT_READ_USHORT( num_glyphs ) ) - goto Exit; - - /* check the number of glyphs */ - if ( num_glyphs > face->max_profile.numGlyphs || - num_glyphs > 258 || - num_glyphs < 1 ) + /* check the number of glyphs, including the theoretical limit */ + if ( num_glyphs > post_len || + num_glyphs > 258 + 128 ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } - if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || - FT_STREAM_READ( offset_table, num_glyphs ) ) + /* load the indices and check their Mac range */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs ) ) goto Fail; - /* now check the offset table */ + q = (FT_Byte*)stream->cursor; + + for ( n = 0; n < num_glyphs; n++ ) { - FT_Int n; + FT_Int idx = n + FT_NEXT_CHAR( q ); - for ( n = 0; n < num_glyphs; n++ ) - { - FT_Long idx = (FT_Long)n + offset_table[n]; + if ( idx < 0 || idx > 257 ) + idx = 0; - - if ( idx < 0 || idx > num_glyphs ) - { - error = FT_THROW( Invalid_File_Format ); - goto Fail; - } - } + glyph_indices[n] = (FT_UShort)idx; } + FT_FRAME_EXIT(); + /* 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; - } + names->num_glyphs = num_glyphs; + names->glyph_indices = glyph_indices; return FT_Err_Ok; Fail: - FT_FREE( offset_table ); + FT_FREE( glyph_indices ); Exit: return error; @@ -381,40 +323,37 @@ static FT_Error load_post_names( TT_Face face ) { - FT_Stream stream; - FT_Error error; - FT_Fixed format; + FT_Error error = FT_Err_Ok; + FT_Stream stream = face->root.stream; + FT_Fixed format = face->postscript.FormatType; FT_ULong post_len; - FT_ULong post_limit; + FT_UShort num_glyphs; - /* 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, &post_len ); if ( error ) goto Exit; - post_limit = FT_STREAM_POS() + post_len; - - format = face->postscript.FormatType; - - /* go to beginning of subtable */ - if ( FT_STREAM_SKIP( 32 ) ) + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + if ( post_len < 34 || + FT_STREAM_SKIP( 32 ) || + FT_READ_USHORT( num_glyphs ) || + num_glyphs > face->max_profile.numGlyphs || + num_glyphs == 0 ) goto Exit; - /* now read postscript table */ + /* now read postscript names data */ if ( format == 0x00020000L ) - error = load_format_20( face, stream, post_limit ); + error = load_format_20( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); else if ( format == 0x00025000L ) - error = load_format_25( face, stream, post_limit ); - else - error = FT_THROW( Invalid_File_Format ); - - face->postscript_names.loaded = 1; + error = load_format_25( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); Exit: + face->postscript_names.loaded = 1; /* even if failed */ return error; } @@ -424,37 +363,20 @@ { FT_Memory memory = face->root.memory; TT_Post_Names names = &face->postscript_names; - FT_Fixed format; - if ( names->loaded ) + if ( names->num_glyphs ) { - 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 == 0x00025000L ) - { - TT_Post_25 table = &names->names.format_25; - - - FT_FREE( table->offsets ); - table->num_glyphs = 0; - } + FT_FREE( names->glyph_indices ); + names->num_glyphs = 0; } + + if ( names->num_names ) + { + FT_FREE( names->glyph_names ); + names->num_names = 0; + } + names->loaded = 0; } @@ -490,7 +412,6 @@ FT_String** PSname ) { FT_Error error; - TT_Post_Names names; FT_Fixed format; #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES @@ -510,21 +431,15 @@ return FT_THROW( Unimplemented_Feature ); #endif - names = &face->postscript_names; - /* `.notdef' by default */ *PSname = MAC_NAME( 0 ); format = face->postscript.FormatType; - if ( format == 0x00010000L ) + if ( format == 0x00020000L || + format == 0x00025000L ) { - if ( idx < 258 ) /* paranoid checking */ - *PSname = MAC_NAME( idx ); - } - else if ( format == 0x00020000L ) - { - TT_Post_20 table = &names->names.format_20; + TT_Post_Names names = &face->postscript_names; if ( !names->loaded ) @@ -534,43 +449,34 @@ goto End; } - if ( idx < (FT_UInt)table->num_glyphs ) + if ( idx < (FT_UInt)names->num_glyphs ) { - FT_UShort name_index = table->glyph_indices[idx]; + FT_UShort name_index = names->glyph_indices[idx]; if ( name_index < 258 ) *PSname = MAC_NAME( name_index ); - else - *PSname = (FT_String*)table->glyph_names[name_index - 258]; + else /* only for version 2.0 */ + *PSname = (FT_String*)names->glyph_names[name_index - 258]; } } - else if ( format == 0x00025000L ) - { - 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 */ - *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] ); - } + /* version 1.0 is only valid with 258 glyphs */ + else if ( format == 0x00010000L && + face->max_profile.numGlyphs == 258 ) + *PSname = MAC_NAME( idx ); /* nothing to do for format == 0x00030000L */ End: + /* post format errors ignored */ return FT_Err_Ok; } #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ /* ANSI C doesn't like empty source files */ - typedef int _tt_post_dummy; + typedef int tt_post_dummy_; #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttpost.h b/src/thirdparty/freetype2/src/sfnt/ttpost.h index 812a0fc92..a11b66968 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttpost.h +++ b/src/thirdparty/freetype2/src/sfnt/ttpost.h @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,7 +23,7 @@ #include #include FT_CONFIG_CONFIG_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/sfnt/ttsbit.c b/src/thirdparty/freetype2/src/sfnt/ttsbit.c index 23bd9d7eb..9f9013bf3 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttsbit.c +++ b/src/thirdparty/freetype2/src/sfnt/ttsbit.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2019 by + * Copyright (C) 2005-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. @@ -19,11 +19,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include FT_BITMAP_H +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS @@ -173,13 +172,8 @@ goto Exit; } - /* we currently don't support bit 1; however, it is better to */ - /* draw at least something... */ if ( flags == 3 ) - FT_TRACE1(( "tt_face_load_sbit_strikes:" - " sbix overlay not supported yet\n" - " " - " expect bad rendering results\n" )); + face->root.face_flags |= FT_FACE_FLAG_SBIX_OVERLAY; /* * Count the number of strikes available in the table. We are a bit @@ -241,8 +235,8 @@ if ( !face->ebdt_size ) { FT_TRACE2(( "tt_face_load_sbit_strikes:" - " no embedded bitmap data table found;\n" - " " + " no embedded bitmap data table found;\n" )); + FT_TRACE2(( " " " resetting number of strikes to zero\n" )); face->sbit_num_strikes = 0; } @@ -346,9 +340,9 @@ if ( metrics->ascender == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid ascender and descender\n" - " " - " values for strike %d (%dppem, %dppem)\n", + " sanitizing invalid ascender and descender\n" )); + FT_TRACE2(( " " + " values for strike %lu (%dppem, %dppem)\n", strike_index, metrics->x_ppem, metrics->y_ppem )); @@ -375,8 +369,8 @@ if ( metrics->height == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid height value\n" - " " + " sanitizing invalid height value\n" )); + FT_TRACE2(( " " " for strike (%d, %d)\n", metrics->x_ppem, metrics->y_ppem )); metrics->height = metrics->y_ppem * 64; @@ -391,11 +385,9 @@ /* set the scale values (in 16.16 units) so advances */ /* from the hmtx and vmtx table are scaled correctly */ - metrics->x_scale = FT_MulDiv( metrics->x_ppem, - 64 * 0x10000, + metrics->x_scale = FT_DivFix( metrics->x_ppem * 64, face->header.Units_Per_EM ); - metrics->y_scale = FT_MulDiv( metrics->y_ppem, - 64 * 0x10000, + metrics->y_scale = FT_DivFix( metrics->y_ppem * 64, face->header.Units_Per_EM ); return FT_Err_Ok; @@ -405,9 +397,9 @@ { FT_Stream stream = face->root.stream; FT_UInt offset; - FT_UShort upem, ppem, resolution; + FT_UShort ppem, resolution; TT_HoriHeader *hori; - FT_Pos ppem_; /* to reduce casts */ + FT_Fixed scale; FT_Error error; FT_Byte* p; @@ -430,32 +422,23 @@ FT_FRAME_EXIT(); - upem = face->header.Units_Per_EM; - hori = &face->horizontal; - metrics->x_ppem = ppem; metrics->y_ppem = ppem; - ppem_ = (FT_Pos)ppem; + scale = FT_DivFix( ppem * 64, face->header.Units_Per_EM ); + hori = &face->horizontal; - metrics->ascender = - FT_MulDiv( hori->Ascender, ppem_ * 64, upem ); - metrics->descender = - FT_MulDiv( hori->Descender, ppem_ * 64, upem ); - metrics->height = - FT_MulDiv( hori->Ascender - hori->Descender + hori->Line_Gap, - ppem_ * 64, upem ); - metrics->max_advance = - FT_MulDiv( hori->advance_Width_Max, ppem_ * 64, upem ); + metrics->ascender = FT_MulFix( hori->Ascender, scale ); + metrics->descender = FT_MulFix( hori->Descender, scale ); + metrics->height = + FT_MulFix( hori->Ascender - hori->Descender + hori->Line_Gap, + scale ); + metrics->max_advance = FT_MulFix( hori->advance_Width_Max, scale ); /* set the scale values (in 16.16 units) so advances */ /* from the hmtx and vmtx table are scaled correctly */ - metrics->x_scale = FT_MulDiv( metrics->x_ppem, - 64 * 0x10000, - face->header.Units_Per_EM ); - metrics->y_scale = FT_MulDiv( metrics->y_ppem, - 64 * 0x10000, - face->header.Units_Per_EM ); + metrics->x_scale = scale; + metrics->y_scale = scale; return error; } @@ -727,6 +710,9 @@ pitch = bitmap->pitch; line = bitmap->buffer; + if ( !line ) + goto Exit; + width = decoder->metrics->width; height = decoder->metrics->height; @@ -1007,7 +993,7 @@ goto Fail; } - FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d component%s\n", + FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %u component%s\n", num_components, num_components == 1 ? "" : "s" )); @@ -1207,7 +1193,7 @@ goto Fail; p += 1; /* skip padding */ - /* fall-through */ + FALL_THROUGH; case 9: loader = tt_sbit_decoder_load_compound; @@ -1433,7 +1419,7 @@ image_start = image_offset + image_start; FT_TRACE3(( "tt_sbit_decoder_load_image:" - " found sbit (format %d) for glyph index %d\n", + " found sbit (format %u) for glyph index %u\n", image_format, glyph_index )); return tt_sbit_decoder_load_bitmap( decoder, @@ -1452,13 +1438,13 @@ if ( recurse_count ) { FT_TRACE4(( "tt_sbit_decoder_load_image:" - " missing subglyph sbit with glyph index %d\n", + " missing subglyph sbit with glyph index %u\n", glyph_index )); return FT_THROW( Invalid_Composite ); } FT_TRACE4(( "tt_sbit_decoder_load_image:" - " no sbit found for glyph index %d\n", glyph_index )); + " no sbit found for glyph index %u\n", glyph_index )); return FT_THROW( Missing_Bitmap ); } @@ -1476,12 +1462,13 @@ FT_Int originOffsetX, originOffsetY; FT_Tag graphicType; FT_Int recurse_depth = 0; + FT_Bool flipped = FALSE; FT_Error error; FT_Byte* p; - FT_UNUSED( map ); #ifndef FT_CONFIG_OPTION_USE_PNG + FT_UNUSED( map ); FT_UNUSED( metrics_only ); #endif @@ -1531,12 +1518,16 @@ switch ( graphicType ) { + case FT_MAKE_TAG( 'f', 'l', 'i', 'p' ): + flipped = !flipped; + FALL_THROUGH; + case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ): - if ( recurse_depth < 4 ) + if ( recurse_depth++ < 4 ) { glyph_index = FT_GET_USHORT(); FT_FRAME_EXIT(); - recurse_depth++; + goto retry; } error = FT_THROW( Invalid_File_Format ); @@ -1554,6 +1545,38 @@ glyph_end - glyph_start - 8, TRUE, metrics_only ); + if ( flipped && !metrics_only && !error ) + { + FT_UInt32* curr_pos = (FT_UInt32*)map->buffer; + + /* `Load_SBit_Png` always returns a pixmap with 32 bits per pixel */ + /* and no extra pitch bytes. */ + FT_UInt width = map->width; + FT_UInt y; + + + for ( y = 0; y < map->rows; y++ ) + { + FT_UInt32* left = curr_pos; + FT_UInt32* right = curr_pos + width - 1; + + + while ( left < right ) + { + FT_UInt32 value; + + + value = *right; + *right = *left; + *left = value; + + left++; + right--; + } + + curr_pos += width; + } + } #else error = FT_THROW( Unimplemented_Feature ); #endif @@ -1574,23 +1597,40 @@ if ( !error ) { - FT_Short abearing; + FT_Short abearing; /* not used here */ FT_UShort aadvance; tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); metrics->horiBearingX = (FT_Short)originOffsetX; - metrics->horiBearingY = (FT_Short)( -originOffsetY + metrics->height ); + metrics->vertBearingX = (FT_Short)originOffsetX; + + metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); + metrics->vertBearingY = (FT_Short)originOffsetY; + metrics->horiAdvance = (FT_UShort)( aadvance * face->root.size->metrics.x_ppem / face->header.Units_Per_EM ); + + if ( face->vertical_info ) + tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); + else if ( face->os2.version != 0xFFFFU ) + aadvance = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + + metrics->vertAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); } return error; } - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) tt_face_load_sbit_image( TT_Face face, FT_ULong strike_index, FT_UInt glyph_index, @@ -1674,7 +1714,7 @@ #else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_sbit_dummy; + typedef int tt_sbit_dummy_; #endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttsbit.h b/src/thirdparty/freetype2/src/sfnt/ttsbit.h index 5ab8ff556..7427149d6 100644 --- a/src/thirdparty/freetype2/src/sfnt/ttsbit.h +++ b/src/thirdparty/freetype2/src/sfnt/ttsbit.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define TTSBIT_H_ -#include #include "ttload.h" diff --git a/src/thirdparty/freetype2/src/sfnt/ttsvg.c b/src/thirdparty/freetype2/src/sfnt/ttsvg.c new file mode 100644 index 000000000..c7b83b2b7 --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/ttsvg.c @@ -0,0 +1,423 @@ +/**************************************************************************** + * + * ttsvg.c + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * 'SVG' table specification: + * + * https://learn.microsoft.com/typography/opentype/spec/svg + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef FT_CONFIG_OPTION_SVG + +#include "ttsvg.h" + + + /* NOTE: These table sizes are given by the specification. */ +#define SVG_TABLE_HEADER_SIZE (10U) +#define SVG_DOCUMENT_RECORD_SIZE (12U) +#define SVG_DOCUMENT_LIST_MINIMUM_SIZE (2U + SVG_DOCUMENT_RECORD_SIZE) +#define SVG_MINIMUM_SIZE (SVG_TABLE_HEADER_SIZE + \ + SVG_DOCUMENT_LIST_MINIMUM_SIZE) + + + /* An arbitrary, heuristic size limit (67MByte) for expanded SVG data. */ +#define MAX_SVG_SIZE ( 1 << 26 ) + + typedef struct Svg_ + { + FT_UShort version; /* table version (starting at 0) */ + FT_UShort num_entries; /* number of SVG document records */ + + FT_Byte* svg_doc_list; /* pointer to the start of SVG Document List */ + + void* table; /* memory that backs up SVG */ + FT_ULong table_size; + + } Svg; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsvg + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_ULong table_size; + FT_Byte* table = NULL; + FT_Byte* p = NULL; + Svg* svg = NULL; + FT_ULong offsetToSVGDocumentList; + + + error = face->goto_table( face, TTAG_SVG, stream, &table_size ); + if ( error ) + goto NoSVG; + + if ( table_size < SVG_MINIMUM_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoSVG; + + /* Allocate memory for the SVG object */ + if ( FT_NEW( svg ) ) + goto NoSVG; + + p = table; + svg->version = FT_NEXT_USHORT( p ); + offsetToSVGDocumentList = FT_NEXT_ULONG( p ); + + if ( offsetToSVGDocumentList < SVG_TABLE_HEADER_SIZE || + offsetToSVGDocumentList > table_size - + SVG_DOCUMENT_LIST_MINIMUM_SIZE ) + goto InvalidTable; + + svg->svg_doc_list = (FT_Byte*)( table + offsetToSVGDocumentList ); + + p = svg->svg_doc_list; + svg->num_entries = FT_NEXT_USHORT( p ); + + FT_TRACE3(( "version: %d\n", svg->version )); + FT_TRACE3(( "number of entries: %d\n", svg->num_entries )); + + if ( offsetToSVGDocumentList + 2U + + svg->num_entries * SVG_DOCUMENT_RECORD_SIZE > table_size ) + goto InvalidTable; + + svg->table = table; + svg->table_size = table_size; + + face->svg = svg; + face->root.face_flags |= FT_FACE_FLAG_SVG; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoSVG: + FT_FRAME_RELEASE( table ); + FT_FREE( svg ); + face->svg = NULL; + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_svg( TT_Face face ) + { + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + Svg* svg = (Svg*)face->svg; + + + if ( svg ) + { + FT_FRAME_RELEASE( svg->table ); + FT_FREE( svg ); + } + } + + + typedef struct Svg_doc_ + { + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_ULong offset; + FT_ULong length; + + } Svg_doc; + + + static Svg_doc + extract_svg_doc( FT_Byte* stream ) + { + Svg_doc doc; + + + doc.start_glyph_id = FT_NEXT_USHORT( stream ); + doc.end_glyph_id = FT_NEXT_USHORT( stream ); + + doc.offset = FT_NEXT_ULONG( stream ); + doc.length = FT_NEXT_ULONG( stream ); + + return doc; + } + + + static FT_Int + compare_svg_doc( Svg_doc doc, + FT_UInt glyph_index ) + { + if ( glyph_index < doc.start_glyph_id ) + return -1; + else if ( glyph_index > doc.end_glyph_id ) + return 1; + else + return 0; + } + + + static FT_Error + find_doc( FT_Byte* document_records, + FT_UShort num_entries, + FT_UInt glyph_index, + FT_ULong *doc_offset, + FT_ULong *doc_length, + FT_UShort *start_glyph, + FT_UShort *end_glyph ) + { + FT_Error error; + + Svg_doc start_doc; + Svg_doc mid_doc = { 0, 0, 0, 0 }; /* pacify compiler */ + Svg_doc end_doc; + + FT_Bool found = FALSE; + FT_UInt i = 0; + + FT_UInt start_index = 0; + FT_UInt end_index = num_entries - 1; + FT_Int comp_res; + + + /* search algorithm */ + if ( num_entries == 0 ) + { + error = FT_THROW( Invalid_Table ); + return error; + } + + start_doc = extract_svg_doc( document_records + start_index * 12 ); + end_doc = extract_svg_doc( document_records + end_index * 12 ); + + if ( ( compare_svg_doc( start_doc, glyph_index ) == -1 ) || + ( compare_svg_doc( end_doc, glyph_index ) == 1 ) ) + { + error = FT_THROW( Invalid_Glyph_Index ); + return error; + } + + while ( start_index <= end_index ) + { + i = ( start_index + end_index ) / 2; + mid_doc = extract_svg_doc( document_records + i * 12 ); + comp_res = compare_svg_doc( mid_doc, glyph_index ); + + if ( comp_res == 1 ) + { + start_index = i + 1; + start_doc = extract_svg_doc( document_records + start_index * 4 ); + } + else if ( comp_res == -1 ) + { + end_index = i - 1; + end_doc = extract_svg_doc( document_records + end_index * 4 ); + } + else + { + found = TRUE; + break; + } + } + /* search algorithm end */ + + if ( found != TRUE ) + { + FT_TRACE5(( "SVG glyph not found\n" )); + error = FT_THROW( Invalid_Glyph_Index ); + } + else + { + *doc_offset = mid_doc.offset; + *doc_length = mid_doc.length; + + *start_glyph = mid_doc.start_glyph_id; + *end_glyph = mid_doc.end_glyph_id; + + error = FT_Err_Ok; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ) + { + FT_Error error = FT_Err_Ok; + TT_Face face = (TT_Face)glyph->face; + FT_Memory memory = face->root.memory; + Svg* svg = (Svg*)face->svg; + + FT_Byte* doc_list; + FT_ULong doc_limit; + + FT_Byte* doc; + FT_ULong doc_offset; + FT_ULong doc_length; + FT_UShort doc_start_glyph_id; + FT_UShort doc_end_glyph_id; + + FT_SVG_Document svg_document = (FT_SVG_Document)glyph->other; + + + FT_ASSERT( !( svg == NULL ) ); + + doc_list = svg->svg_doc_list; + + error = find_doc( doc_list + 2, svg->num_entries, glyph_index, + &doc_offset, &doc_length, + &doc_start_glyph_id, &doc_end_glyph_id ); + if ( error != FT_Err_Ok ) + goto Exit; + + doc_limit = svg->table_size - + (FT_ULong)( doc_list - (FT_Byte*)svg->table ); + if ( doc_offset > doc_limit || + doc_length > doc_limit - doc_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + doc = doc_list + doc_offset; + + if ( doc_length > 6 && + doc[0] == 0x1F && + doc[1] == 0x8B && + doc[2] == 0x08 ) + { +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_ULong uncomp_size; + FT_Byte* uncomp_buffer = NULL; + + + /* + * Get the size of the original document. This helps in allotting the + * buffer to accommodate the uncompressed version. The last 4 bytes + * of the compressed document are equal to the original size modulo + * 2^32. Since the size of SVG documents is less than 2^32 bytes we + * can use this accurately. The four bytes are stored in + * little-endian format. + */ + FT_TRACE4(( "SVG document is GZIP compressed\n" )); + uncomp_size = (FT_ULong)doc[doc_length - 1] << 24 | + (FT_ULong)doc[doc_length - 2] << 16 | + (FT_ULong)doc[doc_length - 3] << 8 | + (FT_ULong)doc[doc_length - 4]; + + if ( uncomp_size >= MAX_SVG_SIZE ) + { + FT_ERROR(( "Uncompressed SVG document too large.\n" )); + error = FT_THROW( Array_Too_Large ); + goto Exit; + } + + if ( FT_QALLOC( uncomp_buffer, uncomp_size ) ) + goto Exit; + + error = FT_Gzip_Uncompress( memory, + uncomp_buffer, + &uncomp_size, + doc, + doc_length ); + if ( error ) + { + FT_FREE( uncomp_buffer ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + glyph->internal->flags |= FT_GLYPH_OWN_GZIP_SVG; + + doc = uncomp_buffer; + doc_length = uncomp_size; + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + } + + svg_document->svg_document = doc; + svg_document->svg_document_length = doc_length; + + svg_document->metrics = glyph->face->size->metrics; + svg_document->units_per_EM = glyph->face->units_per_EM; + + svg_document->start_glyph_id = doc_start_glyph_id; + svg_document->end_glyph_id = doc_end_glyph_id; + + svg_document->transform.xx = 0x10000; + svg_document->transform.xy = 0; + svg_document->transform.yx = 0; + svg_document->transform.yy = 0x10000; + + svg_document->delta.x = 0; + svg_document->delta.y = 0; + + FT_TRACE5(( "start_glyph_id: %d\n", doc_start_glyph_id )); + FT_TRACE5(( "end_glyph_id: %d\n", doc_end_glyph_id )); + FT_TRACE5(( "svg_document:\n" )); + FT_TRACE5(( " %.*s\n", (FT_UInt)doc_length, doc )); + + glyph->other = svg_document; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_SVG */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_svg_dummy_; + +#endif /* !FT_CONFIG_OPTION_SVG */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/ttsvg.h b/src/thirdparty/freetype2/src/sfnt/ttsvg.h new file mode 100644 index 000000000..d2e127d6d --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/ttsvg.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * ttsvg.h + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 TTSVG_H_ +#define TTSVG_H_ + +#include +#include + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_svg( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + +FT_END_HEADER + +#endif /* TTSVG_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/woff2tags.c b/src/thirdparty/freetype2/src/sfnt/woff2tags.c new file mode 100644 index 000000000..0f9e3889a --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/woff2tags.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * + * woff2tags.c + * + * WOFF2 Font table tags (base). + * + * Copyright (C) 2019-2025 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + +#include "woff2tags.h" + + /* + * Return tag from index in the order given in WOFF2 specification. + * + * See + * + * https://www.w3.org/TR/WOFF2/#table_dir_format + * + * for details. + */ + FT_LOCAL_DEF( FT_Tag ) + woff2_known_tags( FT_Byte index ) + { + static const FT_Tag known_tags[63] = + { + FT_MAKE_TAG('c', 'm', 'a', 'p'), /* 0 */ + FT_MAKE_TAG('h', 'e', 'a', 'd'), /* 1 */ + FT_MAKE_TAG('h', 'h', 'e', 'a'), /* 2 */ + FT_MAKE_TAG('h', 'm', 't', 'x'), /* 3 */ + FT_MAKE_TAG('m', 'a', 'x', 'p'), /* 4 */ + FT_MAKE_TAG('n', 'a', 'm', 'e'), /* 5 */ + FT_MAKE_TAG('O', 'S', '/', '2'), /* 6 */ + FT_MAKE_TAG('p', 'o', 's', 't'), /* 7 */ + FT_MAKE_TAG('c', 'v', 't', ' '), /* 8 */ + FT_MAKE_TAG('f', 'p', 'g', 'm'), /* 9 */ + FT_MAKE_TAG('g', 'l', 'y', 'f'), /* 10 */ + FT_MAKE_TAG('l', 'o', 'c', 'a'), /* 11 */ + FT_MAKE_TAG('p', 'r', 'e', 'p'), /* 12 */ + FT_MAKE_TAG('C', 'F', 'F', ' '), /* 13 */ + FT_MAKE_TAG('V', 'O', 'R', 'G'), /* 14 */ + FT_MAKE_TAG('E', 'B', 'D', 'T'), /* 15 */ + FT_MAKE_TAG('E', 'B', 'L', 'C'), /* 16 */ + FT_MAKE_TAG('g', 'a', 's', 'p'), /* 17 */ + FT_MAKE_TAG('h', 'd', 'm', 'x'), /* 18 */ + FT_MAKE_TAG('k', 'e', 'r', 'n'), /* 19 */ + FT_MAKE_TAG('L', 'T', 'S', 'H'), /* 20 */ + FT_MAKE_TAG('P', 'C', 'L', 'T'), /* 21 */ + FT_MAKE_TAG('V', 'D', 'M', 'X'), /* 22 */ + FT_MAKE_TAG('v', 'h', 'e', 'a'), /* 23 */ + FT_MAKE_TAG('v', 'm', 't', 'x'), /* 24 */ + FT_MAKE_TAG('B', 'A', 'S', 'E'), /* 25 */ + FT_MAKE_TAG('G', 'D', 'E', 'F'), /* 26 */ + FT_MAKE_TAG('G', 'P', 'O', 'S'), /* 27 */ + FT_MAKE_TAG('G', 'S', 'U', 'B'), /* 28 */ + FT_MAKE_TAG('E', 'B', 'S', 'C'), /* 29 */ + FT_MAKE_TAG('J', 'S', 'T', 'F'), /* 30 */ + FT_MAKE_TAG('M', 'A', 'T', 'H'), /* 31 */ + FT_MAKE_TAG('C', 'B', 'D', 'T'), /* 32 */ + FT_MAKE_TAG('C', 'B', 'L', 'C'), /* 33 */ + FT_MAKE_TAG('C', 'O', 'L', 'R'), /* 34 */ + FT_MAKE_TAG('C', 'P', 'A', 'L'), /* 35 */ + FT_MAKE_TAG('S', 'V', 'G', ' '), /* 36 */ + FT_MAKE_TAG('s', 'b', 'i', 'x'), /* 37 */ + FT_MAKE_TAG('a', 'c', 'n', 't'), /* 38 */ + FT_MAKE_TAG('a', 'v', 'a', 'r'), /* 39 */ + FT_MAKE_TAG('b', 'd', 'a', 't'), /* 40 */ + FT_MAKE_TAG('b', 'l', 'o', 'c'), /* 41 */ + FT_MAKE_TAG('b', 's', 'l', 'n'), /* 42 */ + FT_MAKE_TAG('c', 'v', 'a', 'r'), /* 43 */ + FT_MAKE_TAG('f', 'd', 's', 'c'), /* 44 */ + FT_MAKE_TAG('f', 'e', 'a', 't'), /* 45 */ + FT_MAKE_TAG('f', 'm', 't', 'x'), /* 46 */ + FT_MAKE_TAG('f', 'v', 'a', 'r'), /* 47 */ + FT_MAKE_TAG('g', 'v', 'a', 'r'), /* 48 */ + FT_MAKE_TAG('h', 's', 't', 'y'), /* 49 */ + FT_MAKE_TAG('j', 'u', 's', 't'), /* 50 */ + FT_MAKE_TAG('l', 'c', 'a', 'r'), /* 51 */ + FT_MAKE_TAG('m', 'o', 'r', 't'), /* 52 */ + FT_MAKE_TAG('m', 'o', 'r', 'x'), /* 53 */ + FT_MAKE_TAG('o', 'p', 'b', 'd'), /* 54 */ + FT_MAKE_TAG('p', 'r', 'o', 'p'), /* 55 */ + FT_MAKE_TAG('t', 'r', 'a', 'k'), /* 56 */ + FT_MAKE_TAG('Z', 'a', 'p', 'f'), /* 57 */ + FT_MAKE_TAG('S', 'i', 'l', 'f'), /* 58 */ + FT_MAKE_TAG('G', 'l', 'a', 't'), /* 59 */ + FT_MAKE_TAG('G', 'l', 'o', 'c'), /* 60 */ + FT_MAKE_TAG('F', 'e', 'a', 't'), /* 61 */ + FT_MAKE_TAG('S', 'i', 'l', 'l'), /* 62 */ + }; + + + if ( index > 62 ) + return 0; + + return known_tags[index]; + } + +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int woff2tags_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/sfnt/woff2tags.h b/src/thirdparty/freetype2/src/sfnt/woff2tags.h new file mode 100644 index 000000000..e22302296 --- /dev/null +++ b/src/thirdparty/freetype2/src/sfnt/woff2tags.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * + * woff2tags.h + * + * WOFF2 Font table tags (specification). + * + * Copyright (C) 2019-2025 by + * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 WOFF2TAGS_H +#define WOFF2TAGS_H + + +#include +#include + + +FT_BEGIN_HEADER + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + + FT_LOCAL( FT_Tag ) + woff2_known_tags( FT_Byte index ); + +#endif + +FT_END_HEADER + +#endif /* WOFF2TAGS_H */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/smooth/ftgrays.c b/src/thirdparty/freetype2/src/smooth/ftgrays.c index fd357a50f..365fbad42 100644 --- a/src/thirdparty/freetype2/src/smooth/ftgrays.c +++ b/src/thirdparty/freetype2/src/smooth/ftgrays.c @@ -4,7 +4,7 @@ * * A new `perfect' anti-aliasing renderer (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -149,32 +149,25 @@ #define FT_INT_MAX INT_MAX #define FT_ULONG_MAX ULONG_MAX -#define ADD_LONG( a, b ) \ - (long)( (unsigned long)(a) + (unsigned long)(b) ) -#define SUB_LONG( a, b ) \ - (long)( (unsigned long)(a) - (unsigned long)(b) ) -#define MUL_LONG( a, b ) \ - (long)( (unsigned long)(a) * (unsigned long)(b) ) -#define NEG_LONG( a ) \ - (long)( -(unsigned long)(a) ) +#define ADD_INT( a, b ) \ + (int)( (unsigned int)(a) + (unsigned int)(b) ) + +#define FT_STATIC_BYTE_CAST( type, var ) (type)(unsigned char)(var) #define ft_memset memset -#define ft_setjmp setjmp -#define ft_longjmp longjmp -#define ft_jmp_buf jmp_buf - typedef ptrdiff_t FT_PtrDist; -#define ErrRaster_Invalid_Mode -2 -#define ErrRaster_Invalid_Outline -1 -#define ErrRaster_Invalid_Argument -3 -#define ErrRaster_Memory_Overflow -4 +#define Smooth_Err_Ok 0 +#define Smooth_Err_Invalid_Outline -1 +#define Smooth_Err_Cannot_Render_Glyph -2 +#define Smooth_Err_Invalid_Argument -3 +#define Smooth_Err_Raster_Overflow -4 -#define FT_BEGIN_HEADER -#define FT_END_HEADER +#define FT_BEGIN_HEADER /* nothing */ +#define FT_END_HEADER /* nothing */ #include "ftimage.h" #include "ftgrays.h" @@ -229,23 +222,26 @@ typedef ptrdiff_t FT_PtrDist; #define FT_ERROR( varformat ) FT_Message varformat #endif -#define FT_THROW( e ) \ - ( FT_Throw( FT_ERR_CAT( ErrRaster_, e ), \ - __LINE__, \ - __FILE__ ) | \ - FT_ERR_CAT( ErrRaster_, e ) ) +#define FT_THROW( e ) \ + ( FT_Throw( FT_ERR_CAT( Smooth_Err_, e ), \ + __LINE__, \ + __FILE__ ) | \ + FT_ERR_CAT( Smooth_Err_, e ) ) #else /* !FT_DEBUG_LEVEL_TRACE */ #define FT_TRACE5( x ) do { } while ( 0 ) /* nothing */ #define FT_TRACE7( x ) do { } while ( 0 ) /* nothing */ #define FT_ERROR( x ) do { } while ( 0 ) /* nothing */ -#define FT_THROW( e ) FT_ERR_CAT( ErrRaster_, e ) - +#define FT_THROW( e ) FT_ERR_CAT( Smooth_Err_, e ) #endif /* !FT_DEBUG_LEVEL_TRACE */ +#define FT_Trace_Enable() do { } while ( 0 ) /* nothing */ +#define FT_Trace_Disable() do { } while ( 0 ) /* nothing */ + + #define FT_DEFINE_OUTLINE_FUNCS( class_, \ move_to_, line_to_, \ conic_to_, cubic_to_, \ @@ -279,18 +275,15 @@ typedef ptrdiff_t FT_PtrDist; #include +#include FT_CONFIG_CONFIG_H #include "ftgrays.h" -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H -#include FT_OUTLINE_H +#include +#include +#include +#include #include "ftsmerrs.h" -#define Smooth_Err_Invalid_Mode Smooth_Err_Cannot_Render_Glyph -#define Smooth_Err_Memory_Overflow Smooth_Err_Out_Of_Memory -#define ErrRaster_Memory_Overflow Smooth_Err_Out_Of_Memory - #endif /* !STANDALONE_ */ @@ -336,7 +329,9 @@ typedef ptrdiff_t FT_PtrDist; #define PIXEL_BITS 8 #define ONE_PIXEL ( 1 << PIXEL_BITS ) +#undef TRUNC #define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#undef FRACT #define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) #if PIXEL_BITS >= 6 @@ -363,7 +358,7 @@ typedef ptrdiff_t FT_PtrDist; } \ FT_END_STMNT -#ifdef __arm__ +#if defined( __GNUC__ ) && __GNUC__ < 7 && defined( __arm__ ) /* Work around a bug specific to GCC which make the compiler fail to */ /* optimize a division and modulo operation on the same parameters */ /* into a single call to `__aeabi_idivmod'. See */ @@ -383,14 +378,58 @@ typedef ptrdiff_t FT_PtrDist; #endif /* __arm__ */ - /* These macros speed up repetitive divisions by replacing them */ - /* with multiplications and right shifts. */ -#define FT_UDIVPREP( c, b ) \ - long b ## _r = c ? (long)( FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ - : 0 -#define FT_UDIV( a, b ) \ - (TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ - ( sizeof( long ) * FT_CHAR_BIT - PIXEL_BITS ) ) + /* Calculating coverages for a slanted line requires a division each */ + /* time the line crosses from cell to cell. These macros speed up */ + /* the repetitive divisions by replacing them with multiplications */ + /* and right shifts so that at most two divisions are performed for */ + /* each slanted line. Nevertheless, these divisions are noticeable */ + /* in the overall performance because flattened curves produce a */ + /* very large number of slanted lines. */ + /* */ + /* The division results here are always within ONE_PIXEL. Therefore */ + /* the shift magnitude should be at least PIXEL_BITS wider than the */ + /* divisors to provide sufficient accuracy of the multiply-shift. */ + /* It should not exceed (64 - PIXEL_BITS) to prevent overflowing and */ + /* leave enough room for 64-bit unsigned multiplication however. */ +#define FT_UDIVPREP( c, b ) \ + FT_Int64 b ## _r = c ? (FT_Int64)0xFFFFFFFF / ( b ) : 0 +#define FT_UDIV( a, b ) \ + (TCoord)( ( (FT_UInt64)( a ) * (FT_UInt64)( b ## _r ) ) >> 32 ) + + + /* Scale area and apply fill rule to calculate the coverage byte. */ + /* The top fill bit is used for the non-zero rule. The eighth */ + /* fill bit is used for the even-odd rule. The higher coverage */ + /* bytes are either clamped for the non-zero-rule or discarded */ + /* later for the even-odd rule. */ +#define FT_FILL_RULE( coverage, area, fill ) \ + FT_BEGIN_STMNT \ + coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) ); \ + if ( coverage & fill ) \ + coverage = ~coverage; \ + if ( coverage > 255 && fill & INT_MIN ) \ + coverage = 255; \ + FT_END_STMNT + + + /* It is faster to write small spans byte-by-byte than calling */ + /* `memset'. This is mainly due to the cost of the function call. */ +#define FT_GRAY_SET( d, s, count ) \ + FT_BEGIN_STMNT \ + unsigned char* q = d; \ + switch ( count ) \ + { \ + case 7: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 6: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 5: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 4: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 3: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 2: *q++ = (unsigned char)s; FALL_THROUGH; \ + case 1: *q = (unsigned char)s; FALL_THROUGH; \ + case 0: break; \ + default: FT_MEM_SET( d, s, count ); \ + } \ + FT_END_STMNT /************************************************************************** @@ -433,7 +472,7 @@ typedef ptrdiff_t FT_PtrDist; #endif /* FT_Span buffer size for direct rendering only */ -#define FT_MAX_GRAY_SPANS 10 +#define FT_MAX_GRAY_SPANS 16 #if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */ @@ -446,30 +485,27 @@ typedef ptrdiff_t FT_PtrDist; typedef struct gray_TWorker_ { - ft_jmp_buf jump_buffer; + FT_BBox cbox; - TCoord ex, ey; - TCoord min_ex, max_ex; + TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ TCoord min_ey, max_ey; + TCoord count_ey; /* same as (max_ey - min_ey) */ - TArea area; - TCoord cover; - int invalid; + int error; /* pool overflow exception */ + PCell cell; /* current cell */ + PCell cell_free; /* call allocation next free slot */ + PCell cell_null; /* last cell, used as dumpster and limit */ - PCell* ycells; - PCell cells; - FT_PtrDist max_cells; - FT_PtrDist num_cells; + PCell* ycells; /* array of cell linked-lists; one per */ + /* vertical coordinate in the current band */ - TPos x, y; + TPos x, y; /* last point position */ - FT_Outline outline; - TPixmap target; + FT_Outline outline; /* input outline */ + TPixmap target; /* target pixmap */ FT_Raster_Span_Func render_span; void* render_span_data; - FT_Span spans[FT_MAX_GRAY_SPANS]; - int num_spans; } gray_TWorker, *gray_PWorker; @@ -477,17 +513,25 @@ typedef ptrdiff_t FT_PtrDist; #pragma warning( pop ) #endif - #ifndef FT_STATIC_RASTER #define ras (*worker) #else static gray_TWorker ras; #endif + /* The |x| value of the null cell. Must be the largest possible */ + /* integer value stored in a `TCell.x` field. */ +#define CELL_MAX_X_VALUE INT_MAX + + +#define FT_INTEGRATE( ras, a, b ) \ + ras.cell->cover = ADD_INT( ras.cell->cover, a ), \ + ras.cell->area = ADD_INT( ras.cell->area, (a) * (TArea)(b) ) + typedef struct gray_TRaster_ { - void* memory; + void* memory; } gray_TRaster, *gray_PRaster; @@ -509,7 +553,7 @@ typedef ptrdiff_t FT_PtrDist; printf( "%3d:", y ); - for ( ; cell != NULL; cell = cell->next ) + for ( ; cell != ras.cell_null; cell = cell->next ) printf( " (%3d, c:%4d, a:%6d)", cell->x, cell->cover, cell->area ); printf( "\n" ); @@ -519,50 +563,6 @@ typedef ptrdiff_t FT_PtrDist; #endif /* FT_DEBUG_LEVEL_TRACE */ - /************************************************************************** - * - * Record the current cell in the linked list. - */ - static void - gray_record_cell( RAS_ARG ) - { - PCell *pcell, cell; - TCoord x = ras.ex; - - - pcell = &ras.ycells[ras.ey - ras.min_ey]; - while ( ( cell = *pcell ) ) - { - if ( cell->x > x ) - break; - - if ( cell->x == x ) - goto Found; - - pcell = &cell->next; - } - - if ( ras.num_cells >= ras.max_cells ) - ft_longjmp( ras.jump_buffer, 1 ); - - /* insert new cell */ - cell = ras.cells + ras.num_cells++; - cell->x = x; - cell->area = ras.area; - cell->cover = ras.cover; - - cell->next = *pcell; - *pcell = cell; - - return; - - Found: - /* update old cell */ - cell->area += ras.area; - cell->cover += ras.cover; - } - - /************************************************************************** * * Set the current cell to a new position. @@ -571,9 +571,9 @@ typedef ptrdiff_t FT_PtrDist; 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: */ + /* Move the cell pointer to a new position in the linked list. We use */ + /* a dumpster null cell for everything outside of the clipping region */ + /* 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 */ @@ -581,21 +581,56 @@ typedef ptrdiff_t FT_PtrDist; /* Note that if a cell is to the left of the clipping region, it is */ /* actually set to the (min_ex-1) horizontal position. */ - /* record the current one if it is valid and substantial */ - if ( !ras.invalid && ( ras.area || ras.cover ) ) - gray_record_cell( RAS_VAR ); + TCoord ey_index = ey - ras.min_ey; - ras.area = 0; - ras.cover = 0; - ras.ex = FT_MAX( ex, ras.min_ex - 1 ); - ras.ey = ey; - ras.invalid = ( ey >= ras.max_ey || ey < ras.min_ey || - ex >= ras.max_ex ); + if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) + ras.cell = ras.cell_null; + else + { + PCell* pcell = ras.ycells + ey_index; + PCell cell; + + + ex = FT_MAX( ex, ras.min_ex - 1 ); + + while ( 1 ) + { + cell = *pcell; + + if ( cell->x > ex ) + break; + + if ( cell->x == ex ) + goto Found; + + pcell = &cell->next; + } + + /* insert new cell */ + cell = ras.cell_free; + if ( cell == ras.cell_null ) + { + ras.error = FT_THROW( Raster_Overflow ); + goto Found; + } + + ras.cell_free = cell + 1; + + cell->x = ex; + cell->area = 0; + cell->cover = 0; + + cell->next = *pcell; + *pcell = cell; + + Found: + ras.cell = cell; + } } -#ifndef FT_LONG64 +#ifndef FT_INT64 /************************************************************************** * @@ -623,8 +658,8 @@ typedef ptrdiff_t FT_PtrDist; return; } - fx1 = FRACT( x1 ); - fx2 = FRACT( x2 ); + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); /* everything is located in a single cell. That is easy! */ /* */ @@ -656,10 +691,9 @@ typedef ptrdiff_t FT_PtrDist; /* XXX: y-delta and x-delta below should be related. */ FT_DIV_MOD( TCoord, p, dx, delta, mod ); - ras.area += (TArea)( ( fx1 + first ) * delta ); - ras.cover += delta; - y1 += delta; - ex1 += incr; + FT_INTEGRATE( ras, delta, fx1 + first ); + y1 += delta; + ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); if ( ex1 != ex2 ) @@ -680,10 +714,9 @@ typedef ptrdiff_t FT_PtrDist; delta++; } - ras.area += (TArea)( ONE_PIXEL * delta ); - ras.cover += delta; - y1 += delta; - ex1 += incr; + FT_INTEGRATE( ras, delta, ONE_PIXEL ); + y1 += delta; + ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); } while ( ex1 != ex2 ); } @@ -691,10 +724,7 @@ typedef ptrdiff_t FT_PtrDist; fx1 = ONE_PIXEL - first; End: - dy = y2 - y1; - - ras.area += (TArea)( ( fx1 + fx2 ) * dy ); - ras.cover += dy; + FT_INTEGRATE( ras, y2 - y1, fx1 + fx2 ); } @@ -737,7 +767,6 @@ typedef ptrdiff_t FT_PtrDist; { TCoord ex = TRUNC( ras.x ); TCoord two_fx = FRACT( ras.x ) << 1; - TArea area; if ( dy > 0) @@ -751,27 +780,23 @@ typedef ptrdiff_t FT_PtrDist; incr = -1; } - delta = first - fy1; - ras.area += (TArea)two_fx * delta; - ras.cover += delta; - ey1 += incr; + delta = first - fy1; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); delta = first + first - ONE_PIXEL; - area = (TArea)two_fx * delta; while ( ey1 != ey2 ) { - ras.area += area; - ras.cover += delta; - ey1 += incr; + FT_INTEGRATE( ras, delta, two_fx); + ey1 += incr; gray_set_cell( RAS_VAR_ ex, ey1 ); } - delta = fy2 - ONE_PIXEL + first; - ras.area += (TArea)two_fx * delta; - ras.cover += delta; + delta = fy2 - ONE_PIXEL + first; + FT_INTEGRATE( ras, delta, two_fx); goto End; } @@ -884,8 +909,7 @@ typedef ptrdiff_t FT_PtrDist; do { fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); fy1 = 0; ey1++; gray_set_cell( RAS_VAR_ ex1, ey1 ); @@ -894,8 +918,7 @@ typedef ptrdiff_t FT_PtrDist; do { fy2 = 0; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + FT_INTEGRATE( ras, fy2 - fy1, fx1 * 2 ); fy1 = ONE_PIXEL; ey1--; gray_set_cell( RAS_VAR_ ex1, ey1 ); @@ -903,7 +926,7 @@ typedef ptrdiff_t FT_PtrDist; } else /* any other line */ { - TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; + FT_Int64 prod = dx * (FT_Int64)fy1 - dy * (FT_Int64)fx1; FT_UDIVPREP( ex1 != ex2, dx ); FT_UDIVPREP( ey1 != ey2, dy ); @@ -913,72 +936,217 @@ typedef ptrdiff_t FT_PtrDist; /* also easily updated when moving from one cell to the next. */ do { - if ( prod <= 0 && - prod - dx * ONE_PIXEL > 0 ) /* left */ + if ( prod - dx * ONE_PIXEL > 0 && + prod <= 0 ) /* left */ { fx2 = 0; fy2 = FT_UDIV( -prod, -dx ); prod -= dy * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; } - else if ( prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ + else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 && + prod - dx * ONE_PIXEL <= 0 ) /* up */ { prod -= dx * ONE_PIXEL; fx2 = FT_UDIV( -prod, dy ); fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = fx2; fy1 = 0; ey1++; } - else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0 ) /* right */ + else if ( prod + dy * ONE_PIXEL >= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 ) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; fy2 = FT_UDIV( prod, dx ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = 0; fy1 = fy2; ex1++; } - else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + else /* ( prod > 0 && + prod + dy * ONE_PIXEL < 0 ) down */ { fx2 = FT_UDIV( prod, -dy ); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } gray_set_cell( RAS_VAR_ ex1, ey1 ); + } while ( ex1 != ex2 || ey1 != ey2 ); } fx2 = FRACT( to_x ); fy2 = FRACT( to_y ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + FT_INTEGRATE( ras, fy2 - fy1, fx1 + fx2 ); End: - ras.x = to_x; - ras.y = to_y; + ras.x = to_x; + ras.y = to_y; } #endif + /* + * For now, the code that uses DDA to render conic curves requires + * `FT_Int64` to be defined. See for example + * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1071. + */ + +#ifdef FT_INT64 + +#define LEFT_SHIFT( a, b ) (FT_Int64)( (FT_UInt64)(a) << (b) ) + + + static void + gray_render_conic( RAS_ARG_ const FT_Vector* control, + const FT_Vector* to ) + { + FT_Vector p0, p1, p2; + TPos ax, ay, bx, by, dx, dy; + int shift; + + FT_Int64 rx, ry; + FT_Int64 qx, qy; + FT_Int64 px, py; + + FT_UInt count; + + + p0.x = ras.x; + p0.y = ras.y; + p1.x = UPSCALE( control->x ); + p1.y = UPSCALE( control->y ); + p2.x = UPSCALE( to->x ); + p2.y = UPSCALE( to->y ); + + /* short-cut the arc that crosses the current band */ + if ( ( TRUNC( p0.y ) >= ras.max_ey && + TRUNC( p1.y ) >= ras.max_ey && + TRUNC( p2.y ) >= ras.max_ey ) || + ( TRUNC( p0.y ) < ras.min_ey && + TRUNC( p1.y ) < ras.min_ey && + TRUNC( p2.y ) < ras.min_ey ) ) + { + ras.x = p2.x; + ras.y = p2.y; + return; + } + + bx = p1.x - p0.x; + by = p1.y - p0.y; + ax = p2.x - p1.x - bx; /* p0.x + p2.x - 2 * p1.x */ + ay = p2.y - p1.y - by; /* p0.y + p2.y - 2 * p1.y */ + + dx = FT_ABS( ax ); + dy = FT_ABS( ay ); + if ( dx < dy ) + dx = dy; + + if ( dx <= ONE_PIXEL / 4 ) + { + gray_render_line( RAS_VAR_ p2.x, p2.y ); + return; + } + + /* We can calculate the number of necessary segments because */ + /* each bisection predictably reduces deviation exactly 4-fold. */ + /* Even 32-bit deviation would vanish after 16 bisections. */ + shift = 16; + do + { + dx >>= 2; + shift--; + + } while ( dx > ONE_PIXEL / 4 ); + count = 0x10000U >> shift; + + /* + * The (P0,P1,P2) arc equation, for t in [0,1] range: + * + * P(t) = P0*(1-t)^2 + P1*2*t*(1-t) + P2*t^2 + * + * P(t) = P0 + 2*(P1-P0)*t + (P0+P2-2*P1)*t^2 + * = P0 + 2*B*t + A*t^2 + * + * for A = P0 + P2 - 2*P1 + * and B = P1 - P0 + * + * Let's consider the difference when advancing by a small + * parameter h: + * + * Q(h,t) = P(t+h) - P(t) = 2*B*h + A*h^2 + 2*A*h*t + * + * And then its own difference: + * + * R(h,t) = Q(h,t+h) - Q(h,t) = 2*A*h*h = R (constant) + * + * Since R is always a constant, it is possible to compute + * successive positions with: + * + * P = P0 + * Q = Q(h,0) = 2*B*h + A*h*h + * R = 2*A*h*h + * + * loop: + * P += Q + * Q += R + * EMIT(P) + * + * To ensure accurate results, perform computations on 64-bit + * values, after scaling them by 2^32. + * + * h = 1 / 2^N + * + * R << 32 = 2 * A << (32 - N - N) + * = A << (33 - 2*N) + * + * Q << 32 = (2 * B << (32 - N)) + (A << (32 - N - N)) + * = (B << (33 - N)) + (A << (32 - 2*N)) + */ + + rx = LEFT_SHIFT( ax, shift + shift ); + ry = LEFT_SHIFT( ay, shift + shift ); + + qx = LEFT_SHIFT( bx, shift + 17 ) + rx; + qy = LEFT_SHIFT( by, shift + 17 ) + ry; + + rx *= 2; + ry *= 2; + + px = LEFT_SHIFT( p0.x, 32 ); + py = LEFT_SHIFT( p0.y, 32 ); + + do + { + px += qx; + py += qy; + qx += rx; + qy += ry; + + gray_render_line( RAS_VAR_ (FT_Pos)( px >> 32 ), + (FT_Pos)( py >> 32 ) ); + } while ( --count ); + } + +#else /* !FT_INT64 */ + + /* + * Note that multiple attempts to speed up the function below + * with SSE2 intrinsics, using various data layouts, have turned + * out to be slower than the non-SIMD code below. + */ static void gray_split_conic( FT_Vector* base ) { @@ -1008,7 +1176,7 @@ typedef ptrdiff_t FT_PtrDist; FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ FT_Vector* arc = bez_stack; TPos dx, dy; - int draw, split; + int draw; arc[0].x = UPSCALE( to->x ); @@ -1051,7 +1219,9 @@ typedef ptrdiff_t FT_PtrDist; /* many times as there are trailing zeros in the counter. */ do { - split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + int split = draw & ( -draw ); /* isolate the rightmost 1-bit */ + + while ( ( split >>= 1 ) ) { gray_split_conic( arc ); @@ -1064,7 +1234,17 @@ typedef ptrdiff_t FT_PtrDist; } while ( --draw ); } +#endif /* !FT_INT64 */ + + /* + * For cubic Bézier, binary splits are still faster than DDA + * because the splits are adaptive to how quickly each sub-arc + * approaches their chord trisection points. + * + * It might be useful to experiment with SSE2 to speed up + * `gray_split_cubic`, though. + */ static void gray_split_cubic( FT_Vector* base ) { @@ -1158,8 +1338,10 @@ typedef ptrdiff_t FT_PtrDist; static int gray_move_to( const FT_Vector* to, - gray_PWorker worker ) + void* worker_ ) /* gray_PWorker */ { + gray_PWorker worker = (gray_PWorker)worker_; + TPos x, y; @@ -1171,26 +1353,35 @@ typedef ptrdiff_t FT_PtrDist; ras.x = x; ras.y = y; - return 0; + + return ras.error; } static int gray_line_to( const FT_Vector* to, - gray_PWorker worker ) + void* worker_ ) /* gray_PWorker */ { + gray_PWorker worker = (gray_PWorker)worker_; + + gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) ); - return 0; + + return ras.error; } static int gray_conic_to( const FT_Vector* control, const FT_Vector* to, - gray_PWorker worker ) + void* worker_ ) /* gray_PWorker */ { + gray_PWorker worker = (gray_PWorker)worker_; + + gray_render_conic( RAS_VAR_ control, to ); - return 0; + + return ras.error; } @@ -1198,135 +1389,14 @@ typedef ptrdiff_t FT_PtrDist; gray_cubic_to( const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, - gray_PWorker worker ) + void* worker_ ) /* gray_PWorker */ { + gray_PWorker worker = (gray_PWorker)worker_; + + gray_render_cubic( RAS_VAR_ control1, control2, to ); - return 0; - } - - static void - gray_hline( RAS_ARG_ TCoord x, - TCoord y, - TArea coverage, - TCoord acount ) - { - /* scale the coverage from 0..(ONE_PIXEL*ONE_PIXEL*2) to 0..256 */ - coverage >>= PIXEL_BITS * 2 + 1 - 8; - - /* compute the line's coverage depending on the outline fill rule */ - if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) - { - coverage &= 511; - - if ( coverage >= 256 ) - coverage = 511 - coverage; - } - else /* default non-zero winding rule */ - { - if ( coverage < 0 ) - coverage = ~coverage; /* the same as -coverage - 1 */ - - if ( coverage >= 256 ) - coverage = 255; - } - - if ( ras.num_spans >= 0 ) /* for FT_RASTER_FLAG_DIRECT only */ - { - FT_Span* span = ras.spans + ras.num_spans++; - - - span->x = (short)x; - span->len = (unsigned short)acount; - span->coverage = (unsigned char)coverage; - - if ( ras.num_spans == FT_MAX_GRAY_SPANS ) - { - /* flush the span buffer and reset the count */ - ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data ); - ras.num_spans = 0; - } - } - else - { - unsigned char* q = ras.target.origin - ras.target.pitch * y + x; - unsigned char c = (unsigned char)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. - */ - switch ( acount ) - { - case 7: - *q++ = c; - /* fall through */ - case 6: - *q++ = c; - /* fall through */ - case 5: - *q++ = c; - /* fall through */ - case 4: - *q++ = c; - /* fall through */ - case 3: - *q++ = c; - /* fall through */ - case 2: - *q++ = c; - /* fall through */ - case 1: - *q = c; - /* fall through */ - case 0: - break; - default: - FT_MEM_SET( q, c, acount ); - } - } - } - - - static void - gray_sweep( RAS_ARG ) - { - int y; - - - for ( y = ras.min_ey; y < ras.max_ey; y++ ) - { - PCell cell = ras.ycells[y - ras.min_ey]; - TCoord x = ras.min_ex; - TArea cover = 0; - TArea area; - - - for ( ; cell != NULL; cell = cell->next ) - { - if ( cover != 0 && cell->x > x ) - gray_hline( RAS_VAR_ x, y, cover, cell->x - x ); - - cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); - area = cover - cell->area; - - if ( area != 0 && cell->x >= ras.min_ex ) - gray_hline( RAS_VAR_ cell->x, y, area, 1 ); - - x = cell->x + 1; - } - - if ( cover != 0 ) - gray_hline( RAS_VAR_ x, y, cover, ras.max_ex - x ); - - if ( ras.num_spans > 0 ) /* for FT_RASTER_FLAG_DIRECT only */ - { - /* flush the span buffer and reset the count */ - ras.render_span( y, ras.num_spans, ras.spans, ras.render_span_data ); - ras.num_spans = 0; - } - } + return ras.error; } @@ -1389,6 +1459,8 @@ typedef ptrdiff_t FT_PtrDist; int n; /* index of contour in outline */ int first; /* index of first point in contour */ + int last; /* index of last point in contour */ + char tag; /* current point's state */ int shift; @@ -1403,18 +1475,17 @@ typedef ptrdiff_t FT_PtrDist; shift = func_interface->shift; delta = func_interface->delta; - first = 0; + last = -1; for ( n = 0; n < outline->n_contours; n++ ) { - int last; /* index of last point in contour */ - - - FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n )); + FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n )); + first = last + 1; last = outline->contours[n]; - if ( last < 0 ) + if ( last < first ) goto Invalid_Outline; + limit = outline->points + last; v_start = outline->points[first]; @@ -1597,15 +1668,13 @@ typedef ptrdiff_t FT_PtrDist; v_start.x / 64.0, v_start.y / 64.0 )); error = func_interface->line_to( &v_start, user ); - Close: + Close: if ( error ) goto Exit; - - first = last + 1; } FT_TRACE5(( "FT_Outline_Decompose: Done\n", n )); - return 0; + return Smooth_Err_Ok; Exit: FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n", error )); @@ -1632,58 +1701,187 @@ typedef ptrdiff_t FT_PtrDist; static int - gray_convert_glyph_inner( RAS_ARG, + gray_convert_glyph_inner( RAS_ARG_ int continued ) { int error; - if ( ft_setjmp( ras.jump_buffer ) == 0 ) - { - if ( continued ) - FT_Trace_Disable(); - error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); - if ( continued ) - FT_Trace_Enable(); + if ( continued ) + FT_Trace_Disable(); + error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras ); + if ( continued ) + FT_Trace_Enable(); - if ( !ras.invalid ) - gray_record_cell( RAS_VAR ); - - FT_TRACE7(( "band [%d..%d]: %d cell%s\n", - ras.min_ey, - ras.max_ey, - ras.num_cells, - ras.num_cells == 1 ? "" : "s" )); - } - else - { - error = FT_THROW( Memory_Overflow ); - - FT_TRACE7(( "band [%d..%d]: to be bisected\n", - ras.min_ey, ras.max_ey )); - } + FT_TRACE7(( error == Smooth_Err_Raster_Overflow + ? "band [%d..%d]: to be bisected\n" + : "band [%d..%d]: %td cell%s remaining\n", + ras.min_ey, + ras.max_ey, + ras.cell_null - ras.cell_free, + ras.cell_null - ras.cell_free == 1 ? "" : "s" )); return error; } + static void + gray_sweep( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + unsigned char* line = ras.target.origin - ras.target.pitch * y; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, cell->x - x ); + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + line[cell->x] = (unsigned char)coverage; + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + FT_GRAY_SET( line + x, coverage, ras.max_ex - x ); + } + } + } + + + static void + gray_sweep_direct( RAS_ARG ) + { + int fill = ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL ) ? 0x100 + : INT_MIN; + int coverage; + int y; + + FT_Span span[FT_MAX_GRAY_SPANS]; + int n = 0; + + + for ( y = ras.min_ey; y < ras.max_ey; y++ ) + { + PCell cell = ras.ycells[y - ras.min_ey]; + TCoord x = ras.min_ex; + TArea cover = 0; + + + for ( ; cell != ras.cell_null; cell = cell->next ) + { + TArea area; + + + if ( cover != 0 && cell->x > x ) + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( cell->x - x ); + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + cover += (TArea)cell->cover * ( ONE_PIXEL * 2 ); + area = cover - cell->area; + + if ( area != 0 && cell->x >= ras.min_ex ) + { + FT_FILL_RULE( coverage, area, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)cell->x; + span[n].len = 1; + + if ( ++n == FT_MAX_GRAY_SPANS ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + + x = cell->x + 1; + } + + if ( cover != 0 ) /* only if cropped */ + { + FT_FILL_RULE( coverage, cover, fill ); + + span[n].coverage = (unsigned char)coverage; + span[n].x = (short)x; + span[n].len = (unsigned short)( ras.max_ex - x ); + + ++n; + } + + if ( n ) + { + /* flush the span buffer and reset the count */ + ras.render_span( y, n, span, ras.render_span_data ); + n = 0; + } + } + } + + static int gray_convert_glyph( RAS_ARG ) { - const TCoord yMin = ras.min_ey; - const TCoord yMax = ras.max_ey; - TCell buffer[FT_MAX_GRAY_POOL]; - size_t height = (size_t)( yMax - yMin ); + size_t height = (size_t)( ras.cbox.yMax - ras.cbox.yMin ); size_t n = FT_MAX_GRAY_POOL / 8; TCoord y; TCoord bands[32]; /* enough to accommodate bisections */ TCoord* band; int continued = 0; + int error = Smooth_Err_Ok; + /* Initialize the null cell at the end of the poll. */ + ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; + ras.cell_null->x = CELL_MAX_X_VALUE; + ras.cell_null->area = 0; + ras.cell_null->cover = 0; + ras.cell_null->next = NULL; + /* set up vertical bands */ + ras.ycells = (PCell*)buffer; + if ( height > n ) { /* two divisions rounded up */ @@ -1691,65 +1889,74 @@ typedef ptrdiff_t FT_PtrDist; height = ( height + n - 1 ) / n; } - /* memory management */ - n = ( height * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) / sizeof ( TCell ); - - ras.cells = buffer + n; - ras.max_cells = (FT_PtrDist)( FT_MAX_GRAY_POOL - n ); - ras.ycells = (PCell*)buffer; - - for ( y = yMin; y < yMax; ) + for ( y = ras.cbox.yMin; y < ras.cbox.yMax; ) { ras.min_ey = y; y += height; - ras.max_ey = FT_MIN( y, yMax ); + ras.max_ey = FT_MIN( y, ras.cbox.yMax ); + + ras.count_ey = ras.max_ey - ras.min_ey; band = bands; - band[1] = ras.min_ey; - band[0] = ras.max_ey; + band[1] = ras.cbox.xMin; + band[0] = ras.cbox.xMax; do { - TCoord width = band[0] - band[1]; - int error; + TCoord i; - FT_MEM_ZERO( ras.ycells, height * sizeof ( PCell ) ); + ras.min_ex = band[1]; + ras.max_ex = band[0]; - ras.num_cells = 0; - ras.invalid = 1; - ras.min_ey = band[1]; - ras.max_ey = band[0]; + /* memory management: zero out and skip ycells */ + for ( i = 0; i < ras.count_ey; ++i ) + ras.ycells[i] = ras.cell_null; - error = gray_convert_glyph_inner( RAS_VAR, continued ); + n = ( (size_t)ras.count_ey * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) + / sizeof ( TCell ); + + ras.cell_free = buffer + n; + ras.cell = ras.cell_null; + ras.error = Smooth_Err_Ok; + + error = gray_convert_glyph_inner( RAS_VAR_ continued ); continued = 1; if ( !error ) { - gray_sweep( RAS_VAR ); + if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ + gray_sweep_direct( RAS_VAR ); + else + gray_sweep( RAS_VAR ); band--; continue; } - else if ( error != ErrRaster_Memory_Overflow ) - return 1; + else if ( error != Smooth_Err_Raster_Overflow ) + goto Exit; /* render pool overflow; we will reduce the render band by half */ - width >>= 1; + i = ( band[0] - band[1] ) >> 1; /* this should never happen even with tiny rendering pool */ - if ( width == 0 ) + if ( i == 0 ) { FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); - return 1; + error = FT_THROW( Raster_Overflow ); + goto Exit; } band++; band[1] = band[0]; - band[0] += width; + band[0] += i; } while ( band >= bands ); } - return 0; + Exit: + ras.cell = ras.cell_free = ras.cell_null = NULL; + ras.ycells = NULL; + + return error; } @@ -1770,14 +1977,14 @@ typedef ptrdiff_t FT_PtrDist; /* this version does not support monochrome rendering */ if ( !( params->flags & FT_RASTER_FLAG_AA ) ) - return FT_THROW( Invalid_Mode ); + return FT_THROW( Cannot_Render_Glyph ); if ( !outline ) return FT_THROW( Invalid_Outline ); /* return immediately if the outline is empty */ - if ( outline->n_points == 0 || outline->n_contours <= 0 ) - return 0; + if ( outline->n_points == 0 || outline->n_contours == 0 ) + return Smooth_Err_Ok; if ( !outline->contours || !outline->points ) return FT_THROW( Invalid_Outline ); @@ -1791,16 +1998,12 @@ typedef ptrdiff_t FT_PtrDist; if ( params->flags & FT_RASTER_FLAG_DIRECT ) { if ( !params->gray_spans ) - return 0; + return Smooth_Err_Ok; ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; - ras.num_spans = 0; - ras.min_ex = params->clip_box.xMin; - ras.min_ey = params->clip_box.yMin; - ras.max_ex = params->clip_box.xMax; - ras.max_ey = params->clip_box.yMax; + ras.cbox = params->clip_box; } else { @@ -1810,7 +2013,7 @@ typedef ptrdiff_t FT_PtrDist; /* nothing to do */ if ( !target_map->width || !target_map->rows ) - return 0; + return Smooth_Err_Ok; if ( !target_map->buffer ) return FT_THROW( Invalid_Argument ); @@ -1825,17 +2028,16 @@ typedef ptrdiff_t FT_PtrDist; ras.render_span = (FT_Raster_Span_Func)NULL; ras.render_span_data = NULL; - ras.num_spans = -1; /* invalid */ - ras.min_ex = 0; - ras.min_ey = 0; - ras.max_ex = (FT_Pos)target_map->width; - ras.max_ey = (FT_Pos)target_map->rows; + ras.cbox.xMin = 0; + ras.cbox.yMin = 0; + ras.cbox.xMax = (FT_Pos)target_map->width; + ras.cbox.yMax = (FT_Pos)target_map->rows; } /* exit if nothing to do */ - if ( ras.max_ex <= ras.min_ex || ras.max_ey <= ras.min_ey ) - return 0; + if ( ras.cbox.xMin >= ras.cbox.xMax || ras.cbox.yMin >= ras.cbox.yMax ) + return Smooth_Err_Ok; return gray_convert_glyph( RAS_VAR ); } @@ -1872,19 +2074,20 @@ typedef ptrdiff_t FT_PtrDist; #else /* !STANDALONE_ */ static int - gray_raster_new( FT_Memory memory, - FT_Raster* araster ) + gray_raster_new( void* memory_, + FT_Raster* araster_ ) { + FT_Memory memory = (FT_Memory)memory_; + gray_PRaster* araster = (gray_PRaster*)araster_; + FT_Error error; gray_PRaster raster = NULL; - *araster = 0; - if ( !FT_ALLOC( raster, sizeof ( gray_TRaster ) ) ) - { + if ( !FT_NEW( raster ) ) raster->memory = memory; - *araster = (FT_Raster)raster; - } + + *araster = raster; return error; } diff --git a/src/thirdparty/freetype2/src/smooth/ftgrays.h b/src/thirdparty/freetype2/src/smooth/ftgrays.h index e9f9c7a4a..e463e5b3e 100644 --- a/src/thirdparty/freetype2/src/smooth/ftgrays.h +++ b/src/thirdparty/freetype2/src/smooth/ftgrays.h @@ -4,7 +4,7 @@ * * FreeType smooth renderer declaration * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,18 +19,14 @@ #ifndef FTGRAYS_H_ #define FTGRAYS_H_ -#ifdef __cplusplus - extern "C" { -#endif - - #ifdef STANDALONE_ #include "ftimage.h" #else #include -#include FT_IMAGE_H +#include #endif +FT_BEGIN_HEADER /************************************************************************** * @@ -46,10 +42,7 @@ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster; - -#ifdef __cplusplus - } -#endif +FT_END_HEADER #endif /* FTGRAYS_H_ */ diff --git a/src/thirdparty/freetype2/src/smooth/ftsmerrs.h b/src/thirdparty/freetype2/src/smooth/ftsmerrs.h index d52c0dd9e..8d5068549 100644 --- a/src/thirdparty/freetype2/src/smooth/ftsmerrs.h +++ b/src/thirdparty/freetype2/src/smooth/ftsmerrs.h @@ -4,7 +4,7 @@ * * smooth renderer error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef FTSMERRS_H_ #define FTSMERRS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX Smooth_Err_ #define FT_ERR_BASE FT_Mod_Err_Smooth -#include FT_ERRORS_H +#include #endif /* FTSMERRS_H_ */ diff --git a/src/thirdparty/freetype2/src/smooth/ftsmooth.c b/src/thirdparty/freetype2/src/smooth/ftsmooth.c index cd034d2b4..21a6eca00 100644 --- a/src/thirdparty/freetype2/src/smooth/ftsmooth.c +++ b/src/thirdparty/freetype2/src/smooth/ftsmooth.c @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (body). * - * Copyright (C) 2000-2019 by + * Copyright (C) 2000-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,46 +16,15 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_OUTLINE_H +#include +#include +#include #include "ftsmooth.h" #include "ftgrays.h" #include "ftsmerrs.h" - /* initialize renderer -- init its raster */ - static FT_Error - ft_smooth_init( FT_Renderer render ) - { - -#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING - - FT_Vector* sub = render->root.library->lcd_geometry; - - - /* set up default subpixel geometry for striped RGB panels. */ - sub[0].x = -21; - sub[0].y = 0; - sub[1].x = 0; - sub[1].y = 0; - sub[2].x = 21; - sub[2].y = 0; - -#elif 0 /* or else, once ClearType patents expire */ - - FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); - -#endif - - render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); - - return 0; - } - - /* sets render-specific mode */ static FT_Error ft_smooth_set_mode( FT_Renderer render, @@ -107,14 +76,369 @@ FT_Outline_Get_CBox( &slot->outline, cbox ); } + typedef struct TOrigin_ + { + unsigned char* origin; /* pixmap origin at the bottom-left */ + int pitch; /* pitch to go down one row */ - /* convert a slot's glyph image into a bitmap */ + } TOrigin; + +#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + /* initialize renderer -- init its raster */ 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_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + FT_Vector* sub = render->root.library->lcd_geometry; + + + /* set up default subpixel geometry for striped RGB panels. */ + sub[0].x = -21; + sub[0].y = 0; + sub[1].x = 0; + sub[1].y = 0; + sub[2].x = 21; + sub[2].y = 0; + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + /* This function writes every third byte in direct rendering mode */ + static void + ft_smooth_lcd_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) /* TOrigin* */ + { + TOrigin* target = (TOrigin*)target_; + + unsigned char* dst_line = target->origin - y * target->pitch; + unsigned char* dst; + unsigned short w; + + + for ( ; count--; spans++ ) + for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) + *dst = spans->coverage; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + TOrigin target; + + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Set up direct rendering to record them on each third byte. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_lcd_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width; + params.clip_box.yMax = bitmap->rows; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + FT_Outline_Translate( outline, + -sub[0].x, + -sub[0].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].x; + y = sub[0].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[0].x - sub[1].x, + sub[0].y - sub[1].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].x; + y = sub[1].y; + if ( error ) + goto Exit; + + target.origin++; + FT_Outline_Translate( outline, + sub[1].x - sub[2].x, + sub[1].y - sub[2].y ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].x; + y = sub[2].y; + + Exit: + FT_Outline_Translate( outline, x, y ); + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + int pitch = bitmap->pitch; + FT_Vector* sub = render->root.library->lcd_geometry; + FT_Pos x, y; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* Render 3 separate coverage bitmaps, shifting the outline. */ + /* Notice that the subpixel geometry vectors are rotated. */ + /* Triple the pitch to render on each third row. */ + bitmap->pitch *= 3; + bitmap->rows /= 3; + + FT_Outline_Translate( outline, + -sub[0].y, + sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[0].y; + y = -sub[0].x; + if ( error ) + goto Exit; + + bitmap->buffer += pitch; + FT_Outline_Translate( outline, + sub[0].y - sub[1].y, + sub[1].x - sub[0].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[1].y; + y = -sub[1].x; + bitmap->buffer -= pitch; + if ( error ) + goto Exit; + + bitmap->buffer += 2 * pitch; + FT_Outline_Translate( outline, + sub[1].y - sub[2].y, + sub[2].x - sub[1].x ); + error = render->raster_render( render->raster, ¶ms ); + x = sub[2].y; + y = -sub[2].x; + bitmap->buffer -= 2 * pitch; + + Exit: + FT_Outline_Translate( outline, x, y ); + + bitmap->pitch /= 3; + bitmap->rows *= 3; + + return error; + } + +#else /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Module module ) /* FT_Renderer */ + { + FT_Renderer render = (FT_Renderer)module; + + + /* set up default LCD filtering */ + FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); + + render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); + + return 0; + } + + + static FT_Error + ft_smooth_raster_lcd( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->x /= 3; + + return error; + } + + + static FT_Error + ft_smooth_raster_lcdv( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + /* implode outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y *= 3; + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + vec->y /= 3; + + return error; + } + +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +/* Oversampling scale to be used in rendering overlaps */ +#define SCALE ( 1 << 2 ) + + /* This function averages inflated spans in direct rendering mode */ + static void + ft_smooth_overlap_spans( int y, + int count, + const FT_Span* spans, + void* target_ ) + { + TOrigin* target = (TOrigin*)target_; + + + unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; + unsigned short x; + unsigned int cover, sum; + + + /* When accumulating the oversampled spans we need to assure that */ + /* fully covered pixels are equal to 255 and do not overflow. */ + /* It is important that the SCALE is a power of 2, each subpixel */ + /* cover can also reach a power of 2 after rounding, and the total */ + /* is clamped to 255 when it adds up to 256. */ + for ( ; count--; spans++ ) + { + cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); + for ( x = 0; x < spans->len; x++ ) + { + sum = dst[( spans->x + x ) / SCALE] + cover; + dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); + } + } + } + + + static FT_Error + ft_smooth_raster_overlap( FT_Renderer render, + FT_Outline* outline, + FT_Bitmap* bitmap ) + { + FT_Error error = FT_Err_Ok; + FT_Vector* points = outline->points; + FT_Vector* points_end = FT_OFFSET( points, outline->n_points ); + FT_Vector* vec; + + FT_Raster_Params params; + TOrigin target; + + + /* Reject outlines that are too wide for 16-bit FT_Span. */ + /* Other limits are applied upstream with the same error code. */ + if ( bitmap->width * SCALE > 0x7FFF ) + return FT_THROW( Raster_Overflow ); + + /* Set up direct rendering to average oversampled spans. */ + params.source = outline; + params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT; + params.gray_spans = ft_smooth_overlap_spans; + params.user = ⌖ + + params.clip_box.xMin = 0; + params.clip_box.yMin = 0; + params.clip_box.xMax = bitmap->width * SCALE; + params.clip_box.yMax = bitmap->rows * SCALE; + + if ( bitmap->pitch < 0 ) + target.origin = bitmap->buffer; + else + target.origin = bitmap->buffer + + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch; + + target.pitch = bitmap->pitch; + + /* inflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x *= SCALE; + vec->y *= SCALE; + } + + /* render outline into the bitmap */ + error = render->raster_render( render->raster, ¶ms ); + + /* deflate outline */ + for ( vec = points; vec < points_end; vec++ ) + { + vec->x /= SCALE; + vec->y /= SCALE; + } + + return error; + } + +#undef SCALE + + static FT_Error + ft_smooth_render( FT_Renderer render, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) { FT_Error error = FT_Err_Ok; FT_Outline* outline = &slot->outline; @@ -122,10 +446,6 @@ FT_Memory memory = render->root.memory; FT_Pos x_shift = 0; FT_Pos y_shift = 0; - FT_Int hmul = ( mode == FT_RENDER_MODE_LCD ); - FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V ); - - FT_Raster_Params params; /* check glyph image format */ @@ -136,7 +456,10 @@ } /* check mode */ - if ( mode != required_mode ) + if ( mode != FT_RENDER_MODE_NORMAL && + mode != FT_RENDER_MODE_LIGHT && + mode != FT_RENDER_MODE_LCD && + mode != FT_RENDER_MODE_LCD_V ) { error = FT_THROW( Cannot_Render_Glyph ); goto Exit; @@ -155,6 +478,9 @@ goto Exit; } + if ( !bitmap->rows || !bitmap->pitch ) + goto Exit; + /* allocate new one */ if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) goto Exit; @@ -178,188 +504,57 @@ if ( x_shift || y_shift ) FT_Outline_Translate( outline, x_shift, y_shift ); - /* set up parameters */ - params.target = bitmap; - params.source = outline; - params.flags = FT_RASTER_FLAG_AA; + if ( mode == FT_RENDER_MODE_NORMAL || + mode == FT_RENDER_MODE_LIGHT ) + { + if ( outline->flags & FT_OUTLINE_OVERLAP ) + error = ft_smooth_raster_overlap( render, outline, bitmap ); + else + { + FT_Raster_Params params; + + + params.target = bitmap; + params.source = outline; + params.flags = FT_RASTER_FLAG_AA; + + error = render->raster_render( render->raster, ¶ms ); + } + } + else + { + if ( mode == FT_RENDER_MODE_LCD ) + error = ft_smooth_raster_lcd ( render, outline, bitmap ); + else if ( mode == FT_RENDER_MODE_LCD_V ) + error = ft_smooth_raster_lcdv( render, outline, bitmap ); #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 ( error ) - goto Exit; - - /* finally apply filtering */ - if ( hmul || vmul ) - { - FT_Byte* lcd_weights; - FT_Bitmap_LcdFilterFunc lcd_filter_func; - - - /* Per-face LCD filtering takes priority if set up. */ - if ( slot->face && slot->face->internal->lcd_filter_func ) + /* finally apply filtering */ { - lcd_weights = slot->face->internal->lcd_weights; - lcd_filter_func = slot->face->internal->lcd_filter_func; - } - else - { - lcd_weights = slot->library->lcd_weights; - lcd_filter_func = slot->library->lcd_filter_func; - } - - if ( lcd_filter_func ) - lcd_filter_func( bitmap, lcd_weights ); - } - -#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ - - if ( hmul ) /* lcd */ - { - FT_Byte* line; - FT_Byte* temp = NULL; - FT_UInt i, j; - - unsigned int height = bitmap->rows; - unsigned int width = bitmap->width; - int pitch = bitmap->pitch; - - FT_Vector* sub = slot->library->lcd_geometry; + FT_Byte* lcd_weights; + FT_Bitmap_LcdFilterFunc lcd_filter_func; - /* Render 3 separate monochrome bitmaps, shifting the outline. */ - width /= 3; - - FT_Outline_Translate( outline, - -sub[0].x, - -sub[0].y ); - error = render->raster_render( render->raster, ¶ms ); - if ( error ) - goto Exit; - - bitmap->buffer += width; - FT_Outline_Translate( outline, - sub[0].x - sub[1].x, - sub[0].y - sub[1].y ); - error = render->raster_render( render->raster, ¶ms ); - bitmap->buffer -= width; - if ( error ) - goto Exit; - - bitmap->buffer += 2 * width; - FT_Outline_Translate( outline, - sub[1].x - sub[2].x, - sub[1].y - sub[2].y ); - error = render->raster_render( render->raster, ¶ms ); - bitmap->buffer -= 2 * width; - if ( error ) - goto Exit; - - x_shift -= sub[2].x; - y_shift -= sub[2].y; - - /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */ - /* XXX: It is more efficient to render every third byte above. */ - - if ( FT_ALLOC( temp, (FT_ULong)pitch ) ) - goto Exit; - - for ( i = 0; i < height; i++ ) - { - line = bitmap->buffer + i * (FT_ULong)pitch; - for ( j = 0; j < width; j++ ) + /* Per-face LCD filtering takes priority if set up. */ + if ( slot->face && slot->face->internal->lcd_filter_func ) { - temp[3 * j ] = line[j]; - temp[3 * j + 1] = line[j + width]; - temp[3 * j + 2] = line[j + width + width]; + lcd_weights = slot->face->internal->lcd_weights; + lcd_filter_func = slot->face->internal->lcd_filter_func; } - FT_MEM_COPY( line, temp, pitch ); + else + { + lcd_weights = slot->library->lcd_weights; + lcd_filter_func = slot->library->lcd_filter_func; + } + + if ( lcd_filter_func ) + lcd_filter_func( bitmap, lcd_weights ); } - FT_FREE( temp ); +#endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + } - else if ( vmul ) /* lcd_v */ - { - int pitch = bitmap->pitch; - - FT_Vector* sub = slot->library->lcd_geometry; - - - /* Render 3 separate monochrome bitmaps, shifting the outline. */ - /* Notice that the subpixel geometry vectors are rotated. */ - /* Triple the pitch to render on each third row. */ - bitmap->pitch *= 3; - bitmap->rows /= 3; - - FT_Outline_Translate( outline, - -sub[0].y, - sub[0].x ); - error = render->raster_render( render->raster, ¶ms ); - if ( error ) - goto Exit; - - bitmap->buffer += pitch; - FT_Outline_Translate( outline, - sub[0].y - sub[1].y, - sub[1].x - sub[0].x ); - error = render->raster_render( render->raster, ¶ms ); - bitmap->buffer -= pitch; - if ( error ) - goto Exit; - - bitmap->buffer += 2 * pitch; - FT_Outline_Translate( outline, - sub[1].y - sub[2].y, - sub[2].x - sub[1].x ); - error = render->raster_render( render->raster, ¶ms ); - bitmap->buffer -= 2 * pitch; - if ( error ) - goto Exit; - - x_shift -= sub[2].y; - y_shift += sub[2].x; - - bitmap->pitch /= 3; - bitmap->rows *= 3; - } - else /* grayscale */ - error = render->raster_render( render->raster, ¶ms ); - -#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ Exit: if ( !error ) @@ -380,45 +575,6 @@ } - /* 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 ) - { - return ft_smooth_render_generic( render, slot, mode, origin, - FT_RENDER_MODE_LCD ); - } - - - /* 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 ) - { - return ft_smooth_render_generic( render, slot, mode, origin, - FT_RENDER_MODE_LCD_V ); - } - - FT_DEFINE_RENDERER( ft_smooth_renderer_class, @@ -446,58 +602,4 @@ ) - FT_DEFINE_RENDERER( - ft_smooth_lcd_renderer_class, - - FT_MODULE_RENDERER, - sizeof ( FT_RendererRec ), - - "smooth-lcd", - 0x10000L, - 0x20000L, - - NULL, /* module specific interface */ - - (FT_Module_Constructor)ft_smooth_init, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) NULL, /* get_interface */ - - FT_GLYPH_FORMAT_OUTLINE, - - (FT_Renderer_RenderFunc) ft_smooth_render_lcd, /* render_glyph */ - (FT_Renderer_TransformFunc)ft_smooth_transform, /* transform_glyph */ - (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ - (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ - - (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ - ) - - - FT_DEFINE_RENDERER( - ft_smooth_lcdv_renderer_class, - - FT_MODULE_RENDERER, - sizeof ( FT_RendererRec ), - - "smooth-lcdv", - 0x10000L, - 0x20000L, - - NULL, /* module specific interface */ - - (FT_Module_Constructor)ft_smooth_init, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) NULL, /* get_interface */ - - FT_GLYPH_FORMAT_OUTLINE, - - (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v, /* render_glyph */ - (FT_Renderer_TransformFunc)ft_smooth_transform, /* transform_glyph */ - (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ - (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ - - (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ - ) - - /* END */ diff --git a/src/thirdparty/freetype2/src/smooth/ftsmooth.h b/src/thirdparty/freetype2/src/smooth/ftsmooth.h index fbb21a31d..f76708ae7 100644 --- a/src/thirdparty/freetype2/src/smooth/ftsmooth.h +++ b/src/thirdparty/freetype2/src/smooth/ftsmooth.h @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define FTSMOOTH_H_ -#include -#include FT_RENDER_H +#include FT_BEGIN_HEADER @@ -29,10 +28,6 @@ FT_BEGIN_HEADER FT_DECLARE_RENDERER( ft_smooth_renderer_class ) - FT_DECLARE_RENDERER( ft_smooth_lcd_renderer_class ) - - FT_DECLARE_RENDERER( ft_smooth_lcdv_renderer_class ) - FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/svg/ftsvg.c b/src/thirdparty/freetype2/src/svg/ftsvg.c new file mode 100644 index 000000000..8e73c3ba4 --- /dev/null +++ b/src/thirdparty/freetype2/src/svg/ftsvg.c @@ -0,0 +1,355 @@ +/**************************************************************************** + * + * ftsvg.c + * + * The FreeType SVG renderer interface (body). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 +#include +#include +#include +#include + +#include "ftsvg.h" +#include "svgtypes.h" + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT otsvg + + +#ifdef FT_CONFIG_OPTION_SVG + + /* ft_svg_init */ + static FT_Error + ft_svg_init( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + FT_Error error = FT_Err_Ok; + + + render->loaded = FALSE; + render->hooks_set = FALSE; + + return error; + } + + + static void + ft_svg_done( FT_Module module ) + { + SVG_Renderer render = (SVG_Renderer)module; + + + if ( render->loaded == TRUE && + render->hooks_set == TRUE ) + render->hooks.free_svg( &render->state ); + + render->loaded = FALSE; + } + + + static FT_Error + ft_svg_preset_slot( FT_Module module, + FT_GlyphSlot slot, + FT_Bool cache ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)module; + SVG_RendererHooks hooks = svg_renderer->hooks; + + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_preset_slot: first presetting call," + " calling init hook\n" )); + hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + return hooks.preset_slot( slot, cache, &svg_renderer->state ); + } + + + static FT_Error + ft_svg_render( FT_Renderer renderer, + FT_GlyphSlot slot, + FT_Render_Mode mode, + const FT_Vector* origin ) + { + SVG_Renderer svg_renderer = (SVG_Renderer)renderer; + + FT_Library library = renderer->root.library; + FT_Memory memory = library->memory; + FT_Error error; + + FT_ULong size_image_buffer; + + SVG_RendererHooks hooks = svg_renderer->hooks; + + + FT_UNUSED( mode ); + FT_UNUSED( origin ); + + if ( mode != FT_RENDER_MODE_NORMAL ) + return FT_THROW( Bad_Argument ); + + if ( svg_renderer->hooks_set == FALSE ) + { + FT_TRACE1(( "Hooks are NOT set. Can't render OT-SVG glyphs\n" )); + return FT_THROW( Missing_SVG_Hooks ); + } + + if ( svg_renderer->loaded == FALSE ) + { + FT_TRACE3(( "ft_svg_render: first rendering, calling init hook\n" )); + error = hooks.init_svg( &svg_renderer->state ); + + svg_renderer->loaded = TRUE; + } + + ft_svg_preset_slot( (FT_Module)renderer, slot, TRUE ); + + size_image_buffer = (FT_ULong)slot->bitmap.pitch * slot->bitmap.rows; + /* No `FT_QALLOC` here since we need a clean, empty canvas */ + /* to start with. */ + if ( FT_ALLOC( slot->bitmap.buffer, size_image_buffer ) ) + return error; + + error = hooks.render_svg( slot, &svg_renderer->state ); + if ( error ) + FT_FREE( slot->bitmap.buffer ); + else + slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + return error; + } + + + static const SVG_Interface svg_interface = + { + ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */ + }; + + + static FT_Error + ft_svg_property_set( FT_Module module, + const char* property_name, + const void* value, + FT_Bool value_is_string ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks; + + + if ( value_is_string == TRUE ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + hooks = (SVG_RendererHooks*)value; + + if ( !hooks->init_svg || + !hooks->free_svg || + !hooks->render_svg || + !hooks->preset_slot ) + { + FT_TRACE0(( "ft_svg_property_set:" + " SVG rendering hooks not set because\n" )); + FT_TRACE0(( " " + " at least one function pointer is NULL\n" )); + + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + + renderer->hooks = *hooks; + renderer->hooks_set = TRUE; + } + else + error = FT_THROW( Missing_Property ); + + Exit: + return error; + } + + + static FT_Error + ft_svg_property_get( FT_Module module, + const char* property_name, + void* value ) + { + FT_Error error = FT_Err_Ok; + SVG_Renderer renderer = (SVG_Renderer)module; + + + if ( !ft_strcmp( property_name, "svg-hooks" ) ) + { + SVG_RendererHooks* hooks = (SVG_RendererHooks*)value; + + + *hooks = renderer->hooks; + } + else + error = FT_THROW( Missing_Property ); + + return error; + } + + + FT_DEFINE_SERVICE_PROPERTIESREC( + ft_svg_service_properties, + + ft_svg_property_set, /* FT_Properties_SetFunc set_property */ + ft_svg_property_get /* FT_Properties_GetFunc get_property */ + ) + + + FT_DEFINE_SERVICEDESCREC1( + ft_svg_services, + FT_SERVICE_ID_PROPERTIES, &ft_svg_service_properties ) + + + FT_CALLBACK_DEF( FT_Module_Interface ) + ft_svg_get_interface( FT_Module module, + const char* ft_svg_interface ) + { + FT_Module_Interface result; + + + FT_UNUSED( module ); + + result = ft_service_list_lookup( ft_svg_services, ft_svg_interface ); + if ( result ) + return result; + + return 0; + } + + + static FT_Error + ft_svg_transform( FT_Renderer renderer, + FT_GlyphSlot slot, + const FT_Matrix* _matrix, + const FT_Vector* _delta ) + { + FT_SVG_Document doc = (FT_SVG_Document)slot->other; + FT_Matrix* matrix = (FT_Matrix*)_matrix; + FT_Vector* delta = (FT_Vector*)_delta; + + FT_Matrix tmp_matrix; + FT_Vector tmp_delta; + + FT_Matrix a, b; + FT_Pos x, y; + + + FT_UNUSED( renderer ); + + if ( !matrix ) + { + tmp_matrix.xx = 0x10000; + tmp_matrix.xy = 0; + tmp_matrix.yx = 0; + tmp_matrix.yy = 0x10000; + + matrix = &tmp_matrix; + } + + if ( !delta ) + { + tmp_delta.x = 0; + tmp_delta.y = 0; + + delta = &tmp_delta; + } + + a = doc->transform; + b = *matrix; + FT_Matrix_Multiply( &b, &a ); + + + x = ADD_LONG( ADD_LONG( FT_MulFix( matrix->xx, doc->delta.x ), + FT_MulFix( matrix->xy, doc->delta.y ) ), + delta->x ); + y = ADD_LONG( ADD_LONG( FT_MulFix( matrix->yx, doc->delta.x ), + FT_MulFix( matrix->yy, doc->delta.y ) ), + delta->y ); + + doc->delta.x = x; + doc->delta.y = y; + doc->transform = a; + + return FT_Err_Ok; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + + +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_MODULE( a ) a +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_SVG +#else +#define PUT_SVG_MODULE( a ) NULL +#define SVG_GLYPH_FORMAT FT_GLYPH_FORMAT_NONE +#endif + + + FT_DEFINE_RENDERER( + ft_svg_renderer_class, + + FT_MODULE_RENDERER, + sizeof ( SVG_RendererRec ), + + "ot-svg", + 0x10000L, + 0x20000L, + + (const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */ + + PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */ + PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */ + PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */ + + SVG_GLYPH_FORMAT, + + PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */ + PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */ + NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */ + NULL, /* FT_Renderer_SetModeFunc set_mode */ + NULL /* FT_Raster_Funcs* raster_class */ + ) + + +/* END */ diff --git a/src/thirdparty/freetype2/src/svg/ftsvg.h b/src/thirdparty/freetype2/src/svg/ftsvg.h new file mode 100644 index 000000000..b04c7fef1 --- /dev/null +++ b/src/thirdparty/freetype2/src/svg/ftsvg.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * + * ftsvg.h + * + * The FreeType SVG renderer interface (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 FTSVG_H_ +#define FTSVG_H_ + +#include +#include +#include + + +FT_BEGIN_HEADER + + FT_DECLARE_RENDERER( ft_svg_renderer_class ) + +FT_END_HEADER + +#endif /* FTSVG_H_ */ + + +/* END */ diff --git a/src/thirdparty/freetype2/src/svg/svgtypes.h b/src/thirdparty/freetype2/src/svg/svgtypes.h new file mode 100644 index 000000000..65b3eacb6 --- /dev/null +++ b/src/thirdparty/freetype2/src/svg/svgtypes.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * svgtypes.h + * + * The FreeType SVG renderer internal types (specification). + * + * Copyright (C) 2022-2025 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.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 SVGTYPES_H_ +#define SVGTYPES_H_ + +#include +#include +#include +#include + + + typedef struct SVG_RendererRec_ + { + FT_RendererRec root; /* this inherits FT_RendererRec */ + FT_Bool loaded; + FT_Bool hooks_set; + SVG_RendererHooks hooks; /* this holds hooks for SVG rendering */ + FT_Pointer state; /* a place for hooks to store state, if needed */ + + } SVG_RendererRec; + + typedef struct SVG_RendererRec_* SVG_Renderer; + +#endif /* SVGTYPES_H_ */ + + +/* EOF */ diff --git a/src/thirdparty/freetype2/src/truetype/ttdriver.c b/src/thirdparty/freetype2/src/truetype/ttdriver.c index ff626d53a..6369d83d6 100644 --- a/src/thirdparty/freetype2/src/truetype/ttdriver.c +++ b/src/thirdparty/freetype2/src/truetype/ttdriver.c @@ -4,7 +4,7 @@ * * TrueType font driver implementation (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,22 +16,21 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_SFNT_H -#include FT_SERVICE_FONT_FORMAT_H +#include +#include +#include +#include #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT -#include FT_MULTIPLE_MASTERS_H -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_METRICS_VARIATIONS_H +#include +#include +#include #endif -#include FT_SERVICE_TRUETYPE_ENGINE_H -#include FT_SERVICE_TRUETYPE_GLYF_H -#include FT_SERVICE_PROPERTIES_H -#include FT_DRIVER_H +#include +#include +#include +#include #include "ttdriver.h" #include "ttgload.h" @@ -58,7 +57,7 @@ * PROPERTY SERVICE * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) tt_property_set( FT_Module module, /* TT_Driver */ const char* property_name, const void* value, @@ -94,31 +93,36 @@ interpreter_version = *iv; } - if ( interpreter_version == TT_INTERPRETER_VERSION_35 -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - || interpreter_version == TT_INTERPRETER_VERSION_38 -#endif + switch ( interpreter_version ) + { + case TT_INTERPRETER_VERSION_35: + driver->interpreter_version = TT_INTERPRETER_VERSION_35; + break; + + case TT_INTERPRETER_VERSION_38: + case TT_INTERPRETER_VERSION_40: #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - || interpreter_version == TT_INTERPRETER_VERSION_40 + driver->interpreter_version = TT_INTERPRETER_VERSION_40; + break; #endif - ) - driver->interpreter_version = interpreter_version; - else + + default: error = FT_ERR( Unimplemented_Feature ); + } return error; } - FT_TRACE0(( "tt_property_set: missing property `%s'\n", + FT_TRACE2(( "tt_property_set: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } - static FT_Error + FT_CALLBACK_DEF( FT_Error ) tt_property_get( FT_Module module, /* TT_Driver */ const char* property_name, - const void* value ) + void* value ) { FT_Error error = FT_Err_Ok; TT_Driver driver = (TT_Driver)module; @@ -136,7 +140,7 @@ return error; } - FT_TRACE0(( "tt_property_get: missing property `%s'\n", + FT_TRACE2(( "tt_property_get: missing property `%s'\n", property_name )); return FT_THROW( Missing_Property ); } @@ -145,8 +149,8 @@ FT_DEFINE_SERVICE_PROPERTIESREC( tt_service_properties, - (FT_Properties_SetFunc)tt_property_set, /* set_property */ - (FT_Properties_GetFunc)tt_property_get /* get_property */ + tt_property_set, /* FT_Properties_SetFunc set_property */ + tt_property_get /* FT_Properties_GetFunc get_property */ ) @@ -199,35 +203,48 @@ * * They can be implemented by format-specific interfaces. */ - static FT_Error - tt_get_kerning( FT_Face ttface, /* TT_Face */ + FT_CALLBACK_DEF( FT_Error ) + tt_get_kerning( FT_Face face, /* 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; + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; kerning->x = 0; kerning->y = 0; if ( sfnt ) - kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph ); + { + /* Use 'kern' table if available since that can be faster; otherwise */ + /* use GPOS kerning pairs if available. */ + if ( ttface->kern_avail_bits ) + kerning->x = sfnt->get_kerning( ttface, + left_glyph, + right_glyph ); +#ifdef TT_CONFIG_OPTION_GPOS_KERNING + else if ( ttface->num_gpos_lookups_kerning ) + kerning->x = sfnt->get_gpos_kerning( ttface, + left_glyph, + right_glyph ); +#endif + } return 0; } - static FT_Error - tt_get_advances( FT_Face ttface, + FT_CALLBACK_DEF( FT_Error ) + tt_get_advances( FT_Face face, /* TT_Face */ FT_UInt start, FT_UInt count, FT_Int32 flags, FT_Fixed *advances ) { FT_UInt nn; - TT_Face face = (TT_Face)ttface; + TT_Face ttface = (TT_Face)face; /* XXX: TODO: check for sbits */ @@ -236,8 +253,8 @@ { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* no fast retrieval for blended MM fonts without VVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) && - !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) return FT_THROW( Unimplemented_Feature ); #endif @@ -248,7 +265,7 @@ /* since we don't need `tsb', we use zero for `yMax' parameter */ - TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah ); + TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah ); advances[nn] = ah; } } @@ -256,8 +273,8 @@ { #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* no fast retrieval for blended MM fonts without HVAR table */ - if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) && - !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) && + !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) return FT_THROW( Unimplemented_Feature ); #endif @@ -267,7 +284,7 @@ FT_UShort aw; - TT_Get_HMetrics( face, start + nn, &lsb, &aw ); + TT_Get_HMetrics( ttface, start + nn, &lsb, &aw ); advances[nn] = aw; } } @@ -291,7 +308,7 @@ #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS - static FT_Error + FT_CALLBACK_DEF( FT_Error ) tt_size_select( FT_Size size, FT_ULong strike_index ) { @@ -307,7 +324,7 @@ /* use the scaled metrics, even when tt_size_reset fails */ FT_Select_Metrics( size->face, strike_index ); - tt_size_reset( ttsize, 0 ); /* ignore return value */ + tt_size_reset( ttsize ); /* ignore return value */ } else { @@ -328,7 +345,7 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) tt_size_request( FT_Size size, FT_Size_Request req ) { @@ -355,11 +372,20 @@ #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ - FT_Request_Metrics( size->face, req ); + { + FT_Error err = FT_Request_Metrics( size->face, req ); + + + if ( err ) + { + error = err; + goto Exit; + } + } if ( FT_IS_SCALABLE( size->face ) ) { - error = tt_size_reset( ttsize, 0 ); + error = tt_size_reset( ttsize ); #ifdef TT_USE_BYTECODE_INTERPRETER /* for the `MPS' bytecode instruction we need the point size */ @@ -383,6 +409,7 @@ #endif } + Exit: return error; } @@ -417,15 +444,15 @@ * @Return: * FreeType error code. 0 means success. */ - static FT_Error - tt_glyph_load( FT_GlyphSlot ttslot, /* TT_GlyphSlot */ - FT_Size ttsize, /* TT_Size */ + FT_CALLBACK_DEF( FT_Error ) + tt_glyph_load( FT_GlyphSlot slot, /* TT_GlyphSlot */ + FT_Size size, /* 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; + TT_GlyphSlot ttslot = (TT_GlyphSlot)slot; + TT_Size ttsize = (TT_Size)size; + FT_Face face = ttslot->face; FT_Error error; @@ -467,12 +494,12 @@ } /* use hinted metrics only if we load a glyph with hinting */ - size->metrics = ( load_flags & FT_LOAD_NO_HINTING ) - ? &ttsize->metrics - : &size->hinted_metrics; + ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING ) + ? &size->metrics + : &ttsize->hinted_metrics; /* now fill in the glyph slot with outline/bitmap/layered */ - error = TT_Load_Glyph( size, slot, glyph_index, load_flags ); + error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags ); /* force drop-out mode to 2 - irrelevant now */ /* slot->outline.dropout_mode = 2; */ @@ -498,34 +525,47 @@ FT_DEFINE_SERVICE_MULTIMASTERSREC( tt_service_gx_multi_masters, - (FT_Get_MM_Func) NULL, /* get_mm */ - (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ - (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */ - (FT_Set_Var_Design_Func) TT_Set_Var_Design, /* set_var_design */ - (FT_Get_Var_Design_Func) TT_Get_Var_Design, /* get_var_design */ - (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */ - (FT_Set_MM_WeightVector_Func)NULL, /* set_mm_weightvector */ - (FT_Get_MM_WeightVector_Func)NULL, /* get_mm_weightvector */ + NULL, /* FT_Get_MM_Func get_mm */ + NULL, /* FT_Set_MM_Design_Func set_mm_design */ + TT_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + TT_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + TT_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + TT_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + TT_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func set_named_instance */ + TT_Get_Default_Named_Instance, + /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + NULL, /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + NULL, /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ - (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */ - (FT_Done_Blend_Func) tt_done_blend /* done_blend */ + tt_construct_ps_name, /* FT_Construct_PS_Name_Func construct_ps_name */ + tt_var_load_delta_set_index_mapping, + /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + tt_var_load_item_variation_store, + /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + tt_var_done_item_variation_store, + /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + tt_var_done_delta_set_index_map, + /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + tt_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */ + tt_done_blend /* FT_Done_Blend_Func done_blend */ ) FT_DEFINE_SERVICE_METRICSVARIATIONSREC( tt_service_metrics_variations, - (FT_HAdvance_Adjust_Func)tt_hadvance_adjust, /* hadvance_adjust */ - (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */ - (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */ + tt_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */ + NULL, /* FT_LSB_Adjust_Func lsb_adjust */ + NULL, /* FT_RSB_Adjust_Func rsb_adjust */ - (FT_VAdvance_Adjust_Func)tt_vadvance_adjust, /* vadvance_adjust */ - (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */ - (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */ - (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */ + tt_vadvance_adjust, /* FT_VAdvance_Adjust_Func vadvance_adjust */ + NULL, /* FT_TSB_Adjust_Func tsb_adjust */ + NULL, /* FT_BSB_Adjust_Func bsb_adjust */ + NULL, /* FT_VOrg_Adjust_Func vorg_adjust */ - (FT_Metrics_Adjust_Func) tt_apply_mvar /* metrics_adjust */ + tt_apply_mvar, /* FT_Metrics_Adjust_Func metrics_adjust */ + tt_size_reset_height /* FT_Size_Reset_Func size_reset */ ) #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ diff --git a/src/thirdparty/freetype2/src/truetype/ttdriver.h b/src/thirdparty/freetype2/src/truetype/ttdriver.h index 3936c6a4d..943eaae34 100644 --- a/src/thirdparty/freetype2/src/truetype/ttdriver.h +++ b/src/thirdparty/freetype2/src/truetype/ttdriver.h @@ -4,7 +4,7 @@ * * High-level TrueType driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define TTDRIVER_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/truetype/tterrors.h b/src/thirdparty/freetype2/src/truetype/tterrors.h index 5609d28d6..631dbf5a8 100644 --- a/src/thirdparty/freetype2/src/truetype/tterrors.h +++ b/src/thirdparty/freetype2/src/truetype/tterrors.h @@ -4,7 +4,7 @@ * * TrueType error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef TTERRORS_H_ #define TTERRORS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX TT_Err_ #define FT_ERR_BASE FT_Mod_Err_TrueType -#include FT_ERRORS_H +#include #endif /* TTERRORS_H_ */ diff --git a/src/thirdparty/freetype2/src/truetype/ttgload.c b/src/thirdparty/freetype2/src/truetype/ttgload.c index a04684086..e810ebfd5 100644 --- a/src/thirdparty/freetype2/src/truetype/ttgload.c +++ b/src/thirdparty/freetype2/src/truetype/ttgload.c @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,15 +17,15 @@ #include -#include FT_INTERNAL_DEBUG_H +#include #include FT_CONFIG_CONFIG_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 FT_DRIVER_H -#include FT_LIST_H +#include +#include +#include +#include +#include +#include +#include #include "ttgload.h" #include "ttpload.h" @@ -35,7 +35,6 @@ #endif #include "tterrors.h" -#include "ttsubpix.h" /************************************************************************** @@ -60,7 +59,7 @@ #define SAME_X 0x10 #define Y_POSITIVE 0x20 /* two meanings depending on Y_SHORT_VECTOR */ #define SAME_Y 0x20 -#define OVERLAP_SIMPLE 0x40 /* we ignore this value */ +#define OVERLAP_SIMPLE 0x40 /* retained as FT_OUTLINE_OVERLAP */ /************************************************************************** @@ -77,7 +76,7 @@ #define WE_HAVE_A_2X2 0x0080 #define WE_HAVE_INSTR 0x0100 #define USE_MY_METRICS 0x0200 -#define OVERLAP_COMPOUND 0x0400 /* we ignore this value */ +#define OVERLAP_COMPOUND 0x0400 /* retained as FT_OUTLINE_OVERLAP */ #define SCALED_COMPONENT_OFFSET 0x0800 #define UNSCALED_COMPONENT_OFFSET 0x1000 @@ -137,6 +136,11 @@ face->horizontal.Descender ); } +#ifdef FT_DEBUG_LEVEL_TRACE + if ( !face->vertical_info ) + FT_TRACE5(( " [vertical metrics missing, computing values]\n" )); +#endif + FT_TRACE5(( " advance height (font units): %d\n", *ah )); FT_TRACE5(( " top side bearing (font units): %d\n", *tsb )); } @@ -147,9 +151,6 @@ FT_UInt glyph_index ) { TT_Face face = loader->face; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); -#endif FT_Error error; FT_Stream stream = loader->stream; @@ -178,24 +179,17 @@ loader->top_bearing = top_bearing; loader->vadvance = advance_height; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && - loader->exec ) +#ifdef FT_CONFIG_OPTION_INCREMENTAL + /* With the incremental interface, these values are set by */ + /* a call to `tt_get_metrics_incremental'. */ + if ( face->root.internal->incremental_interface == NULL ) +#endif { - loader->exec->sph_tweak_flags = 0; - - /* This may not be the right place for this, but it works... */ - /* Note that we have to unconditionally load the tweaks since */ - /* it is possible that glyphs individually switch ClearType's */ - /* backward compatibility mode on and off. */ - sph_set_tweaks( loader, glyph_index ); - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - if ( !loader->linear_def ) - { - loader->linear_def = 1; - loader->linear = advance_width; + if ( !loader->linear_def ) + { + loader->linear_def = 1; + loader->linear = advance_width; + } } return FT_Err_Ok; @@ -205,8 +199,8 @@ #ifdef FT_CONFIG_OPTION_INCREMENTAL static void - tt_get_metrics_incr_overrides( TT_Loader loader, - FT_UInt glyph_index ) + tt_get_metrics_incremental( TT_Loader loader, + FT_UInt glyph_index ) { TT_Face face = loader->face; @@ -333,9 +327,9 @@ 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, + FT_TRACE5(( " xMin: %4ld xMax: %4ld\n", loader->bbox.xMin, loader->bbox.xMax )); - FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, + FT_TRACE5(( " yMin: %4ld yMax: %4ld\n", loader->bbox.yMin, loader->bbox.yMax )); loader->cursor = p; @@ -350,17 +344,17 @@ FT_Byte* p = load->cursor; FT_Byte* limit = load->limit; FT_GlyphLoader gloader = load->gloader; + FT_Outline* outline = &gloader->current.outline; FT_Int n_contours = load->n_contours; - FT_Outline* outline; - FT_UShort n_ins; FT_Int n_points; + FT_UShort n_ins; FT_Byte *flag, *flag_limit; FT_Byte c, count; FT_Vector *vec, *vec_limit; FT_Pos x, y; - FT_Short *cont, *cont_limit, prev_cont; - FT_Int xy_size = 0; + FT_UShort *cont, *cont_limit; + FT_Int last; /* check that we can add the contours to the glyph */ @@ -368,40 +362,26 @@ if ( error ) goto Fail; + /* check space for contours array + instructions count */ + if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit ) + goto Invalid_Outline; + /* reading the contours' endpoints & number of points */ - cont = gloader->current.outline.contours; + cont = 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; - - prev_cont = FT_NEXT_SHORT( p ); - - if ( n_contours > 0 ) - cont[0] = prev_cont; - - if ( prev_cont < 0 ) - goto Invalid_Outline; - - for ( cont++; cont < cont_limit; cont++ ) + last = -1; + for ( ; cont < cont_limit; cont++ ) { - cont[0] = FT_NEXT_SHORT( p ); - if ( cont[0] <= prev_cont ) - { - /* unordered contours: this is invalid */ + *cont = FT_NEXT_USHORT( p ); + + if ( *cont <= last ) goto Invalid_Outline; - } - prev_cont = cont[0]; + + last = *cont; } - n_points = 0; - if ( n_contours > 0 ) - { - n_points = cont[-1] + 1; - if ( n_points < 0 ) - goto Invalid_Outline; - } + n_points = last + 1; FT_TRACE5(( " # of points: %d\n", n_points )); @@ -410,61 +390,48 @@ if ( error ) goto Fail; - /* reading the bytecode instructions */ - load->glyph->control_len = 0; - load->glyph->control_data = NULL; - - if ( p + 2 > limit ) - goto Invalid_Outline; - + /* space checked above */ n_ins = FT_NEXT_USHORT( p ); FT_TRACE5(( " Instructions size: %u\n", n_ins )); + /* check instructions size */ + if ( p + n_ins > limit ) + { + FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" )); + error = FT_THROW( Too_Many_Hints ); + goto Fail; + } + #ifdef TT_USE_BYTECODE_INTERPRETER if ( IS_HINTED( load->load_flags ) ) { - FT_ULong tmp; + TT_ExecContext exec = load->exec; + FT_Memory memory = exec->memory; - /* check instructions size */ - if ( ( limit - p ) < n_ins ) - { - FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" )); - error = FT_THROW( Too_Many_Hints ); - goto Fail; - } + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; /* we don't trust `maxSizeOfInstructions' in the `maxp' table */ - /* and thus update the bytecode array size by ourselves */ - - tmp = load->exec->glyphSize; - error = Update_Max( load->exec->memory, - &tmp, - sizeof ( FT_Byte ), - (void*)&load->exec->glyphIns, - n_ins ); - - load->exec->glyphSize = (FT_UShort)tmp; - if ( error ) - return error; - - load->glyph->control_len = n_ins; - load->glyph->control_data = load->exec->glyphIns; - + /* and thus allocate the bytecode array size by ourselves */ if ( n_ins ) - FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins ); + { + if ( FT_DUP( exec->glyphIns, p, n_ins ) ) + return error; + + exec->glyphSize = n_ins; + } } #endif /* TT_USE_BYTECODE_INTERPRETER */ p += n_ins; - outline = &gloader->current.outline; - /* reading the point tags */ - flag = (FT_Byte*)outline->tags; + flag = outline->tags; flag_limit = flag + n_points; FT_ASSERT( flag ); @@ -489,16 +456,17 @@ } } + /* retain the overlap flag */ + if ( n_points && outline->tags[0] & OVERLAP_SIMPLE ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; + /* reading the X coordinates */ vec = outline->points; vec_limit = vec + n_points; - flag = (FT_Byte*)outline->tags; + flag = outline->tags; x = 0; - if ( p + xy_size > limit ) - goto Invalid_Outline; - for ( ; vec < vec_limit; vec++, flag++ ) { FT_Pos delta = 0; @@ -528,9 +496,9 @@ /* reading the Y coordinates */ - vec = gloader->current.outline.points; + vec = outline->points; vec_limit = vec + n_points; - flag = (FT_Byte*)outline->tags; + flag = outline->tags; y = 0; for ( ; vec < vec_limit; vec++, flag++ ) @@ -563,8 +531,8 @@ *flag = (FT_Byte)( f & ON_CURVE_POINT ); } - outline->n_points = (FT_Short)n_points; - outline->n_contours = (FT_Short)n_contours; + outline->n_points = (FT_UShort)n_points; + outline->n_contours = (FT_UShort)n_contours; load->cursor = p; @@ -692,7 +660,7 @@ } while ( subglyph->flags & MORE_COMPONENTS ); gloader->current.num_subglyphs = num_subglyphs; - FT_TRACE5(( " %d component%s\n", + FT_TRACE5(( " %u component%s\n", num_subglyphs, num_subglyphs > 1 ? "s" : "" )); @@ -706,7 +674,7 @@ for ( i = 0; i < num_subglyphs; i++ ) { if ( num_subglyphs > 1 ) - FT_TRACE7(( " subglyph %d:\n", i )); + FT_TRACE7(( " subglyph %u:\n", i )); FT_TRACE7(( " glyph index: %d\n", subglyph->index )); @@ -721,18 +689,20 @@ if ( subglyph->flags & WE_HAVE_A_SCALE ) FT_TRACE7(( " scaling: %f\n", - subglyph->transform.xx / 65536.0 )); + (double)subglyph->transform.xx / 65536 )); else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE ) FT_TRACE7(( " scaling: x=%f, y=%f\n", - subglyph->transform.xx / 65536.0, - subglyph->transform.yy / 65536.0 )); + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yy / 65536 )); else if ( subglyph->flags & WE_HAVE_A_2X2 ) - FT_TRACE7(( " scaling: xx=%f, yx=%f\n" - " xy=%f, yy=%f\n", - subglyph->transform.xx / 65536.0, - subglyph->transform.yx / 65536.0, - subglyph->transform.xy / 65536.0, - subglyph->transform.yy / 65536.0 )); + { + FT_TRACE7(( " scaling: xx=%f, yx=%f\n", + (double)subglyph->transform.xx / 65536, + (double)subglyph->transform.yx / 65536 )); + FT_TRACE7(( " xy=%f, yy=%f\n", + (double)subglyph->transform.xy / 65536, + (double)subglyph->transform.yy / 65536 )); + } subglyph++; } @@ -783,15 +753,13 @@ FT_UInt start_point, FT_UInt start_contour ) { - zone->n_points = (FT_UShort)load->outline.n_points - - (FT_UShort)start_point; - zone->n_contours = load->outline.n_contours - - (FT_Short)start_contour; + zone->n_points = load->outline.n_points + 4 - (FT_UShort)start_point; + zone->n_contours = load->outline.n_contours - (FT_UShort)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->tags = load->outline.tags + start_point; + zone->contours = load->outline.contours + start_contour; zone->first_point = (FT_UShort)start_point; } @@ -809,44 +777,35 @@ TT_Hint_Glyph( TT_Loader loader, FT_Bool is_composite ) { -#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ - defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Face face = loader->face; - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); -#endif - TT_GlyphZone zone = &loader->zone; #ifdef TT_USE_BYTECODE_INTERPRETER - FT_Long n_ins; + TT_ExecContext exec = loader->exec; + TT_Size size = loader->size; + FT_Long n_ins = exec->glyphSize; #else FT_UNUSED( is_composite ); #endif #ifdef TT_USE_BYTECODE_INTERPRETER - n_ins = loader->glyph->control_len; - /* save original point positions in `org' array */ if ( n_ins > 0 ) FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points ); - /* Reset graphics state. */ - loader->exec->GS = loader->size->GS; - /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */ /* completely refer to the (already) hinted subglyphs. */ if ( is_composite ) { - loader->exec->metrics.x_scale = 1 << 16; - loader->exec->metrics.y_scale = 1 << 16; + exec->metrics.x_scale = 1 << 16; + exec->metrics.y_scale = 1 << 16; FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points ); } else { - loader->exec->metrics.x_scale = loader->size->metrics->x_scale; - loader->exec->metrics.y_scale = loader->size->metrics->y_scale; + exec->metrics.x_scale = size->metrics->x_scale; + exec->metrics.y_scale = size->metrics->y_scale; } #endif @@ -866,53 +825,36 @@ { FT_Error error; - FT_GlyphLoader gloader = loader->gloader; - FT_Outline current_outline = gloader->current.outline; + TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins ); - TT_Set_CodeRange( loader->exec, tt_coderange_glyph, - loader->exec->glyphIns, n_ins ); + exec->is_composite = is_composite; + exec->pts = *zone; - loader->exec->is_composite = is_composite; - loader->exec->pts = *zone; - - error = TT_Run_Context( loader->exec ); - if ( error && loader->exec->pedantic_hinting ) + error = TT_Run_Context( exec, size ); + if ( error && exec->pedantic_hinting ) return error; /* store drop-out mode in bits 5-7; set bit 2 also as a marker */ - current_outline.tags[0] |= - ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; + loader->gloader->current.outline.tags[0] |= + ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE; } #endif -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* Save possibly modified glyph phantom points unless in v40 backward */ /* compatibility mode, where no movement on the x axis means no reason */ /* to change bearings or advance widths. */ - if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - loader->exec->backward_compatibility ) ) - { -#endif - 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]; + #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - } + if ( exec->backward_compatibility ) + return FT_Err_Ok; #endif -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN ) - FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 ); - - else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN ) - FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 ); - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + 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 FT_Err_Ok; } @@ -931,10 +873,10 @@ static FT_Error TT_Process_Simple_Glyph( TT_Loader loader ) { - FT_GlyphLoader gloader = loader->gloader; - FT_Error error = FT_Err_Ok; - FT_Outline* outline; - FT_Int n_points; + FT_Error error = FT_Err_Ok; + FT_GlyphLoader gloader = loader->gloader; + FT_Outline* outline = &gloader->current.outline; + FT_Int n_points = outline->n_points; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Memory memory = loader->face->root.memory; @@ -942,49 +884,25 @@ #endif - 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 ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) { - if ( FT_NEW_ARRAY( unrounded, n_points ) ) + if ( FT_QNEW_ARRAY( unrounded, n_points ) ) goto Exit; /* Deltas apply to the unscaled data. */ - error = TT_Vary_Apply_Glyph_Deltas( loader->face, - loader->glyph_index, + error = TT_Vary_Apply_Glyph_Deltas( loader, outline, - unrounded, - (FT_UInt)n_points ); - - /* recalculate linear horizontal and vertical advances */ - /* if we don't have HVAR and VVAR, respectively */ - - /* XXX: change all FreeType modules to store `linear' and `vadvance' */ - /* in 26.6 format before the `base' module scales them to 16.16 */ - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x - - unrounded[n_points - 4].x ) / 64; - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].x - - unrounded[n_points - 2].x ) / 64; - + unrounded ); if ( error ) goto Exit; } @@ -996,20 +914,10 @@ tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 ); FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur, - loader->zone.n_points + 4 ); + loader->zone.n_points ); } { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - TT_Face face = loader->face; - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); - - FT_String* family = face->root.family_name; - FT_UInt ppem = loader->size->metrics->x_ppem; - FT_String* style = face->root.style_name; - FT_UInt x_scale_factor = 1000; -#endif - FT_Vector* vec = outline->points; FT_Vector* limit = outline->points + n_points; @@ -1019,52 +927,6 @@ FT_Bool do_scale = FALSE; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - /* scale, but only if enabled and only if TT hinting is being used */ - if ( IS_HINTED( loader->load_flags ) ) - x_scale_factor = sph_test_tweak_x_scaling( face, - family, - ppem, - style, - loader->glyph_index ); - /* scale the glyph */ - if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 || - x_scale_factor != 1000 ) - { - x_scale = FT_MulDiv( loader->size->metrics->x_scale, - (FT_Long)x_scale_factor, 1000 ); - y_scale = loader->size->metrics->y_scale; - - /* compensate for any scaling by de/emboldening; */ - /* the amount was determined via experimentation */ - if ( x_scale_factor != 1000 && ppem > 11 ) - { -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - FT_Vector* orig_points = outline->points; - - - if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) - outline->points = unrounded; -#endif - FT_Outline_EmboldenXY( outline, - FT_MulFix( 1280 * ppem, - 1000 - x_scale_factor ), - 0 ); -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) ) - outline->points = orig_points; -#endif - } - do_scale = TRUE; - } - } - else - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - { /* scale the glyph */ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ) @@ -1086,8 +948,8 @@ for ( ; vec < limit; vec++, u++ ) { - vec->x = ( FT_MulFix( u->x, x_scale ) + 32 ) >> 6; - vec->y = ( FT_MulFix( u->y, y_scale ) + 32 ) >> 6; + vec->x = ADD_LONG( FT_MulFix( u->x, x_scale ), 32 ) >> 6; + vec->y = ADD_LONG( FT_MulFix( u->y, y_scale ), 32 ) >> 6; } } else @@ -1102,9 +964,16 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* if we have a HVAR table, `pp1' and/or `pp2' are already adjusted */ - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) || - !IS_HINTED( loader->load_flags ) ) + /* if we have a HVAR table, `pp1' and/or `pp2' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + /* pp1.y and pp2.y are always zero */ + } + else #endif { loader->pp1 = outline->points[n_points - 4]; @@ -1112,9 +981,17 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - /* if we have a VVAR table, `pp3' and/or `pp4' are already adjusted */ - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) || - !IS_HINTED( loader->load_flags ) ) + /* if we have a VVAR table, `pp3' and/or `pp4' */ + /* are already adjusted but unscaled */ + if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) && + IS_HINTED( loader->load_flags ) ) + { + loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale ); + loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale ); + loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale ); + loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale ); + } + else #endif { loader->pp3 = outline->points[n_points - 2]; @@ -1123,11 +1000,7 @@ } if ( IS_HINTED( loader->load_flags ) ) - { - loader->zone.n_points += 4; - error = TT_Hint_Glyph( loader, 0 ); - } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT Exit: @@ -1162,7 +1035,7 @@ current.points = gloader->base.outline.points + num_base_points; current.n_points = gloader->base.outline.n_points - - (short)num_base_points; + (FT_UShort)num_base_points; have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE | WE_HAVE_AN_XY_SCALE | @@ -1175,7 +1048,7 @@ /* get offset */ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) ) { - FT_UInt num_points = (FT_UInt)gloader->base.outline.n_points; + FT_UInt num_points = gloader->base.outline.n_points; FT_UInt k = (FT_UInt)subglyph->arg1; FT_UInt l = (FT_UInt)subglyph->arg2; FT_Vector* p1; @@ -1195,8 +1068,8 @@ p1 = gloader->base.outline.points + k; p2 = gloader->base.outline.points + l; - x = p1->x - p2->x; - y = p1->y - p2->y; + x = SUB_LONG( p1->x, p2->x ); + y = SUB_LONG( p1->y, p2->y ); } else { @@ -1271,30 +1144,15 @@ x = FT_MulFix( x, x_scale ); y = FT_MulFix( y, y_scale ); - if ( subglyph->flags & ROUND_XY_TO_GRID ) + if ( subglyph->flags & ROUND_XY_TO_GRID && + IS_HINTED( loader->load_flags ) ) { - TT_Face face = loader->face; - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !loader->exec->backward_compatibility ) +#endif + x = FT_PIX_ROUND( x ); - - if ( IS_HINTED( loader->load_flags ) ) - { - /* - * We round the horizontal offset only if there is hinting along - * the x axis; this corresponds to integer advance width values. - * - * Theoretically, a glyph's bytecode can toggle ClearType's - * `backward compatibility' mode, which would allow modification - * of the advance width. In reality, however, applications - * neither allow nor expect modified advance widths if subpixel - * rendering is active. - * - */ - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 ) - x = FT_PIX_ROUND( x ); - - y = FT_PIX_ROUND( y ); - } + y = FT_PIX_ROUND( y ); } } } @@ -1322,12 +1180,10 @@ FT_UInt start_contour ) { FT_Error error; - FT_Outline* outline; + FT_Outline* outline = &loader->gloader->base.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, @@ -1340,60 +1196,45 @@ 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, max_ins; - FT_ULong tmp; + TT_ExecContext exec = loader->exec; + FT_Memory memory = exec->memory; + FT_Stream stream = loader->stream; + FT_UShort n_ins; + if ( exec->glyphSize ) + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; + /* 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 )); + FT_TRACE5(( " Instructions size = %hu\n", n_ins )); - /* check it */ - max_ins = loader->face->max_profile.maxSizeOfInstructions; - if ( n_ins > max_ins ) - { - /* don't trust `maxSizeOfInstructions'; */ - /* only do a rough safety check */ - if ( (FT_Int)n_ins > loader->byte_len ) - { - FT_TRACE1(( "TT_Process_Composite_Glyph:" - " too many instructions (%d) for glyph with length %d\n", - n_ins, loader->byte_len )); - return FT_THROW( Too_Many_Hints ); - } - - tmp = loader->exec->glyphSize; - error = Update_Max( loader->exec->memory, - &tmp, - sizeof ( FT_Byte ), - (void*)&loader->exec->glyphIns, - n_ins ); - - loader->exec->glyphSize = (FT_UShort)tmp; - if ( error ) - return error; - } - else if ( n_ins == 0 ) + if ( !n_ins ) return FT_Err_Ok; - if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) ) + /* don't trust `maxSizeOfInstructions'; */ + /* only do a rough safety check */ + if ( n_ins > loader->byte_len ) + { + FT_TRACE1(( "TT_Process_Composite_Glyph:" + " too many instructions (%hu) for glyph with length %u\n", + n_ins, loader->byte_len )); + return FT_THROW( Too_Many_Hints ); + } + + if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) || + FT_STREAM_READ( exec->glyphIns, n_ins ) ) return error; - loader->glyph->control_data = loader->exec->glyphIns; - loader->glyph->control_len = n_ins; + exec->glyphSize = n_ins; } #endif @@ -1403,11 +1244,9 @@ /* Some points are likely touched during execution of */ /* instructions on components. So let's untouch them. */ - for ( i = 0; i < loader->zone.n_points; i++ ) + for ( i = 0; i < loader->zone.n_points - 4U; i++ ) loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH; - loader->zone.n_points += 4; - return TT_Hint_Glyph( loader, 1 ); } @@ -1499,45 +1338,32 @@ static void tt_loader_set_pp( TT_Loader loader ) { - FT_Bool subpixel_hinting = 0; - FT_Bool grayscale = 0; - FT_Bool use_aw_2 = 0; - -#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face ); -#endif - - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting - : 0; - grayscale = loader->exec ? loader->exec->grayscale - : 0; - } -#endif -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) - { - subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting_lean - : 0; - grayscale = loader->exec ? loader->exec->grayscale_cleartype - : 0; - } -#endif - - use_aw_2 = FT_BOOL( subpixel_hinting && grayscale ); - 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 = use_aw_2 ? loader->advance / 2 : 0; + loader->pp3.x = 0; loader->pp3.y = loader->bbox.yMax + loader->top_bearing; - loader->pp4.x = use_aw_2 ? loader->advance / 2 : 0; + loader->pp4.x = 0; loader->pp4.y = loader->pp3.y - loader->vadvance; + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + { + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face ); + + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + loader->exec && + loader->exec->mode != FT_RENDER_MODE_MONO && + loader->exec->mode != FT_RENDER_MODE_LCD && + loader->exec->mode != FT_RENDER_MODE_LCD_V ) + { + loader->pp3.x = loader->advance / 2; + loader->pp4.x = loader->advance / 2; + } + } +#endif } @@ -1596,13 +1422,13 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( recurse_count ) - FT_TRACE5(( " nesting level: %d\n", recurse_count )); + FT_TRACE5(( " nesting level: %u\n", recurse_count )); #endif /* some fonts have an incorrect value of `maxComponentDepth' */ if ( recurse_count > face->max_profile.maxComponentDepth ) { - FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n", + FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %u\n", recurse_count )); face->max_profile.maxComponentDepth = (FT_UShort)recurse_count; } @@ -1653,16 +1479,21 @@ FT_ZERO( &inc_stream ); FT_Stream_OpenMemory( &inc_stream, glyph_data.pointer, - (FT_ULong)glyph_data.length ); + glyph_data.length ); loader->stream = &inc_stream; } else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ + { + FT_ULong len; - offset = tt_face_get_location( face, glyph_index, - (FT_UInt*)&loader->byte_len ); + + offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len ); + + loader->byte_len = (FT_UInt)len; + } if ( loader->byte_len > 0 ) { @@ -1681,7 +1512,7 @@ error = face->access_glyph_frame( loader, glyph_index, face->glyf_offset + offset, - (FT_UInt)loader->byte_len ); + loader->byte_len ); if ( error ) goto Exit; @@ -1713,75 +1544,45 @@ if ( header_only ) goto Exit; +#ifdef FT_CONFIG_OPTION_INCREMENTAL + tt_get_metrics_incremental( loader, glyph_index ); +#endif + tt_loader_set_pp( loader ); + + /* shortcut for empty glyphs */ if ( loader->byte_len == 0 || loader->n_contours == 0 ) { - /* must initialize points before (possibly) overriding */ - /* glyph metrics from the incremental interface */ - tt_loader_set_pp( loader ); - -#ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incr_overrides( loader, glyph_index ); -#endif #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) + if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) ) { /* a small outline structure with four elements for */ /* communication with `TT_Vary_Apply_Glyph_Deltas' */ FT_Vector points[4]; - char tags[4] = { 1, 1, 1, 1 }; - short contours[4] = { 0, 1, 2, 3 }; FT_Outline outline; /* unrounded values */ FT_Vector unrounded[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - points[0].x = loader->pp1.x; - points[0].y = loader->pp1.y; - points[1].x = loader->pp2.x; - points[1].y = loader->pp2.y; + points[0] = loader->pp1; + points[1] = loader->pp2; + points[2] = loader->pp3; + points[3] = loader->pp4; - points[2].x = loader->pp3.x; - points[2].y = loader->pp3.y; - points[3].x = loader->pp4.x; - points[3].y = loader->pp4.y; - - outline.n_points = 4; - outline.n_contours = 4; + outline.n_points = 0; + outline.n_contours = 0; outline.points = points; - outline.tags = tags; - outline.contours = contours; + outline.tags = NULL; + outline.contours = NULL; /* this must be done before scaling */ - error = TT_Vary_Apply_Glyph_Deltas( loader->face, - glyph_index, + error = TT_Vary_Apply_Glyph_Deltas( loader, &outline, - unrounded, - (FT_UInt)outline.n_points ); + unrounded ); if ( error ) goto Exit; - - loader->pp1.x = points[0].x; - loader->pp1.y = points[0].y; - loader->pp2.x = points[1].x; - loader->pp2.y = points[1].y; - - loader->pp3.x = points[2].x; - loader->pp3.y = points[2].y; - loader->pp4.x = points[3].x; - loader->pp4.y = points[3].y; - - /* recalculate linear horizontal and vertical advances */ - /* if we don't have HVAR and VVAR, respectively */ - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - loader->linear = FT_PIX_ROUND( unrounded[1].x - - unrounded[0].x ) / 64; - if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - loader->vadvance = FT_PIX_ROUND( unrounded[3].x - - unrounded[2].x ) / 64; } #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ @@ -1804,13 +1605,6 @@ goto Exit; } - /* must initialize phantom points before (possibly) overriding */ - /* glyph metrics from the incremental interface */ - tt_loader_set_pp( loader ); - -#ifdef FT_CONFIG_OPTION_INCREMENTAL - tt_get_metrics_incr_overrides( loader, glyph_index ); -#endif /***********************************************************************/ /***********************************************************************/ @@ -1820,7 +1614,7 @@ /* (which consists of 10 bytes) */ error = face->access_glyph_frame( loader, glyph_index, face->glyf_offset + offset + 10, - (FT_UInt)loader->byte_len - 10 ); + loader->byte_len - 10 ); if ( error ) goto Exit; @@ -1874,7 +1668,7 @@ /* clear the nodes filled by sibling chains */ node = ft_list_get_node_at( &loader->composites, recurse_count ); for ( node2 = node; node2; node2 = node2->next ) - node2->data = (void*)FT_ULONG_MAX; + node2->data = (void*)-1; /* check whether we already have a composite glyph with this index */ if ( FT_List_Find( &loader->composites, @@ -1891,14 +1685,14 @@ else { - if ( FT_NEW( node ) ) + if ( FT_QNEW( node ) ) goto Exit; node->data = FT_UINT_TO_POINTER( glyph_index ); FT_List_Add( &loader->composites, node ); } - start_point = (FT_UInt)gloader->base.outline.n_points; - start_contour = (FT_UInt)gloader->base.outline.n_contours; + 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 ); @@ -1914,36 +1708,27 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) + if ( !IS_DEFAULT_INSTANCE( FT_FACE( face ) ) ) { - short i, limit; + FT_UShort i, limit; FT_SubGlyph subglyph; - FT_Outline outline; - FT_Vector* points = NULL; - char* tags = NULL; - short* contours = NULL; + FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 }; FT_Vector* unrounded = NULL; - limit = (short)gloader->current.num_subglyphs; + limit = (FT_UShort)gloader->current.num_subglyphs; /* construct an outline structure for */ /* communication with `TT_Vary_Apply_Glyph_Deltas' */ - outline.n_points = (short)( gloader->current.num_subglyphs + 4 ); - outline.n_contours = outline.n_points; - - outline.points = NULL; - outline.tags = NULL; - outline.contours = NULL; - - if ( FT_NEW_ARRAY( points, outline.n_points ) || - FT_NEW_ARRAY( tags, outline.n_points ) || - FT_NEW_ARRAY( contours, outline.n_points ) || - FT_NEW_ARRAY( unrounded, outline.n_points ) ) + if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) || + FT_QNEW_ARRAY( outline.tags, limit ) || + FT_QNEW_ARRAY( outline.contours, limit ) || + FT_QNEW_ARRAY( unrounded, limit + 4 ) ) goto Exit1; + outline.n_contours = outline.n_points = limit; + subglyph = gloader->current.subglyphs; for ( i = 0; i < limit; i++, subglyph++ ) @@ -1951,47 +1736,22 @@ /* applying deltas for anchor points doesn't make sense, */ /* but we don't have to specially check this since */ /* unused delta values are zero anyways */ - points[i].x = subglyph->arg1; - points[i].y = subglyph->arg2; - tags[i] = 1; - contours[i] = i; + outline.points[i].x = subglyph->arg1; + outline.points[i].y = subglyph->arg2; + outline.tags[i] = ON_CURVE_POINT; + outline.contours[i] = i; } - points[i].x = loader->pp1.x; - points[i].y = loader->pp1.y; - tags[i] = 1; - contours[i] = i; - - i++; - points[i].x = loader->pp2.x; - points[i].y = loader->pp2.y; - tags[i] = 1; - contours[i] = i; - - i++; - points[i].x = loader->pp3.x; - points[i].y = loader->pp3.y; - tags[i] = 1; - contours[i] = i; - - i++; - points[i].x = loader->pp4.x; - points[i].y = loader->pp4.y; - tags[i] = 1; - contours[i] = i; - - outline.points = points; - outline.tags = tags; - outline.contours = contours; + outline.points[i++] = loader->pp1; + outline.points[i++] = loader->pp2; + outline.points[i++] = loader->pp3; + outline.points[i ] = loader->pp4; /* this call provides additional offsets */ /* for each component's translation */ - if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas( - face, - glyph_index, - &outline, - unrounded, - (FT_UInt)outline.n_points ) ) ) + if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas( loader, + &outline, + unrounded ) ) ) goto Exit1; subglyph = gloader->current.subglyphs; @@ -2000,32 +1760,11 @@ { if ( subglyph->flags & ARGS_ARE_XY_VALUES ) { - subglyph->arg1 = (FT_Int16)points[i].x; - subglyph->arg2 = (FT_Int16)points[i].y; + subglyph->arg1 = (FT_Int16)outline.points[i].x; + subglyph->arg2 = (FT_Int16)outline.points[i].y; } } - loader->pp1.x = points[i + 0].x; - loader->pp1.y = points[i + 0].y; - loader->pp2.x = points[i + 1].x; - loader->pp2.y = points[i + 1].y; - - loader->pp3.x = points[i + 2].x; - loader->pp3.y = points[i + 2].y; - loader->pp4.x = points[i + 3].x; - loader->pp4.y = points[i + 3].y; - - /* recalculate linear horizontal and vertical advances */ - /* if we don't have HVAR and VVAR, respectively */ - if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - loader->linear = - FT_PIX_ROUND( unrounded[outline.n_points - 3].x - - unrounded[outline.n_points - 4].x ) / 64; - if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - loader->vadvance = - FT_PIX_ROUND( unrounded[outline.n_points - 1].x - - unrounded[outline.n_points - 2].x ) / 64; - Exit1: FT_FREE( outline.points ); FT_FREE( outline.tags ); @@ -2076,7 +1815,7 @@ FT_UInt num_base_subgs = gloader->base.num_subglyphs; FT_Stream old_stream = loader->stream; - FT_Int old_byte_len = loader->byte_len; + FT_UInt old_byte_len = loader->byte_len; FT_GlyphLoader_Add( gloader ); @@ -2104,7 +1843,7 @@ linear_hadvance = loader->linear; linear_vadvance = loader->vadvance; - num_base_points = (FT_UInt)gloader->base.outline.n_points; + num_base_points = gloader->base.outline.n_points; error = load_truetype_glyph( loader, (FT_UInt)subglyph->index, @@ -2128,7 +1867,7 @@ loader->vadvance = linear_vadvance; } - num_points = (FT_UInt)gloader->base.outline.n_points; + num_points = gloader->base.outline.n_points; if ( num_points == num_base_points ) continue; @@ -2168,6 +1907,11 @@ goto Exit; } } + + /* retain the overlap flag */ + if ( gloader->base.num_subglyphs && + gloader->base.subglyphs[0].flags & OVERLAP_COMPOUND ) + gloader->base.outline.flags |= FT_OUTLINE_OVERLAP; } /***********************************************************************/ @@ -2181,6 +1925,9 @@ #ifdef FT_CONFIG_OPTION_INCREMENTAL + /* restore the original stream */ + loader->stream = face->root.stream; + if ( glyph_data_loaded ) face->root.internal->incremental_interface->funcs->free_glyph_data( face->root.internal->incremental_interface->object, @@ -2196,16 +1943,11 @@ compute_glyph_metrics( TT_Loader loader, FT_UInt glyph_index ) { - TT_Face face = loader->face; -#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ - defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); -#endif - + TT_Face face = loader->face; + TT_Size size = loader->size; + TT_GlyphSlot glyph = loader->glyph; FT_BBox bbox; FT_Fixed y_scale; - TT_GlyphSlot glyph = loader->glyph; - TT_Size size = loader->size; y_scale = 0x10000L; @@ -2223,53 +1965,10 @@ glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; - glyph->metrics.horiAdvance = SUB_LONG(loader->pp2.x, loader->pp1.x); - - /* Adjust advance width to the value contained in the hdmx table */ - /* unless FT_LOAD_COMPUTE_METRICS is set or backward compatibility */ - /* mode of the v40 interpreter is active. See `ttinterp.h' for */ - /* details on backward compatibility mode. */ - if ( -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && - ( loader->exec && loader->exec->backward_compatibility ) ) && -#endif - !face->postscript.isFixedPitch && - IS_HINTED( loader->load_flags ) && - !( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) ) - { - FT_Byte* widthp; - - - widthp = tt_face_get_device_metrics( face, - size->metrics->x_ppem, - glyph_index ); - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - FT_Bool ignore_x_mode; - - - ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != - FT_RENDER_MODE_MONO ); - - if ( widthp && - ( ( ignore_x_mode && loader->exec->compatible_widths ) || - !ignore_x_mode || - SPH_OPTION_BITMAP_WIDTHS ) ) - glyph->metrics.horiAdvance = *widthp * 64; - } - else - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - { - if ( widthp ) - glyph->metrics.horiAdvance = *widthp * 64; - } - } + if ( loader->widthp ) + glyph->metrics.horiAdvance = loader->widthp[glyph_index] * 64; + else + glyph->metrics.horiAdvance = SUB_LONG( loader->pp2.x, loader->pp1.x ); /* set glyph dimensions */ glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); @@ -2287,13 +1986,14 @@ if ( face->vertical_info && face->vertical.number_Of_VMetrics > 0 ) { - top = (FT_Short)FT_DivFix( loader->pp3.y - bbox.yMax, + top = (FT_Short)FT_DivFix( SUB_LONG( 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, + advance = (FT_UShort)FT_DivFix( SUB_LONG( loader->pp3.y, + loader->pp4.y ), y_scale ); } else @@ -2385,29 +2085,21 @@ FT_UInt glyph_index, FT_Int32 load_flags ) { - TT_Face face; - SFNT_Service sfnt; - FT_Stream stream; + TT_Face face = (TT_Face)glyph->face; + SFNT_Service sfnt = (SFNT_Service)face->sfnt; FT_Error error; TT_SBit_MetricsRec sbit_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_UInt)load_flags, - stream, + face->root.stream, &glyph->bitmap, &sbit_metrics ); if ( !error ) { - glyph->outline.n_points = 0; - glyph->outline.n_contours = 0; - glyph->metrics.width = (FT_Pos)sbit_metrics.width * 64; glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64; @@ -2432,6 +2124,50 @@ glyph->bitmap_top = sbit_metrics.horiBearingY; } } + /* a missing glyph in a bitmap-only font is assumed whitespace */ + /* that needs to be constructed using metrics data from `hmtx' */ + /* and, optionally, `vmtx' tables */ + else if ( FT_ERR_EQ( error, Missing_Bitmap ) && + !FT_IS_SCALABLE( glyph->face ) && + face->horz_metrics_size ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->metrics.width = 0; + glyph->metrics.height = 0; + + glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); + glyph->metrics.horiBearingY = 0; + glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); + + glyph->metrics.vertBearingX = 0; + glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); + + glyph->format = FT_GLYPH_FORMAT_BITMAP; + glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; + + glyph->bitmap_left = 0; + glyph->bitmap_top = 0; + + error = FT_Err_Ok; + } return error; } @@ -2446,21 +2182,8 @@ FT_Int32 load_flags, FT_Bool glyf_table_only ) { - TT_Face face; - FT_Stream stream; + TT_Face face = (TT_Face)glyph->face; -#ifdef TT_USE_BYTECODE_INTERPRETER - FT_Error error; - FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); -#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \ - defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( (TT_Face)glyph->face ); -#endif -#endif - - - face = (TT_Face)glyph->face; - stream = face->root.stream; FT_ZERO( loader ); @@ -2469,241 +2192,118 @@ /* load execution context */ if ( IS_HINTED( load_flags ) && !glyf_table_only ) { + FT_Error error; TT_ExecContext exec; - FT_Bool grayscale = TRUE; + FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); + FT_Bool grayscale = FT_BOOL( mode != FT_RENDER_MODE_MONO ); + FT_Bool reexecute = FALSE; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - FT_Bool subpixel_hinting_lean; - FT_Bool grayscale_cleartype; + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face ); #endif -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_Bool subpixel_hinting = FALSE; -#if 0 - /* not used yet */ - FT_Bool compatible_widths; - FT_Bool symmetrical_smoothing; - FT_Bool bgr; - FT_Bool vertical_lcd; - FT_Bool subpixel_positioned; - FT_Bool gray_cleartype; -#endif -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - FT_Bool reexecute = FALSE; - - - if ( size->bytecode_ready < 0 || size->cvt_ready < 0 ) + if ( size->bytecode_ready > 0 ) + return size->bytecode_ready; + if ( size->bytecode_ready < 0 ) { - error = tt_size_ready_bytecode( size, pedantic ); + FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); + + + error = tt_size_init_bytecode( size, pedantic ); if ( error ) return error; } - else if ( size->bytecode_ready ) - return size->bytecode_ready; - else if ( size->cvt_ready ) - return size->cvt_ready; - /* query new execution context */ exec = size->context; - if ( !exec ) - return FT_THROW( Could_Not_Find_Context ); #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) { - subpixel_hinting_lean = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); - grayscale_cleartype = - FT_BOOL( subpixel_hinting_lean && - !( ( load_flags & - FT_LOAD_TARGET_LCD ) || - ( load_flags & - FT_LOAD_TARGET_LCD_V ) ) ); - exec->vertical_lcd_lean = - FT_BOOL( subpixel_hinting_lean && - ( load_flags & - FT_LOAD_TARGET_LCD_V ) ); - } - else - { - subpixel_hinting_lean = FALSE; - grayscale_cleartype = FALSE; - exec->vertical_lcd_lean = FALSE; - } -#endif + grayscale = FALSE; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ) && - SPH_OPTION_SET_SUBPIXEL ); - - if ( subpixel_hinting ) - grayscale = FALSE; - else if ( SPH_OPTION_SET_GRAYSCALE ) + /* any mode change requires a re-execution of the CVT program */ + if ( mode != exec->mode ) { - grayscale = TRUE; - subpixel_hinting = FALSE; + FT_TRACE4(( "tt_loader_init: render mode change," + " re-executing `prep' table\n" )); + + exec->mode = mode; + reexecute = TRUE; } - else - grayscale = FALSE; - - if ( FT_IS_TRICKY( glyph->face ) ) - subpixel_hinting = FALSE; - - exec->ignore_x_mode = subpixel_hinting || grayscale; - exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) - exec->rasterizer_version = TT_INTERPRETER_VERSION_35; - -#if 1 - exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS; - exec->symmetrical_smoothing = TRUE; - exec->bgr = FALSE; - exec->vertical_lcd = FALSE; - exec->subpixel_positioned = TRUE; - exec->gray_cleartype = FALSE; -#else /* 0 */ - exec->compatible_widths = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_COMPATIBLE_WIDTHS ); - exec->symmetrical_smoothing = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_SYMMETRICAL_SMOOTHING ); - exec->bgr = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_BGR ); - exec->vertical_lcd = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_VERTICAL_LCD ); - exec->subpixel_positioned = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_SUBPIXEL_POSITIONED ); - exec->gray_cleartype = - FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - TT_LOAD_GRAY_CLEARTYPE ); -#endif /* 0 */ - } - else - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) - grayscale = FT_BOOL( !subpixel_hinting_lean && - FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); - else #endif - grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != - FT_RENDER_MODE_MONO ); + + /* a change from mono to grayscale rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ + if ( grayscale != exec->grayscale ) + { + FT_TRACE4(( "tt_loader_init: grayscale hinting change," + " re-executing `prep' table\n" )); + + exec->grayscale = grayscale; + reexecute = TRUE; + } + + if ( size->cvt_ready > 0 ) + return size->cvt_ready; + if ( size->cvt_ready < 0 || reexecute ) + { + error = tt_size_run_prep( size ); + if ( error ) + return error; + } error = TT_Load_Context( exec, face, size ); if ( error ) return error; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 ) - { - /* a change from mono to subpixel rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( subpixel_hinting != exec->subpixel_hinting ) - { - FT_TRACE4(( "tt_loader_init: subpixel hinting change," - " re-executing `prep' table\n" )); - - exec->subpixel_hinting = subpixel_hinting; - reexecute = TRUE; - } - - /* a change from mono to grayscale rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) - { - FT_TRACE4(( "tt_loader_init: grayscale hinting change," - " re-executing `prep' table\n" )); - - exec->grayscale = grayscale; - reexecute = TRUE; - } - } - else - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - { - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) - { - /* a change from mono to subpixel rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( subpixel_hinting_lean != exec->subpixel_hinting_lean ) - { - FT_TRACE4(( "tt_loader_init: subpixel hinting change," - " re-executing `prep' table\n" )); - - exec->subpixel_hinting_lean = subpixel_hinting_lean; - reexecute = TRUE; - } - - /* a change from colored to grayscale subpixel rendering (and */ - /* vice versa) requires a re-execution of the CVT program */ - if ( grayscale_cleartype != exec->grayscale_cleartype ) - { - FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change," - " re-executing `prep' table\n" )); - - exec->grayscale_cleartype = grayscale_cleartype; - reexecute = TRUE; - } - } -#endif - - /* a change from mono to grayscale rendering (and vice versa) */ - /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) - { - FT_TRACE4(( "tt_loader_init: grayscale hinting change," - " re-executing `prep' table\n" )); - - exec->grayscale = grayscale; - reexecute = TRUE; - } - } - - if ( reexecute ) - { - error = tt_size_run_prep( size, pedantic ); - if ( error ) - return error; - } - /* check whether the cvt program has disabled hinting */ - if ( exec->GS.instruct_control & 1 ) + if ( size->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; + /* check whether GS modifications should be reverted */ + if ( size->GS.instruct_control & 2 ) + size->GS = tt_default_graphics_state; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* check whether we have a font hinted for ClearType -- */ - /* note that this flag can also be modified in a glyph's bytecode */ - if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 && - exec->GS.instruct_control & 4 ) - exec->ignore_x_mode = 0; -#endif +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Toggle backward compatibility according to what font wants, except + * when + * + * 1) we have a `tricky' font that heavily relies on the interpreter to + * render glyphs correctly, for example DFKai-SB, or + * 2) FT_RENDER_MODE_MONO (i.e, monochrome rendering) is requested. + * + * In those cases, backward compatibility needs to be turned off to get + * correct rendering. The rendering is then completely up to the + * font's programming. + * + */ + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 && + mode != FT_RENDER_MODE_MONO && + !FT_IS_TRICKY( glyph->face ) ) + exec->backward_compatibility = ( size->GS.instruct_control & 4 ) ^ 4; + else + exec->backward_compatibility = 0; +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ - exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC ); loader->exec = exec; - loader->instructions = exec->glyphIns; + + /* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */ + /* is set or backward compatibility mode of the v38 or v40 */ + /* interpreters is active. See `ttinterp.h' for details on */ + /* backward compatibility mode. */ + if ( IS_HINTED( load_flags ) && + !( load_flags & FT_LOAD_COMPUTE_METRICS ) && +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + !exec->backward_compatibility && +#endif + !face->postscript.isFixedPitch ) + { + loader->widthp = size->widthp; + } + else + loader->widthp = NULL; } #endif /* TT_USE_BYTECODE_INTERPRETER */ @@ -2723,7 +2323,7 @@ loader->face = face; loader->size = size; loader->glyph = (FT_GlyphSlot)glyph; - loader->stream = stream; + loader->stream = face->root.stream; loader->composites.head = NULL; loader->composites.tail = NULL; @@ -2751,11 +2351,12 @@ * A function used to load a single glyph within a given glyph slot, * for a given size. * - * @Input: + * @InOut: * glyph :: * A handle to a target slot object where the glyph * will be loaded. * + * @Input: * size :: * A handle to the source face size at which the glyph * must be scaled/loaded. @@ -2779,89 +2380,31 @@ FT_UInt glyph_index, FT_Int32 load_flags ) { + TT_Face face = (TT_Face)glyph->face; FT_Error error; TT_LoaderRec loader; - FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "TT_Load_Glyph: glyph index %u\n", glyph_index )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /* try to load embedded bitmap (if any) */ - if ( size->strike_index != 0xFFFFFFFFUL && - ( load_flags & FT_LOAD_NO_BITMAP ) == 0 && - IS_DEFAULT_INSTANCE( glyph->face ) ) + if ( size->strike_index != 0xFFFFFFFFUL && + !( load_flags & FT_LOAD_NO_BITMAP && + FT_IS_SCALABLE( glyph->face ) ) && + IS_DEFAULT_INSTANCE( glyph->face ) ) { - FT_Fixed x_scale = size->root.metrics.x_scale; - FT_Fixed y_scale = size->root.metrics.y_scale; - - error = load_sbit_image( size, glyph, glyph_index, load_flags ); - if ( FT_ERR_EQ( error, Missing_Bitmap ) ) + if ( !error ) { - /* the bitmap strike is incomplete and misses the requested glyph; */ - /* if we have a bitmap-only font, return an empty glyph */ - if ( !FT_IS_SCALABLE( glyph->face ) ) + if ( FT_IS_SCALABLE( glyph->face ) || + FT_HAS_SBIX( glyph->face ) ) { - TT_Face face = (TT_Face)glyph->face; - - FT_Short left_bearing = 0; - FT_Short top_bearing = 0; - - FT_UShort advance_width = 0; - FT_UShort advance_height = 0; + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; - /* to return an empty glyph, however, we need metrics data */ - /* from the `hmtx' (or `vmtx') table; the assumption is that */ - /* empty glyphs are missing intentionally, representing */ - /* whitespace - not having at least horizontal metrics is */ - /* thus considered an error */ - if ( !face->horz_metrics_size ) - return error; - - /* we now construct an empty bitmap glyph */ - TT_Get_HMetrics( face, glyph_index, - &left_bearing, - &advance_width ); - TT_Get_VMetrics( face, glyph_index, - 0, - &top_bearing, - &advance_height ); - - glyph->outline.n_points = 0; - glyph->outline.n_contours = 0; - - glyph->metrics.width = 0; - glyph->metrics.height = 0; - - glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale ); - glyph->metrics.horiBearingY = 0; - glyph->metrics.horiAdvance = FT_MulFix( advance_width, x_scale ); - - glyph->metrics.vertBearingX = 0; - glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale ); - glyph->metrics.vertAdvance = FT_MulFix( advance_height, y_scale ); - - glyph->format = FT_GLYPH_FORMAT_BITMAP; - glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO; - - glyph->bitmap_left = 0; - glyph->bitmap_top = 0; - - return FT_Err_Ok; - } - } - else if ( error ) - { - /* return error if font is not scalable */ - if ( !FT_IS_SCALABLE( glyph->face ) ) - return error; - } - else - { - if ( FT_IS_SCALABLE( glyph->face ) ) - { /* for the bbox we need the header only */ (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE ); (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE ); @@ -2869,6 +2412,35 @@ glyph->linearHoriAdvance = loader.linear; glyph->linearVertAdvance = loader.vadvance; + /* Bitmaps from the 'sbix' table need special treatment: */ + /* if there is a glyph contour, the bitmap origin must be */ + /* shifted to be relative to the lower left corner of the */ + /* glyph bounding box, also taking the left-side bearing */ + /* (or top bearing) into account. */ + if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX && + loader.n_contours > 0 ) + { + FT_Int bitmap_left; + FT_Int bitmap_top; + + + if ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) + { + /* This is a guess, since Apple's CoreText engine doesn't */ + /* really do vertical typesetting. */ + bitmap_left = loader.bbox.xMin; + bitmap_top = loader.top_bearing; + } + else + { + bitmap_left = loader.left_bearing; + bitmap_top = loader.bbox.yMin; + } + + glyph->bitmap_left += FT_MulFix( bitmap_left, x_scale ) >> 6; + glyph->bitmap_top += FT_MulFix( bitmap_top, y_scale ) >> 6; + } + /* sanity checks: if `xxxAdvance' in the sbit metric */ /* structure isn't set, use `linearXXXAdvance' */ if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance ) @@ -2879,17 +2451,10 @@ y_scale ); } - return FT_Err_Ok; + goto Exit; } - } - -#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 ) - { - error = FT_THROW( Invalid_Size_Handle ); - goto Exit; + else if ( !FT_IS_SCALABLE( glyph->face ) ) + goto Exit; } if ( load_flags & FT_LOAD_SBITS_ONLY ) @@ -2898,13 +2463,87 @@ goto Exit; } +#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.ppem ) + { + error = FT_THROW( Invalid_Size_Handle ); + goto Exit; + } + +#ifdef FT_CONFIG_OPTION_SVG + + /* check for OT-SVG */ + if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 && + ( load_flags & FT_LOAD_COLOR ) && + face->svg ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + + FT_TRACE3(( "Trying to load SVG glyph\n" )); + + error = sfnt->load_svg_doc( glyph, glyph_index ); + if ( !error ) + { + FT_Fixed x_scale = size->root.metrics.x_scale; + FT_Fixed y_scale = size->root.metrics.y_scale; + + FT_Short leftBearing; + FT_Short topBearing; + FT_UShort advanceX; + FT_UShort advanceY; + + + FT_TRACE3(( "Successfully loaded SVG glyph\n" )); + + glyph->format = FT_GLYPH_FORMAT_SVG; + + sfnt->get_metrics( face, + FALSE, + glyph_index, + &leftBearing, + &advanceX ); + sfnt->get_metrics( face, + TRUE, + glyph_index, + &topBearing, + &advanceY ); + + glyph->linearHoriAdvance = advanceX; + glyph->linearVertAdvance = advanceY; + + glyph->metrics.horiAdvance = FT_MulFix( advanceX, x_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advanceY, y_scale ); + + goto Exit; + } + + FT_TRACE3(( "Failed to load SVG glyph\n" )); + } + + /* return immediately if we only want SVG glyphs */ + if ( load_flags & FT_LOAD_SVG_ONLY ) + { + error = FT_THROW( Invalid_Argument ); + goto Exit; + } + +#endif /* FT_CONFIG_OPTION_SVG */ + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) goto Exit; - glyph->format = FT_GLYPH_FORMAT_OUTLINE; - glyph->num_subglyphs = 0; - glyph->outline.flags = 0; + /* done if we are only interested in the `hdmx` advance */ + if ( load_flags & FT_LOAD_ADVANCE_ONLY && + !( load_flags & FT_LOAD_VERTICAL_LAYOUT ) && + loader.widthp ) + { + glyph->metrics.horiAdvance = loader.widthp[glyph_index] * 64; + goto Done; + } /* main loading loop */ error = load_truetype_glyph( &loader, glyph_index, 0, FALSE ); @@ -2917,9 +2556,18 @@ } else { + glyph->format = FT_GLYPH_FORMAT_OUTLINE; + glyph->outline = loader.gloader->base.outline; glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS; + /* 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->metrics->y_ppem < 24 ) + glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* Translate array so that (0,0) is the glyph's origin. Note */ /* that this behaviour is independent on the value of bit 1 of */ /* the `flags' field in the `head' table -- at least major */ @@ -2932,6 +2580,9 @@ if ( IS_HINTED( load_flags ) ) { + glyph->control_data = loader.exec->glyphIns; + glyph->control_len = loader.exec->glyphSize; + if ( loader.exec->GS.scan_control ) { /* convert scan conversion mode to FT_OUTLINE_XXX flags */ @@ -2965,22 +2616,19 @@ error = compute_glyph_metrics( &loader, glyph_index ); } + FT_TRACE1(( " subglyphs = %u, contours = %hu, points = %hu," + " flags = 0x%.3x\n", + loader.gloader->base.num_subglyphs, + glyph->outline.n_contours, + glyph->outline.n_points, + glyph->outline.flags )); + + Done: tt_loader_done( &loader ); - /* 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->metrics->y_ppem < 24 ) - glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - Exit: -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE1(( " failed (error code 0x%x)\n", - error )); -#endif + FT_TRACE1(( error ? " failed (error code 0x%x)\n" : "", + error )); return error; } diff --git a/src/thirdparty/freetype2/src/truetype/ttgload.h b/src/thirdparty/freetype2/src/truetype/ttgload.h index f1324bc86..39d6ae366 100644 --- a/src/thirdparty/freetype2/src/truetype/ttgload.h +++ b/src/thirdparty/freetype2/src/truetype/ttgload.h @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define TTGLOAD_H_ -#include #include "ttobjs.h" #ifdef TT_USE_BYTECODE_INTERPRETER diff --git a/src/thirdparty/freetype2/src/truetype/ttgxvar.c b/src/thirdparty/freetype2/src/truetype/ttgxvar.c index 78d87dc09..2ff40c9e8 100644 --- a/src/thirdparty/freetype2/src/truetype/ttgxvar.c +++ b/src/thirdparty/freetype2/src/truetype/ttgxvar.c @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -40,14 +40,16 @@ #include -#include FT_INTERNAL_DEBUG_H +#include #include FT_CONFIG_CONFIG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_SFNT_H -#include FT_TRUETYPE_TAGS_H -#include FT_TRUETYPE_IDS_H -#include FT_MULTIPLE_MASTERS_H -#include FT_LIST_H +#include +#include +#include +#include +#include +#include +#include +#include #include "ttpload.h" #include "ttgxvar.h" @@ -127,9 +129,6 @@ * stream :: * The data stream. * - * size :: - * The size of the table holding the data. - * * @Output: * point_cnt :: * The number of points read. A zero value means that @@ -142,18 +141,16 @@ */ static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, - FT_ULong size, FT_UInt *point_cnt ) { FT_UShort *points = NULL; FT_UInt n; - FT_UInt runcnt; + FT_UInt runcnt, cnt; FT_UInt i, j; FT_UShort first; + FT_Byte* p; FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; *point_cnt = 0; @@ -169,56 +166,60 @@ n |= FT_GET_BYTE(); } - if ( n > size ) - { - FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" )); - return NULL; - } - - /* in the nested loops below we increase `i' twice; */ - /* it is faster to simply allocate one more slot */ - /* than to add another test within the loop */ - if ( FT_NEW_ARRAY( points, n + 1 ) ) + if ( FT_QNEW_ARRAY( points, n ) ) return NULL; - *point_cnt = n; - + p = stream->cursor; first = 0; i = 0; while ( i < n ) { - runcnt = FT_GET_BYTE(); + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); + cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK; + + /* first point not included in run count */ + cnt++; + if ( cnt > n - i ) + cnt = n - i; + if ( runcnt & GX_PT_POINTS_ARE_WORDS ) { - runcnt &= GX_PT_POINT_RUN_COUNT_MASK; - first += FT_GET_USHORT(); - points[i++] = first; + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; - /* first point not included in run count */ - for ( j = 0; j < runcnt; j++ ) + for ( j = 0; j < cnt; j++ ) { - first += FT_GET_USHORT(); + first += FT_NEXT_USHORT( p ); points[i++] = first; - if ( i >= n ) - break; } } else { - first += FT_GET_BYTE(); - points[i++] = first; + if ( cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; - for ( j = 0; j < runcnt; j++ ) + for ( j = 0; j < cnt; j++ ) { - first += FT_GET_BYTE(); + first += FT_NEXT_BYTE( p ); points[i++] = first; - if ( i >= n ) - break; } } } + stream->cursor = p; + + *point_cnt = n; + return points; + + Fail: + FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" )); + + FT_FREE( points ); + return NULL; } @@ -240,9 +241,6 @@ * stream :: * The data stream. * - * size :: - * The size of the table holding the data. - * * delta_cnt :: * The number of deltas to be read. * @@ -258,61 +256,66 @@ */ static FT_Fixed* ft_var_readpackeddeltas( FT_Stream stream, - FT_ULong size, FT_UInt delta_cnt ) { FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; FT_UInt i, j; + FT_Byte* p; FT_Memory memory = stream->memory; - FT_Error error = FT_Err_Ok; - - FT_UNUSED( error ); + FT_Error error; - if ( delta_cnt > size ) - { - FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" )); - return NULL; - } - - if ( FT_NEW_ARRAY( deltas, delta_cnt ) ) + if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) return NULL; + p = stream->cursor; i = 0; while ( i < delta_cnt ) { - runcnt = FT_GET_BYTE(); + if ( p >= stream->limit ) + goto Fail; + + runcnt = FT_NEXT_BYTE( p ); cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK; + /* first point not included in run count */ + cnt++; + if ( cnt > delta_cnt - i ) + cnt = delta_cnt - i; + if ( runcnt & GX_DT_DELTAS_ARE_ZERO ) { - /* `runcnt' zeroes get added */ - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) + for ( j = 0; j < cnt; j++ ) deltas[i++] = 0; } else if ( runcnt & GX_DT_DELTAS_ARE_WORDS ) { - /* `runcnt' shorts from the stack */ - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); + if ( 2 * cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; + + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) ); } else { - /* `runcnt' signed bytes from the stack */ - for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); - } + if ( cnt > (FT_UInt)( stream->limit - p ) ) + goto Fail; - if ( j <= cnt ) - { - /* bad format */ - FT_FREE( deltas ); - return NULL; + for ( j = 0; j < cnt; j++ ) + deltas[i++] = FT_intToFixed( FT_NEXT_CHAR( p ) ); } } + stream->cursor = p; + return deltas; + + Fail: + FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" )); + + FT_FREE( deltas ); + return NULL; } @@ -332,17 +335,24 @@ static void ft_var_load_avar( TT_Face face ) { - FT_Stream stream = FT_FACE_STREAM( face ); - FT_Memory memory = stream->memory; + FT_Error error; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Int i, j; + GX_Blend blend = face->blend; GX_AVarSegment segment; - FT_Error error = FT_Err_Ok; - FT_Long version; - FT_Long axisCount; - FT_Int i, j; - FT_ULong table_len; + GX_AVarTable table; - FT_UNUSED( error ); + FT_Long version; + FT_Long axisCount; + FT_ULong table_len; + +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + FT_ULong table_offset; + FT_ULong store_offset; + FT_ULong axisMap_offset; +#endif FT_TRACE2(( "AVAR " )); @@ -355,13 +365,21 @@ return; } +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + table_offset = FT_STREAM_POS(); +#endif + if ( FT_FRAME_ENTER( table_len ) ) return; version = FT_GET_LONG(); axisCount = FT_GET_LONG(); - if ( version != 0x00010000L ) + if ( version != 0x00010000L +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + && version != 0x00020000L +#endif + ) { FT_TRACE2(( "bad table version\n" )); goto Exit; @@ -371,31 +389,35 @@ if ( axisCount != (FT_Long)blend->mmvar->num_axis ) { - FT_TRACE2(( "ft_var_load_avar: number of axes in `avar' and `fvar'\n" - " table are different\n" )); + FT_TRACE2(( "ft_var_load_avar:" + " number of axes in `avar' and `fvar'\n" )); + FT_TRACE2(( " table are different\n" )); goto Exit; } - if ( FT_NEW_ARRAY( blend->avar_segment, axisCount ) ) + if ( FT_NEW( blend->avar_table ) ) + goto Exit; + table = blend->avar_table; + + if ( FT_QNEW_ARRAY( table->avar_segment, axisCount ) ) goto Exit; - segment = &blend->avar_segment[0]; + segment = &table->avar_segment[0]; for ( i = 0; i < axisCount; i++, segment++ ) { FT_TRACE5(( " axis %d:\n", i )); segment->pairCount = FT_GET_USHORT(); - if ( (FT_ULong)segment->pairCount * 4 > table_len || - FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) ) + if ( (FT_ULong)segment->pairCount * 4 > table_len || + FT_QNEW_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( table->avar_segment[j].correspondence ); - FT_FREE( blend->avar_segment ); - blend->avar_segment = NULL; + FT_FREE( table->avar_segment ); goto Exit; } @@ -407,35 +429,71 @@ FT_fdot14ToFixed( FT_GET_SHORT() ); FT_TRACE5(( " mapping %.5f to %.5f\n", - segment->correspondence[j].fromCoord / 65536.0, - segment->correspondence[j].toCoord / 65536.0 )); + (double)segment->correspondence[j].fromCoord / 65536, + (double)segment->correspondence[j].toCoord / 65536 )); } FT_TRACE5(( "\n" )); } +#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION + if ( version < 0x00020000L ) + goto Exit; + + axisMap_offset = FT_GET_ULONG(); + store_offset = FT_GET_ULONG(); + + if ( store_offset ) + { + error = tt_var_load_item_variation_store( + FT_FACE( face ), + table_offset + store_offset, + &table->itemStore ); + if ( error ) + goto Exit; + } + + if ( axisMap_offset ) + { + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), + table_offset + axisMap_offset, + &table->axisMap, + &table->itemStore, + table_len ); + if ( error ) + goto Exit; + } +#endif + + Exit: FT_FRAME_EXIT(); } - static FT_Error - ft_var_load_item_variation_store( TT_Face face, + FT_LOCAL_DEF( FT_Error ) + tt_var_load_item_variation_store( FT_Face face, /* TT_Face */ FT_ULong offset, GX_ItemVarStore itemStore ) { + TT_Face ttface = (TT_Face)face; FT_Stream stream = FT_FACE_STREAM( face ); FT_Memory memory = stream->memory; FT_Error error; FT_UShort format; FT_ULong region_offset; - FT_UInt i, j, k; - FT_UInt shortDeltaCount; - GX_Blend blend = face->blend; - GX_ItemVarData varData; + FT_UInt data_count; + FT_UShort axis_count; + FT_UInt region_count; + FT_UInt i, j; + FT_Byte* bytes; + FT_Bool long_words; + + GX_Blend blend = ttface->blend; FT_ULong* dataOffsetArray = NULL; @@ -445,77 +503,107 @@ if ( format != 1 ) { - FT_TRACE2(( "ft_var_load_item_variation_store: bad store format %d\n", + FT_TRACE2(( "tt_var_load_item_variation_store: bad store format %d\n", format )); error = FT_THROW( Invalid_Table ); goto Exit; } /* read top level fields */ - if ( FT_READ_ULONG( region_offset ) || - FT_READ_USHORT( itemStore->dataCount ) ) + if ( FT_READ_ULONG( region_offset ) || + FT_READ_USHORT( data_count ) ) goto Exit; /* we need at least one entry in `itemStore->varData' */ - if ( !itemStore->dataCount ) + if ( !data_count ) { - FT_TRACE2(( "ft_var_load_item_variation_store: missing varData\n" )); + FT_TRACE2(( "tt_var_load_item_variation_store: missing varData\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } /* make temporary copy of item variation data offsets; */ /* we will parse region list first, then come back */ - if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) ) + if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) ) goto Exit; - for ( i = 0; i < itemStore->dataCount; i++ ) - { - if ( FT_READ_ULONG( dataOffsetArray[i] ) ) - goto Exit; - } + if ( FT_FRAME_ENTER( data_count * 4 ) ) + goto Exit; + + bytes = stream->cursor; + + for ( i = 0; i < data_count; i++ ) + dataOffsetArray[i] = FT_NEXT_ULONG( bytes ); + + FT_FRAME_EXIT(); /* parse array of region records (region list) */ if ( FT_STREAM_SEEK( offset + region_offset ) ) goto Exit; - if ( FT_READ_USHORT( itemStore->axisCount ) || - FT_READ_USHORT( itemStore->regionCount ) ) + if ( FT_READ_USHORT( axis_count ) || + FT_READ_USHORT( region_count ) ) goto Exit; - if ( itemStore->axisCount != (FT_Long)blend->mmvar->num_axis ) + if ( axis_count != (FT_Long)blend->mmvar->num_axis ) { - FT_TRACE2(( "ft_var_load_item_variation_store:" - " number of axes in item variation store\n" - " " + FT_TRACE2(( "tt_var_load_item_variation_store:" + " number of axes in item variation store\n" )); + FT_TRACE2(( " " " and `fvar' table are different\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } + itemStore->axisCount = axis_count; - if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) ) + /* new constraint in OpenType 1.8.4 */ + if ( region_count >= 32768U ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " too many variation region tables\n" )); + error = FT_THROW( Invalid_Table ); goto Exit; + } - for ( i = 0; i < itemStore->regionCount; i++ ) + if ( FT_NEW_ARRAY( itemStore->varRegionList, region_count ) ) + goto Exit; + itemStore->regionCount = region_count; + + if ( FT_FRAME_ENTER( (FT_Long)region_count * axis_count * 6 ) ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " not enough data for variation regions\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; + + for ( i = 0; i < region_count; i++ ) { GX_AxisCoords axisCoords; - if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, - itemStore->axisCount ) ) + if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) ) + { + FT_FRAME_EXIT(); goto Exit; + } axisCoords = itemStore->varRegionList[i].axisList; for ( j = 0; j < itemStore->axisCount; j++ ) { - FT_Short start, peak, end; + FT_Int start, peak, end; - if ( FT_READ_SHORT( start ) || - FT_READ_SHORT( peak ) || - FT_READ_SHORT( end ) ) - goto Exit; + start = FT_NEXT_SHORT( bytes ); + peak = FT_NEXT_SHORT( bytes ); + end = FT_NEXT_SHORT( bytes ); + + /* immediately tag invalid ranges with special peak = 0 */ + if ( ( start < 0 && end > 0 ) || start > peak || peak > end ) + peak = 0; axisCoords[j].startCoord = FT_fdot14ToFixed( start ); axisCoords[j].peakCoord = FT_fdot14ToFixed( peak ); @@ -523,99 +611,104 @@ } } + FT_FRAME_EXIT(); + /* end of region list parse */ /* use dataOffsetArray now to parse varData items */ - if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) ) + if ( FT_NEW_ARRAY( itemStore->varData, data_count ) ) goto Exit; + itemStore->dataCount = data_count; - for ( i = 0; i < itemStore->dataCount; i++ ) + for ( i = 0; i < data_count; i++ ) { - varData = &itemStore->varData[i]; + GX_ItemVarData varData = &itemStore->varData[i]; + + FT_UInt item_count; + FT_UShort word_delta_count; + FT_UInt region_idx_count; + FT_UInt per_region_size; + if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) ) goto Exit; - if ( FT_READ_USHORT( varData->itemCount ) || - FT_READ_USHORT( shortDeltaCount ) || - FT_READ_USHORT( varData->regionIdxCount ) ) + if ( FT_READ_USHORT( item_count ) || + FT_READ_USHORT( word_delta_count ) || + FT_READ_USHORT( region_idx_count ) ) goto Exit; + long_words = !!( word_delta_count & 0x8000 ); + word_delta_count &= 0x7FFF; + /* check some data consistency */ - if ( shortDeltaCount > varData->regionIdxCount ) + if ( word_delta_count > region_idx_count ) { - FT_TRACE2(( "bad short count %d or region count %d\n", - shortDeltaCount, - varData->regionIdxCount )); + FT_TRACE2(( "bad short count %d or region count %u\n", + word_delta_count, + region_idx_count )); error = FT_THROW( Invalid_Table ); goto Exit; } - if ( varData->regionIdxCount > itemStore->regionCount ) + if ( region_idx_count > itemStore->regionCount ) { - FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n", - varData->regionIdxCount, + FT_TRACE2(( "inconsistent regionCount %u in varData[%u]\n", + region_idx_count, i )); error = FT_THROW( Invalid_Table ); goto Exit; } /* parse region indices */ - if ( FT_NEW_ARRAY( varData->regionIndices, - varData->regionIdxCount ) ) + if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) ) goto Exit; + varData->regionIdxCount = region_idx_count; + varData->wordDeltaCount = word_delta_count; + varData->longWords = long_words; + + if ( FT_FRAME_ENTER( region_idx_count * 2 ) ) + { + FT_TRACE2(( "tt_var_load_item_variation_store:" + " not enough data for region indices\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; for ( j = 0; j < varData->regionIdxCount; j++ ) { - if ( FT_READ_USHORT( varData->regionIndices[j] ) ) - goto Exit; + varData->regionIndices[j] = FT_NEXT_USHORT( bytes ); if ( varData->regionIndices[j] >= itemStore->regionCount ) { - FT_TRACE2(( "bad region index %d\n", + FT_TRACE2(( "bad region index %u\n", varData->regionIndices[j] )); + FT_FRAME_EXIT(); error = FT_THROW( Invalid_Table ); goto Exit; } } - /* Parse delta set. */ - /* */ - /* On input, deltas are (shortDeltaCount + regionIdxCount) bytes */ - /* each; on output, deltas are expanded to `regionIdxCount' shorts */ - /* each. */ - if ( FT_NEW_ARRAY( varData->deltaSet, - varData->regionIdxCount * varData->itemCount ) ) + FT_FRAME_EXIT(); + + per_region_size = word_delta_count + region_idx_count; + if ( long_words ) + per_region_size *= 2; + + if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) ) goto Exit; - - /* the delta set is stored as a 2-dimensional array of shorts; */ - /* sign-extend signed bytes to signed shorts */ - for ( j = 0; j < varData->itemCount * varData->regionIdxCount; ) + if ( FT_Stream_Read( stream, + varData->deltaSet, + per_region_size * item_count ) ) { - for ( k = 0; k < shortDeltaCount; k++, j++ ) - { - /* read the short deltas */ - FT_Short delta; - - - if ( FT_READ_SHORT( delta ) ) - goto Exit; - - varData->deltaSet[j] = delta; - } - - for ( ; k < varData->regionIdxCount; k++, j++ ) - { - /* read the (signed) byte deltas */ - FT_Char delta; - - - if ( FT_READ_CHAR( delta ) ) - goto Exit; - - varData->deltaSet[j] = delta; - } + FT_TRACE2(( "deltaSet read failed." )); + error = FT_THROW( Invalid_Table ); + goto Exit; } + + varData->itemCount = item_count; } Exit: @@ -625,47 +718,87 @@ } - static FT_Error - ft_var_load_delta_set_index_mapping( TT_Face face, + FT_LOCAL_DEF( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, /* TT_Face */ FT_ULong offset, GX_DeltaSetIdxMap map, - GX_ItemVarStore itemStore ) + GX_ItemVarStore itemStore, + FT_ULong table_len ) { FT_Stream stream = FT_FACE_STREAM( face ); FT_Memory memory = stream->memory; - FT_Error error; + FT_Error error; - FT_UShort format; - FT_UInt entrySize; - FT_UInt innerBitCount; - FT_UInt innerIndexMask; - FT_UInt i, j; + FT_Byte format; + FT_Byte entryFormat; + FT_UInt entrySize; + FT_UInt innerBitCount; + FT_UInt innerIndexMask; + FT_ULong i; + FT_UInt j; + FT_Byte* bytes; - if ( FT_STREAM_SEEK( offset ) || - FT_READ_USHORT( format ) || - FT_READ_USHORT( map->mapCount ) ) + if ( FT_STREAM_SEEK( offset ) || + FT_READ_BYTE( format ) || + FT_READ_BYTE( entryFormat ) ) goto Exit; - if ( format & 0xFFC0 ) + if ( format == 0 ) + { + if ( FT_READ_USHORT( map->mapCount ) ) + goto Exit; + } + else if ( format == 1 ) /* new in OpenType 1.9 */ + { + if ( FT_READ_ULONG( map->mapCount ) ) + goto Exit; + } + else { FT_TRACE2(( "bad map format %d\n", format )); error = FT_THROW( Invalid_Table ); goto Exit; } + if ( entryFormat & 0xC0 ) + { + FT_TRACE2(( "bad entry format %d\n", format )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + /* bytes per entry: 1, 2, 3, or 4 */ - entrySize = ( ( format & 0x0030 ) >> 4 ) + 1; - innerBitCount = ( format & 0x000F ) + 1; + entrySize = ( ( entryFormat & 0x30 ) >> 4 ) + 1; + innerBitCount = ( entryFormat & 0x0F ) + 1; innerIndexMask = ( 1 << innerBitCount ) - 1; + /* rough sanity check */ + if ( map->mapCount * entrySize > table_len ) + { + FT_TRACE1(( "tt_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) ) goto Exit; if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) ) goto Exit; + if ( FT_FRAME_ENTER( map->mapCount * entrySize ) ) + { + FT_TRACE2(( "tt_var_load_delta_set_index_mapping:" + " invalid number of delta-set index mappings\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + bytes = stream->cursor; + for ( i = 0; i < map->mapCount; i++ ) { FT_UInt mapData = 0; @@ -678,17 +811,25 @@ FT_Byte data; - if ( FT_READ_BYTE( data ) ) - goto Exit; - + data = FT_NEXT_BYTE( bytes ); mapData = ( mapData << 8 ) | data; } + /* new in OpenType 1.8.4 */ + if ( mapData == 0xFFFFFFFFUL ) + { + /* no variation data for this item */ + map->outerIndex[i] = 0xFFFFU; + map->innerIndex[i] = 0xFFFFU; + + continue; + } + outerIndex = mapData >> innerBitCount; if ( outerIndex >= itemStore->dataCount ) { - FT_TRACE2(( "outerIndex[%d] == %d out of range\n", + FT_TRACE2(( "outerIndex[%lu] == %u out of range\n", i, outerIndex )); error = FT_THROW( Invalid_Table ); @@ -701,7 +842,7 @@ if ( innerIndex >= itemStore->varData[outerIndex].itemCount ) { - FT_TRACE2(( "innerIndex[%d] == %d out of range\n", + FT_TRACE2(( "innerIndex[%lu] == %u out of range\n", i, innerIndex )); error = FT_THROW( Invalid_Table ); @@ -711,6 +852,8 @@ map->innerIndex[i] = innerIndex; } + FT_FRAME_EXIT(); + Exit: return error; } @@ -813,8 +956,8 @@ table = blend->hvar_table; } - error = ft_var_load_item_variation_store( - face, + error = tt_var_load_item_variation_store( + FT_FACE( face ), table_offset + store_offset, &table->itemStore ); if ( error ) @@ -822,11 +965,12 @@ if ( widthMap_offset ) { - error = ft_var_load_delta_set_index_mapping( - face, + error = tt_var_load_delta_set_index_mapping( + FT_FACE( face ), table_offset + widthMap_offset, &table->widthMap, - &table->itemStore ); + &table->itemStore, + table_len ); if ( error ) goto Exit; } @@ -863,88 +1007,262 @@ } - static FT_Int - ft_var_get_item_delta( TT_Face face, + static FT_Fixed + tt_calculate_scalar( GX_AxisCoords axis, + FT_UInt axisCount, + FT_Fixed* normalizedcoords ) + { + FT_Fixed scalar = 0x10000L; + FT_UInt j; + + + /* Inner loop steps through axes in this region. */ + for ( j = 0; j < axisCount; j++, axis++ ) + { + FT_Fixed ncv = normalizedcoords[j]; + + + /* Compute the scalar contribution of this axis, */ + /* with peak of 0 used for invalid axes. */ + if ( axis->peakCoord == ncv || + axis->peakCoord == 0 ) + continue; + + /* Ignore this region if coordinates are out of range. */ + else if ( ncv <= axis->startCoord || + ncv >= axis->endCoord ) + { + scalar = 0; + break; + } + + /* Cumulative product of all the axis scalars. */ + else if ( ncv < axis->peakCoord ) + scalar = FT_MulDiv( scalar, + ncv - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else /* ncv > axis->peakCoord */ + scalar = FT_MulDiv( scalar, + axis->endCoord - ncv, + axis->endCoord - axis->peakCoord ); + + } /* per-axis loop */ + + return scalar; + } + + + static FT_Int64 + ft_mul_add_delta_scalar( FT_Int64 returnValue, + FT_Int32 delta, + FT_Int32 scalar ) + { + +#ifdef FT_INT64 + + return returnValue + (FT_Int64)delta * scalar; + +#else /* !FT_INT64 */ + + if ( (FT_UInt32)( delta + 0x8000 ) <= 0x20000 ) + { + /* Fast path: multiplication result fits into 32 bits. */ + + FT_Int32 lo = delta * scalar; + + + returnValue.lo += (FT_UInt32)lo; + + if ( returnValue.lo < (FT_UInt32)lo ) + returnValue.hi += ( lo < 0 ) ? 0 : 1; + + if ( lo < 0 ) + returnValue.hi -= 1; + + return returnValue; + } + else + { + /* Slow path: full 32x32 -> 64-bit signed multiplication. */ + + FT_Int64 product; + + /* Get absolute values. */ + FT_UInt32 a = ( delta < 0 ) ? -delta : delta; + FT_UInt32 b = ( scalar < 0 ) ? -scalar : scalar; + + /* Prepare unsigned multiplication. */ + FT_UInt32 a_lo = a & 0xFFFF; + FT_UInt32 a_hi = a >> 16; + + FT_UInt32 b_lo = b & 0xFFFF; + FT_UInt32 b_hi = b >> 16; + + /* Partial products. */ + FT_UInt32 p0 = a_lo * b_lo; + FT_UInt32 p1 = a_lo * b_hi; + FT_UInt32 p2 = a_hi * b_lo; + FT_UInt32 p3 = a_hi * b_hi; + + /* Combine: result = p3 << 32 + (p1 + p2) << 16 + p0 */ + FT_UInt32 mid = p1 + p2; + FT_UInt32 mid_carry = ( mid < p1 ); + + FT_UInt32 carry; + + + product.lo = ( mid << 16 ) + ( p0 & 0xFFFF ); + carry = ( product.lo < ( p0 & 0xFFFF ) ) ? 1 : 0; + product.hi = p3 + ( mid >> 16 ) + mid_carry + carry; + + /* If result should be negative, negate. */ + if ( ( delta < 0 ) ^ ( scalar < 0 ) ) + { + product.lo = ~product.lo + 1; + product.hi = ~product.hi + ( product.lo == 0 ? 1 : 0 ); + } + + /* Add to `returnValue`. */ + returnValue.lo += product.lo; + if ( returnValue.lo < product.lo ) + returnValue.hi++; + returnValue.hi += product.hi; + + return returnValue; + } + +#endif /* !FT_INT64 */ + + } + + + static FT_ItemVarDelta + ft_round_and_shift16( FT_Int64 returnValue ) + { + +#ifdef FT_INT64 + + return (FT_ItemVarDelta)( returnValue + 0x8000L ) >> 16; + +#else /* !FT_INT64 */ + + FT_UInt hi = returnValue.hi; + FT_UInt lo = returnValue.lo; + + FT_UInt delta; + + + /* Add 0x8000 to round. */ + lo += 0x8000; + if ( lo < 0x8000 ) /* overflow occurred */ + hi += 1; + + /* Shift right by 16 bits. */ + delta = ( hi << 16 ) | ( lo >> 16 ); + + return (FT_ItemVarDelta)delta; + +#endif /* !FT_INT64 */ + + } + + + FT_LOCAL_DEF( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, /* TT_Face */ GX_ItemVarStore itemStore, FT_UInt outerIndex, FT_UInt innerIndex ) { + TT_Face ttface = (TT_Face)face; + GX_ItemVarData varData; - FT_Short* deltaSet; - FT_UInt master, j; - FT_Fixed netAdjustment = 0; /* accumulated adjustment */ - FT_Fixed scaledDelta; - FT_Fixed delta; + FT_UInt master; + FT_Int64 returnValue = FT_INT64_ZERO; + FT_UInt shift_base = 1; + FT_UInt per_region_size; + FT_Byte* bytes; + if ( !ttface->blend || !ttface->blend->normalizedcoords ) + return 0; + + /* OpenType 1.8.4+: No variation data for this item */ + /* as indices have special value 0xFFFF. */ + if ( outerIndex == 0xFFFF && innerIndex == 0xFFFF ) + return 0; + /* See pseudo code from `Font Variations Overview' */ /* in the OpenType specification. */ - varData = &itemStore->varData[outerIndex]; - deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex]; + if ( outerIndex >= itemStore->dataCount ) + return 0; /* Out of range. */ + + varData = &itemStore->varData[outerIndex]; + + if ( innerIndex >= varData->itemCount ) + return 0; /* Out of range. */ + + if ( varData->regionIdxCount == 0 ) + return 0; /* Avoid "applying zero offset to null pointer". */ + + /* Parse delta set. */ + /* */ + /* Deltas are (word_delta_count + region_idx_count) bytes each */ + /* if `longWords` isn't set, and twice as much otherwise. */ + per_region_size = varData->wordDeltaCount + varData->regionIdxCount; + if ( varData->longWords ) + { + shift_base = 2; + per_region_size *= 2; + } + + bytes = varData->deltaSet + per_region_size * innerIndex; /* outer loop steps through master designs to be blended */ for ( master = 0; master < varData->regionIdxCount; master++ ) { - FT_Fixed scalar = 0x10000L; - FT_UInt regionIndex = varData->regionIndices[master]; + FT_UInt regionIndex = varData->regionIndices[master]; GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; + FT_Fixed scalar = tt_calculate_scalar( + axis, + itemStore->axisCount, + ttface->blend->normalizedcoords ); - /* inner loop steps through axes in this region */ - for ( j = 0; j < itemStore->axisCount; j++, axis++ ) + + if ( scalar ) { - /* compute the scalar contribution of this axis; */ - /* ignore invalid ranges */ - if ( axis->startCoord > axis->peakCoord || - axis->peakCoord > axis->endCoord ) - continue; + FT_Int delta; - else if ( axis->startCoord < 0 && - axis->endCoord > 0 && - axis->peakCoord != 0 ) - continue; - /* peak of 0 means ignore this axis */ - else if ( axis->peakCoord == 0 ) - continue; - - else if ( face->blend->normalizedcoords[j] == axis->peakCoord ) - continue; - - /* ignore this region if coords are out of range */ - else if ( face->blend->normalizedcoords[j] <= axis->startCoord || - face->blend->normalizedcoords[j] >= axis->endCoord ) + if ( varData->longWords ) { - scalar = 0; - break; + if ( master < varData->wordDeltaCount ) + delta = FT_NEXT_LONG( bytes ); + else + delta = FT_NEXT_SHORT( bytes ); + } + else + { + if ( master < varData->wordDeltaCount ) + delta = FT_NEXT_SHORT( bytes ); + else + delta = FT_NEXT_CHAR( bytes ); } - /* cumulative product of all the axis scalars */ - else if ( face->blend->normalizedcoords[j] < axis->peakCoord ) - scalar = - FT_MulDiv( scalar, - face->blend->normalizedcoords[j] - axis->startCoord, - axis->peakCoord - axis->startCoord ); - else - scalar = - FT_MulDiv( scalar, - axis->endCoord - face->blend->normalizedcoords[j], - axis->endCoord - axis->peakCoord ); - } /* per-axis loop */ - - /* get the scaled delta for this region */ - delta = FT_intToFixed( deltaSet[master] ); - scaledDelta = FT_MulFix( scalar, delta ); - - /* accumulate the adjustments from each region */ - netAdjustment = netAdjustment + scaledDelta; + returnValue = ft_mul_add_delta_scalar( returnValue, delta, scalar ); + } + else + { + /* Branch-free, yay. */ + bytes += shift_base << ( master < varData->wordDeltaCount ); + } } /* per-region loop */ - return FT_fixedToInt( netAdjustment ); + return ft_round_and_shift16( returnValue ); } @@ -1037,35 +1355,27 @@ } else { - GX_ItemVarData varData; - - /* no widthMap data */ outerIndex = 0; innerIndex = gindex; - - varData = &table->itemStore.varData[outerIndex]; - if ( gindex >= varData->itemCount ) - { - FT_TRACE2(( "gindex %d out of range\n", gindex )); - error = FT_THROW( Invalid_Argument ); - goto Exit; - } } - delta = ft_var_get_item_delta( face, + delta = tt_var_get_item_delta( FT_FACE( face ), &table->itemStore, outerIndex, innerIndex ); - FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", - vertical ? "vertical height" : "horizontal width", - *avalue, - delta, - delta == 1 ? "" : "s", - vertical ? "VVAR" : "HVAR" )); + if ( delta ) + { + FT_TRACE5(( "%s value %d adjusted by %d unit%s (%s)\n", + vertical ? "vertical height" : "horizontal width", + *avalue, + delta, + delta == 1 ? "" : "s", + vertical ? "VVAR" : "HVAR" )); - *avalue += delta; + *avalue = ADD_INT( *avalue, delta ); + } Exit: return error; @@ -1073,20 +1383,20 @@ FT_LOCAL_DEF( FT_Error ) - tt_hadvance_adjust( TT_Face face, + tt_hadvance_adjust( FT_Face face, /* TT_Face */ FT_UInt gindex, FT_Int *avalue ) { - return tt_hvadvance_adjust( face, gindex, avalue, 0 ); + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 ); } FT_LOCAL_DEF( FT_Error ) - tt_vadvance_adjust( TT_Face face, + tt_vadvance_adjust( FT_Face face, /* TT_Face */ FT_UInt gindex, FT_Int *avalue ) { - return tt_hvadvance_adjust( face, gindex, avalue, 1 ); + return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 ); } @@ -1232,8 +1542,8 @@ records_offset = FT_STREAM_POS(); - error = ft_var_load_item_variation_store( - face, + error = tt_var_load_item_variation_store( + FT_FACE( face ), table_offset + store_offset, &blend->mvar_table->itemStore ); if ( error ) @@ -1248,7 +1558,7 @@ return; value = blend->mvar_table->values; - limit = value + blend->mvar_table->valueCount; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); itemStore = &blend->mvar_table->itemStore; for ( ; value < limit; value++ ) @@ -1257,6 +1567,13 @@ value->outerIndex = FT_GET_USHORT(); value->innerIndex = FT_GET_USHORT(); + /* new in OpenType 1.8.4 */ + if ( value->outerIndex == 0xFFFFU && value->innerIndex == 0xFFFFU ) + { + /* no variation data for this item */ + continue; + } + if ( value->outerIndex >= itemStore->dataCount || value->innerIndex >= itemStore->varData[value->outerIndex] .itemCount ) @@ -1274,7 +1591,7 @@ FT_TRACE2(( "loaded\n" )); value = blend->mvar_table->values; - limit = value + blend->mvar_table->valueCount; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); /* save original values of the data MVAR is going to modify */ for ( ; value < limit; value++ ) @@ -1299,15 +1616,14 @@ static FT_Error - tt_size_reset_iterator( FT_ListNode node, + ft_size_reset_iterator( FT_ListNode node, void* user ) { - TT_Size size = (TT_Size)node->data; - - FT_UNUSED( user ); + FT_Size size = (FT_Size)node->data; + FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user; - tt_size_reset( size, 1 ); + var->size_reset( size ); return FT_Err_Ok; } @@ -1326,33 +1642,36 @@ * The font face. */ FT_LOCAL_DEF( void ) - tt_apply_mvar( TT_Face face ) + tt_apply_mvar( FT_Face face ) /* TT_Face */ { - GX_Blend blend = face->blend; + TT_Face ttface = (TT_Face)face; + + GX_Blend blend = ttface->blend; GX_Value value, limit; + FT_Short mvar_hasc_delta = 0; FT_Short mvar_hdsc_delta = 0; FT_Short mvar_hlgp_delta = 0; - if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) + if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) return; value = blend->mvar_table->values; - limit = value + blend->mvar_table->valueCount; + limit = FT_OFFSET( value, blend->mvar_table->valueCount ); for ( ; value < limit; value++ ) { - FT_Short* p = ft_var_get_value_pointer( face, value->tag ); + FT_Short* p = ft_var_get_value_pointer( ttface, value->tag ); FT_Int delta; - delta = ft_var_get_item_delta( face, + delta = tt_var_get_item_delta( face, &blend->mvar_table->itemStore, value->outerIndex, value->innerIndex ); - if ( p ) + if ( p && delta ) { FT_TRACE5(( "value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n", (FT_Char)( value->tag >> 24 ), @@ -1380,7 +1699,8 @@ /* adjust all derived values */ { - FT_Face root = &face->root; + FT_Service_MetricsVariations var = + (FT_Service_MetricsVariations)ttface->face_var; /* * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender, @@ -1408,24 +1728,25 @@ * whether they were actually changed or the font had the OS/2 table's * fsSelection's bit 7 (USE_TYPO_METRICS) set. */ - FT_Short current_line_gap = root->height - root->ascender + - root->descender; + FT_Short current_line_gap = face->height - face->ascender + + face->descender; - root->ascender = root->ascender + mvar_hasc_delta; - root->descender = root->descender + mvar_hdsc_delta; - root->height = root->ascender - root->descender + + face->ascender = face->ascender + mvar_hasc_delta; + face->descender = face->descender + mvar_hdsc_delta; + face->height = face->ascender - face->descender + current_line_gap + mvar_hlgp_delta; - root->underline_position = face->postscript.underlinePosition - - face->postscript.underlineThickness / 2; - root->underline_thickness = face->postscript.underlineThickness; + face->underline_position = ttface->postscript.underlinePosition - + ttface->postscript.underlineThickness / 2; + face->underline_thickness = ttface->postscript.underlineThickness; - /* iterate over all FT_Size objects and call `tt_size_reset' */ - /* to propagate the metrics changes */ - FT_List_Iterate( &root->sizes_list, - tt_size_reset_iterator, - NULL ); + /* iterate over all FT_Size objects and call `var->size_reset' */ + /* to propagate the metrics changes */ + if ( var && var->size_reset ) + FT_List_Iterate( &face->sizes_list, + ft_size_reset_iterator, + (void*)var ); } } @@ -1467,9 +1788,11 @@ GX_Blend blend = face->blend; FT_Error error; FT_UInt i, j; + FT_Byte* bytes; FT_ULong table_len; FT_ULong gvar_start; FT_ULong offsetToData; + FT_ULong offsets_len; GX_GVar_Head gvar_head; static const FT_Frame_Field gvar_fields[] = @@ -1514,8 +1837,9 @@ if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) { - FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n" - " table are different\n" )); + FT_TRACE1(( "ft_var_load_gvar:" + " number of axes in `gvar' and `cvar'\n" )); + FT_TRACE1(( " table are different\n" )); error = FT_THROW( Invalid_Table ); goto Exit; } @@ -1530,9 +1854,13 @@ goto Exit; } - /* rough sanity check: offsets can be either 2 or 4 bytes */ - if ( (FT_ULong)gvar_head.glyphCount * - ( ( gvar_head.flags & 1 ) ? 4 : 2 ) > table_len ) + /* offsets can be either 2 or 4 bytes */ + /* (one more offset than glyphs, to mark size of last) */ + offsets_len = ( gvar_head.glyphCount + 1 ) * + ( ( gvar_head.flags & 1 ) ? 4L : 2L ); + + /* rough sanity check */ + if (offsets_len > table_len ) { FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" )); error = FT_THROW( Invalid_Table ); @@ -1541,93 +1869,140 @@ FT_TRACE2(( "loaded\n" )); - blend->gvar_size = table_len; - blend->tuplecount = gvar_head.globalCoordCount; - blend->gv_glyphcnt = gvar_head.glyphCount; - offsetToData = gvar_start + gvar_head.offsetToData; + blend->gvar_size = table_len; + offsetToData = gvar_start + gvar_head.offsetToData; FT_TRACE5(( "gvar: there %s %d shared coordinate%s:\n", - blend->tuplecount == 1 ? "is" : "are", - blend->tuplecount, - blend->tuplecount == 1 ? "" : "s" )); + gvar_head.globalCoordCount == 1 ? "is" : "are", + gvar_head.globalCoordCount, + gvar_head.globalCoordCount == 1 ? "" : "s" )); - if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) ) + if ( FT_FRAME_ENTER( offsets_len ) ) goto Exit; + bytes = stream->cursor; + + /* offsets (one more offset than glyphs, to mark size of last) */ + if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) ) + goto Fail2; + if ( gvar_head.flags & 1 ) { - FT_ULong limit = gvar_start + table_len; + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; - /* 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++ ) + if ( stream->limit - stream->cursor < gvar_head.glyphCount * 4 ) { - blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); - /* use `>', not `>=' */ - if ( blend->glyphoffsets[i] > limit ) + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset not enough\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_NEXT_ULONG( bytes ); + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else { FT_TRACE2(( "ft_var_load_gvar:" - " invalid glyph variation data offset for index %d\n", + " glyph variation data offset %u not monotonic\n", i )); - error = FT_THROW( Invalid_Table ); - break; + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %u out of range\n", + i )); + blend->glyphoffsets[i] = limit; } } } else { - FT_ULong limit = gvar_start + table_len; + FT_ULong limit = gvar_start + table_len; + FT_ULong max_offset = 0; - /* 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++ ) + if ( stream->limit - stream->cursor < gvar_head.glyphCount * 2 ) { - blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; - /* use `>', not `>=' */ - if ( blend->glyphoffsets[i] > limit ) + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset not enough\n" )); + error = FT_THROW( Invalid_Table ); + goto Fail; + } + + for ( i = 0; i <= gvar_head.glyphCount; i++ ) + { + blend->glyphoffsets[i] = offsetToData + FT_NEXT_USHORT( bytes ) * 2; + + if ( max_offset <= blend->glyphoffsets[i] ) + max_offset = blend->glyphoffsets[i]; + else { FT_TRACE2(( "ft_var_load_gvar:" - " invalid glyph variation data offset for index %d\n", + " glyph variation data offset %u not monotonic\n", i )); - error = FT_THROW( Invalid_Table ); - break; + blend->glyphoffsets[i] = max_offset; + } + + /* use `<', not `<=' */ + if ( limit < blend->glyphoffsets[i] ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation data offset %u out of range\n", + i )); + blend->glyphoffsets[i] = limit; } } } + blend->gv_glyphcnt = gvar_head.glyphCount; + FT_FRAME_EXIT(); - if ( error ) - goto Exit; - if ( blend->tuplecount != 0 ) + if ( gvar_head.globalCoordCount != 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( gvar_head.globalCoordCount * + gvar_head.axisCount * 2L ) ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " glyph variation shared tuples missing\n" )); + goto Fail; + } - if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) || - FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) ) - goto Exit; + bytes = stream->cursor; - for ( i = 0; i < blend->tuplecount; i++ ) + if ( FT_QNEW_ARRAY( blend->tuplecoords, + gvar_head.axisCount * gvar_head.globalCoordCount ) ) + goto Fail2; + + for ( i = 0; i < gvar_head.globalCoordCount; i++ ) { FT_TRACE5(( " [ " )); for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) { blend->tuplecoords[i * gvar_head.axisCount + j] = - FT_fdot14ToFixed( FT_GET_SHORT() ); + FT_fdot14ToFixed( FT_NEXT_SHORT( bytes ) ); FT_TRACE5(( "%.5f ", - blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); + (double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 )); } FT_TRACE5(( "]\n" )); } + if ( FT_NEW_ARRAY( blend->tuplescalars, + gvar_head.globalCoordCount ) ) + goto Fail2; + + blend->tuplecount = gvar_head.globalCoordCount; + FT_TRACE5(( "\n" )); FT_FRAME_EXIT(); @@ -1635,6 +2010,14 @@ Exit: return error; + + Fail2: + FT_FRAME_EXIT(); + + Fail: + FT_FREE( blend->glyphoffsets ); + blend->gv_glyphcnt = 0; + goto Exit; } @@ -1683,31 +2066,30 @@ for ( i = 0; i < blend->num_axis; i++ ) { - FT_TRACE6(( " axis %d coordinate %.5f:\n", - i, blend->normalizedcoords[i] / 65536.0 )); + FT_Fixed ncv; - /* 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. */ if ( tuple_coords[i] == 0 ) { - FT_TRACE6(( " tuple coordinate is zero, ignore\n", i )); + FT_TRACE6(( " tuple coordinate is zero, ignore\n" )); continue; } - if ( blend->normalizedcoords[i] == 0 ) + ncv = blend->normalizedcoords[i]; + + FT_TRACE6(( " axis %u coordinate %.5f:\n", i, (double)ncv / 65536 )); + + if ( ncv == 0 ) { FT_TRACE6(( " axis coordinate is zero, stop\n" )); apply = 0; break; } - if ( blend->normalizedcoords[i] == tuple_coords[i] ) + if ( tuple_coords[i] == ncv ) { FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n", - tuple_coords[i] / 65536.0 )); + (double)tuple_coords[i] / 65536 )); /* `apply' does not change */ continue; } @@ -1716,51 +2098,51 @@ { /* not an intermediate tuple */ - if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) || - blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) ) + if ( ( tuple_coords[i] > ncv && ncv > 0 ) || + ( tuple_coords[i] < ncv && ncv < 0 ) ) + { + FT_TRACE6(( " tuple coordinate %.5f fits\n", + (double)tuple_coords[i] / 65536 )); + apply = FT_MulDiv( apply, ncv, tuple_coords[i] ); + } + else { FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n", - tuple_coords[i] / 65536.0 )); + (double)tuple_coords[i] / 65536 )); apply = 0; break; } - - FT_TRACE6(( " tuple coordinate %.5f fits\n", - tuple_coords[i] / 65536.0 )); - apply = FT_MulDiv( apply, - blend->normalizedcoords[i], - tuple_coords[i] ); } else { /* intermediate tuple */ - if ( blend->normalizedcoords[i] <= im_start_coords[i] || - blend->normalizedcoords[i] >= im_end_coords[i] ) + if ( ncv <= im_start_coords[i] || + ncv >= im_end_coords[i] ) { FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ is exceeded," " stop\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); apply = 0; break; } FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); - if ( blend->normalizedcoords[i] < tuple_coords[i] ) + (double)im_start_coords[i] / 65536, + (double)im_end_coords[i] / 65536 )); + if ( ncv < tuple_coords[i] ) apply = FT_MulDiv( apply, - blend->normalizedcoords[i] - im_start_coords[i], + ncv - im_start_coords[i], tuple_coords[i] - im_start_coords[i] ); - else + else /* ncv > tuple_coords[i] */ apply = FT_MulDiv( apply, - im_end_coords[i] - blend->normalizedcoords[i], + im_end_coords[i] - ncv, im_end_coords[i] - tuple_coords[i] ); } } - FT_TRACE6(( " apply factor is %.5f\n", apply / 65536.0 )); + FT_TRACE6(( " apply factor is %.5f\n", (double)apply / 65536 )); return apply; } @@ -1774,12 +2156,18 @@ FT_Fixed* coords, FT_Fixed* normalized ) { + FT_Error error = FT_Err_Ok; + FT_Memory memory = face->root.memory; + FT_UInt i, j; + GX_Blend blend; FT_MM_Var* mmvar; - FT_UInt i, j; FT_Var_Axis* a; GX_AVarSegment av; + FT_Fixed* new_normalized = NULL; + FT_Fixed* old_normalized; + blend = face->blend; mmvar = blend->mmvar; @@ -1787,7 +2175,7 @@ if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "ft_var_to_normalized:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } @@ -1802,28 +2190,25 @@ FT_Fixed coord = coords[i]; - FT_TRACE5(( " %d: %.5f\n", i, coord / 65536.0 )); + FT_TRACE5(( " %u: %.5f\n", i, (double)coord / 65536 )); if ( coord > a->maximum || coord < a->minimum ) { - FT_TRACE1(( - "ft_var_to_normalized: design coordinate %.5f\n" - " is out of range [%.5f;%.5f]; clamping\n", - coord / 65536.0, - a->minimum / 65536.0, - a->maximum / 65536.0 )); - - if ( coord > a->maximum ) - coord = a->maximum; - else - coord = a->minimum; + FT_TRACE1(( "ft_var_to_normalized: design coordinate %.5f\n", + (double)coord / 65536 )); + FT_TRACE1(( " is out of range [%.5f;%.5f];" + " clamping\n", + (double)a->minimum / 65536, + (double)a->maximum / 65536 )); } - if ( coord < a->def ) - normalized[i] = -FT_DivFix( SUB_LONG( coord, a->def ), - SUB_LONG( a->minimum, a->def ) ); - else if ( coord > a->def ) - normalized[i] = FT_DivFix( SUB_LONG( coord, a->def ), + if ( coord > a->def ) + normalized[i] = coord >= a->maximum ? 0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), SUB_LONG( a->maximum, a->def ) ); + else if ( coord < a->def ) + normalized[i] = coord <= a->minimum ? -0x10000L : + FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->def, a->minimum ) ); else normalized[i] = 0; } @@ -1833,31 +2218,93 @@ for ( ; i < mmvar->num_axis; i++ ) normalized[i] = 0; - if ( blend->avar_segment ) + if ( blend->avar_table ) { + GX_AVarTable table = blend->avar_table; + + FT_TRACE5(( "normalized design coordinates" " before applying `avar' data:\n" )); - av = blend->avar_segment; - for ( i = 0; i < mmvar->num_axis; i++, av++ ) + if ( table->avar_segment ) { - for ( j = 1; j < (FT_UInt)av->pairCount; j++ ) - { - if ( normalized[i] < av->correspondence[j].fromCoord ) - { - FT_TRACE5(( " %.5f\n", normalized[i] / 65536.0 )); + av = table->avar_segment; - normalized[i] = - FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, - av->correspondence[j].toCoord - - av->correspondence[j - 1].toCoord, - av->correspondence[j].fromCoord - - av->correspondence[j - 1].fromCoord ) + - av->correspondence[j - 1].toCoord; - break; + 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 ) + { + FT_TRACE5(( " %.5f\n", (double)normalized[i] / 65536 )); + + normalized[i] = + FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord, + av->correspondence[j].toCoord - + av->correspondence[j - 1].toCoord, + av->correspondence[j].fromCoord - + av->correspondence[j - 1].fromCoord ) + + av->correspondence[j - 1].toCoord; + break; + } } } } + + if ( table->itemStore.varData ) + { + if ( FT_QNEW_ARRAY( new_normalized, mmvar->num_axis ) ) + return; + + /* Install our half-normalized coordinates for the next */ + /* Item Variation Store to work with. */ + old_normalized = face->blend->normalizedcoords; + face->blend->normalizedcoords = normalized; + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + FT_Fixed v = normalized[i]; + FT_UInt innerIndex = i; + FT_UInt outerIndex = 0; + FT_Int delta; + + + if ( table->axisMap.innerIndex ) + { + FT_UInt idx = i; + + + if ( idx >= table->axisMap.mapCount ) + idx = table->axisMap.mapCount - 1; + + outerIndex = table->axisMap.outerIndex[idx]; + innerIndex = table->axisMap.innerIndex[idx]; + } + + delta = tt_var_get_item_delta( FT_FACE( face ), + &table->itemStore, + outerIndex, + innerIndex ); + + /* Convert delta in F2DOT14 to 16.16 before adding. */ + v += MUL_INT( delta, 4 ); + + /* Clamp value to range [-1, 1]. */ + v = v >= 0x10000L ? 0x10000 : v; + v = v <= -0x10000L ? -0x10000 : v; + + new_normalized[i] = v; + } + + for ( i = 0; i < mmvar->num_axis; i++ ) + { + normalized[i] = new_normalized[i]; + } + + face->blend->normalizedcoords = old_normalized; + + FT_FREE( new_normalized ); + } } } @@ -1883,7 +2330,7 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "ft_var_to_design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -1894,9 +2341,9 @@ for ( ; i < num_coords; i++ ) design[i] = 0; - if ( blend->avar_segment ) + if ( blend->avar_table && blend->avar_table->avar_segment ) { - GX_AVarSegment av = blend->avar_segment; + GX_AVarSegment av = blend->avar_table->avar_segment; FT_TRACE5(( "design coordinates" @@ -1916,7 +2363,7 @@ av->correspondence[j - 1].toCoord ) + av->correspondence[j - 1].fromCoord; - FT_TRACE5(( " %.5f\n", design[i] / 65536.0 )); + FT_TRACE5(( " %.5f\n", (double)design[i] / 65536 )); break; } } @@ -1997,11 +2444,12 @@ * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - TT_Get_MM_Var( TT_Face face, + TT_Get_MM_Var( FT_Face face, /* TT_Face */ FT_MM_Var* *master ) { - FT_Stream stream = face->root.stream; - FT_Memory memory = face->root.memory; + TT_Face ttface = (TT_Face)face; + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = FT_FACE_MEMORY( face ); FT_ULong table_len; FT_Error error = FT_Err_Ok; FT_ULong fvar_start = 0; @@ -2013,7 +2461,7 @@ FT_Var_Axis* a; FT_Fixed* c; FT_Var_Named_Style* ns; - GX_FVar_Head fvar_head; + GX_FVar_Head fvar_head = { 0, 0, 0, 0, 0, 0 }; FT_Bool usePsName = 0; FT_UInt num_instances; FT_UInt num_axes; @@ -2061,32 +2509,23 @@ FT_FRAME_END }; + /* `num_instances` holds the number of all named instances including */ + /* the default instance, which might be missing in the table of named */ + /* instances (in 'fvar'). This value is validated in `sfobjs.c` and */ + /* may be reset to 0 if consistency checks fail. */ + num_instances = (FT_UInt)face->style_flags >> 16; /* read the font data and set up the internal representation */ /* if not already done */ - need_init = !face->blend; + need_init = !ttface->blend; if ( need_init ) { FT_TRACE2(( "FVAR " )); - /* both `fvar' and `gvar' must be present */ - if ( FT_SET_ERROR( face->goto_table( face, TTAG_gvar, - stream, &table_len ) ) ) - { - /* CFF2 is an alternate to gvar here */ - if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2, + if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar, stream, &table_len ) ) ) - { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" )); - goto Exit; - } - } - - if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar, - stream, &table_len ) ) ) { FT_TRACE1(( "is missing\n" )); goto Exit; @@ -2099,6 +2538,17 @@ if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) goto Exit; + /* If `num_instances` is larger, synthetization of the default */ + /* instance is required. If `num_instances` is smaller, */ + /* however, the value has been reset to 0 in `sfnt_init_face` */ + /* (in `sfobjs.c`); in this case we have underallocated `mmvar` */ + /* structs. */ + if ( num_instances < fvar_head.instanceCount ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + usePsName = FT_BOOL( fvar_head.instanceSize == 6 + 4 * fvar_head.axisCount ); @@ -2108,26 +2558,21 @@ fvar_head.axisCount, fvar_head.axisCount == 1 ? "is" : "es" )); - if ( FT_NEW( face->blend ) ) + if ( FT_NEW( ttface->blend ) ) goto Exit; - num_axes = fvar_head.axisCount; - face->blend->num_axis = num_axes; + num_axes = fvar_head.axisCount; + ttface->blend->num_axis = num_axes; } else - num_axes = face->blend->num_axis; - - /* `num_instances' holds the number of all named instances, */ - /* including the default instance which might be missing */ - /* in fvar's table of named instances */ - num_instances = (FT_UInt)face->root.style_flags >> 16; + num_axes = ttface->blend->num_axis; /* prepare storage area for MM data; this cannot overflow */ /* 32-bit arithmetic because of the size limits used in the */ /* `fvar' table validity check in `sfnt_init_face' */ /* the various `*_size' variables, which we also use as */ - /* offsets into the `mmlen' array, must be multiples of the */ + /* offsets into the `mmvar' array, must be multiples of the */ /* pointer size (except the last one); without such an */ /* alignment there might be runtime errors due to */ /* misaligned addresses */ @@ -2149,16 +2594,16 @@ if ( need_init ) { - face->blend->mmvar_len = mmvar_size + - axis_flags_size + - axis_size + - namedstyle_size + - next_coords_size + - next_name_size; + ttface->blend->mmvar_len = mmvar_size + + axis_flags_size + + axis_size + + namedstyle_size + + next_coords_size + + next_name_size; - if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) ) goto Exit; - face->blend->mmvar = mmvar; + ttface->blend->mmvar = mmvar; /* set up pointers and offsets into the `mmvar' array; */ /* the data gets filled in later on */ @@ -2245,13 +2690,13 @@ " minimum default maximum flags\n" )); /* " XXXX.XXXXX XXXX.XXXXX XXXX.XXXXX 0xXXXX" */ - FT_TRACE5(( " %3d `%s'" + FT_TRACE5(( " %3u `%s'" " %10.5f %10.5f %10.5f 0x%04X%s\n", i, a->name, - a->minimum / 65536.0, - a->def / 65536.0, - a->maximum / 65536.0, + (double)a->minimum / 65536, + (double)a->def / 65536, + (double)a->maximum / 65536, *axis_flags, invalid ? " (invalid, disabled)" : "" )); #endif @@ -2264,27 +2709,27 @@ /* named instance coordinates are stored as design coordinates; */ /* we have to convert them to normalized coordinates also */ - if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords, + if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords, num_axes * num_instances ) ) goto Exit; - if ( fvar_head.instanceCount && !face->blend->avar_loaded ) + if ( fvar_head.instanceCount && !ttface->blend->avar_loaded ) { FT_ULong offset = FT_STREAM_POS(); - ft_var_load_avar( face ); + ft_var_load_avar( ttface ); if ( FT_STREAM_SEEK( offset ) ) goto Exit; } - FT_TRACE5(( "%d instance%s\n", + FT_TRACE5(( "%d named instance%s\n", fvar_head.instanceCount, fvar_head.instanceCount == 1 ? "" : "s" )); ns = mmvar->namedstyle; - nsc = face->blend->normalized_stylecoords; + nsc = ttface->blend->normalized_stylecoords; for ( i = 0; i < fvar_head.instanceCount; i++, ns++ ) { /* PostScript names add 2 bytes to the instance record size */ @@ -2307,7 +2752,7 @@ #ifdef FT_DEBUG_LEVEL_TRACE { - SFNT_Service sfnt = (SFNT_Service)face->sfnt; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; FT_String* strname = NULL; FT_String* psname = NULL; @@ -2319,7 +2764,7 @@ if ( ns->strid != 0xFFFF ) { - (void)sfnt->get_name( face, + (void)sfnt->get_name( ttface, (FT_UShort)ns->strid, &strname ); if ( strname && !ft_strcmp( strname, ".notdef" ) ) @@ -2328,7 +2773,7 @@ if ( ns->psid != 0xFFFF ) { - (void)sfnt->get_name( face, + (void)sfnt->get_name( ttface, (FT_UShort)ns->psid, &psname ); if ( psname && !ft_strcmp( psname, ".notdef" ) ) @@ -2337,7 +2782,7 @@ (void)FT_STREAM_SEEK( pos ); - FT_TRACE5(( " instance %d (%s%s%s, %s%s%s)\n", + FT_TRACE5(( " named instance %u (%s%s%s, %s%s%s)\n", i, strname ? "name: `" : "", strname ? strname : "unnamed", @@ -2351,7 +2796,7 @@ } #endif /* FT_DEBUG_LEVEL_TRACE */ - ft_var_to_normalized( face, num_axes, ns->coords, nsc ); + ft_var_to_normalized( ttface, num_axes, ns->coords, nsc ); nsc += num_axes; FT_FRAME_EXIT(); @@ -2359,15 +2804,17 @@ if ( num_instances != fvar_head.instanceCount ) { - SFNT_Service sfnt = (SFNT_Service)face->sfnt; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; FT_Int found, dummy1, dummy2; FT_UInt strid = ~0U; - /* the default instance is missing in array the */ - /* of named instances; try to synthesize an entry */ - found = sfnt->get_name_id( face, + /* The default instance is missing in the array */ + /* of named instances; try to synthesize an entry. */ + /* If this fails, `default_named_instance` remains */ + /* at value zero, which doesn't do any harm. */ + found = sfnt->get_name_id( ttface, TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, &dummy1, &dummy2 ); @@ -2375,7 +2822,7 @@ strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY; else { - found = sfnt->get_name_id( face, + found = sfnt->get_name_id( ttface, TT_NAME_ID_FONT_SUBFAMILY, &dummy1, &dummy2 ); @@ -2385,7 +2832,7 @@ if ( found ) { - found = sfnt->get_name_id( face, + found = sfnt->get_name_id( ttface, TT_NAME_ID_PS_NAME, &dummy1, &dummy2 ); @@ -2394,6 +2841,9 @@ FT_TRACE5(( "TT_Get_MM_Var:" " Adding default instance to named instances\n" )); + /* named instance indices start with value 1 */ + ttface->var_default_named_instance = num_instances; + ns = &mmvar->namedstyle[fvar_head.instanceCount]; ns->strid = strid; @@ -2407,7 +2857,7 @@ } } - ft_var_load_mvar( face ); + ft_var_load_mvar( ttface ); } /* fill the output array if requested */ @@ -2417,9 +2867,8 @@ FT_UInt n; - if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) + if ( FT_DUP( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ) ) goto Exit; - FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len ); axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); @@ -2452,6 +2901,8 @@ a->name = (char*)"OpticalSize"; else if ( a->tag == TTAG_slnt ) a->name = (char*)"Slant"; + else if ( a->tag == TTAG_ital ) + a->name = (char*)"Italic"; next_name += 5; a++; @@ -2489,11 +2940,19 @@ } manageCvt; - face->doblend = FALSE; - if ( !face->blend ) { - if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + face->doblend = FALSE; + for ( i = 0; i < num_coords; i++ ) + if ( coords[i] ) + { + face->doblend = TRUE; + break; + } + if ( !face->doblend ) + goto Exit; + + if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) ) goto Exit; } @@ -2503,22 +2962,22 @@ if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "TT_Set_MM_Blend:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } - FT_TRACE5(( "TT_Set_MM_Blend:\n" - " normalized design coordinates:\n" )); + FT_TRACE5(( "TT_Set_MM_Blend:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); for ( i = 0; i < num_coords; i++ ) { - FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 )); + FT_TRACE5(( " %.5f\n", (double)coords[i] / 65536 )); if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L ) { - FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n" - " is out of range [-1;1]\n", - coords[i] / 65536.0 )); + FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n", + (double)coords[i] / 65536 )); + FT_TRACE1(( " is out of range [-1;1]\n" )); error = FT_THROW( Invalid_Argument ); goto Exit; } @@ -2527,8 +2986,16 @@ FT_TRACE5(( "\n" )); if ( !face->is_cff2 && !blend->glyphoffsets ) - if ( FT_SET_ERROR( ft_var_load_gvar( face ) ) ) + { + /* While a missing 'gvar' table is acceptable, for example for */ + /* fonts that only vary metrics information or 'COLR' v1 */ + /* `PaintVar*` tables, an incorrect SFNT table offset or size */ + /* for 'gvar', or an inconsistent 'gvar' table is not. */ + error = ft_var_load_gvar( face ); + if ( error != FT_Err_Table_Missing && error != FT_Err_Ok ) goto Exit; + error = FT_Err_Ok; + } if ( !blend->coords ) { @@ -2570,35 +3037,34 @@ } } - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + if ( !have_diff ) { - FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16; + if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + { + FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16; - c = blend->normalizedcoords + i; - n = blend->normalized_stylecoords + - ( instance_index - 1 ) * mmvar->num_axis + - i; + c = blend->normalizedcoords + i; + n = blend->normalized_stylecoords + + ( instance_index - 1 ) * mmvar->num_axis + + i; - for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) - if ( *c != *n ) - have_diff = 1; - } - else - { - c = blend->normalizedcoords + i; - for ( j = i; j < mmvar->num_axis; j++, c++ ) - if ( *c != 0 ) - have_diff = 1; + for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) + if ( *c != *n ) + have_diff = 1; + } + else + { + c = blend->normalizedcoords + i; + for ( j = i; j < mmvar->num_axis; j++, c++ ) + if ( *c != 0 ) + have_diff = 1; + } } /* return value -1 indicates `no change' */ if ( !have_diff ) - { - face->doblend = TRUE; - return -1; - } for ( ; i < mmvar->num_axis; i++ ) { @@ -2616,9 +3082,10 @@ } blend->num_axis = mmvar->num_axis; - FT_MEM_COPY( blend->normalizedcoords, - coords, - num_coords * sizeof ( FT_Fixed ) ); + if ( coords ) + FT_MEM_COPY( blend->normalizedcoords, + coords, + num_coords * sizeof ( FT_Fixed ) ); if ( set_design_coords ) ft_var_to_design( face, @@ -2626,7 +3093,15 @@ blend->normalizedcoords, blend->coords ); - face->doblend = TRUE; + face->doblend = FALSE; + for ( i = 0; i < blend->num_axis; i++ ) + { + if ( blend->normalizedcoords[i] ) + { + face->doblend = TRUE; + break; + } + } if ( face->cvt ) { @@ -2636,7 +3111,6 @@ /* 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; error = tt_face_load_cvt( face, face->root.stream ); break; @@ -2653,9 +3127,8 @@ } } - /* enforce recomputation of the PostScript name; */ - FT_FREE( face->postscript_name ); - face->postscript_name = NULL; + for ( i = 0 ; i < blend->tuplecount ; i++ ) + blend->tuplescalars[i] = (FT_Fixed)-0x20000L; Exit: return error; @@ -2688,26 +3161,32 @@ * An array of `num_coords', each between [-1,1]. * * @Return: - * FreeType error code. 0 means success. + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. */ FT_LOCAL_DEF( FT_Error ) - TT_Set_MM_Blend( TT_Face face, + TT_Set_MM_Blend( FT_Face face, /* TT_Face */ FT_UInt num_coords, FT_Fixed* coords ) { FT_Error error; - error = tt_set_mm_blend( face, num_coords, coords, 1 ); - if ( error ) - return error; + error = tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 ); + if ( error == FT_Err_Ok ) + { + FT_UInt i; - if ( num_coords ) - face->root.face_flags |= FT_FACE_FLAG_VARIATION; - else - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; - return FT_Err_Ok; + for ( i = 0; i < num_coords; i++ ) + if ( coords[i] ) + { + error = -2; /* -2 means is_variable. */ + break; + } + } + + return error; } @@ -2735,31 +3214,34 @@ * An array of `num_coords', each between [-1,1]. * * @Return: - * FreeType error code. 0 means success. + * FreeType error code. 0 means success, -1 means success and unchanged + * axis values. */ FT_LOCAL_DEF( FT_Error ) - TT_Get_MM_Blend( TT_Face face, + TT_Get_MM_Blend( FT_Face face, /* TT_Face */ FT_UInt num_coords, FT_Fixed* coords ) { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; GX_Blend blend; FT_UInt i, nc; - if ( !face->blend ) + if ( !ttface->blend ) { if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) return error; } - blend = face->blend; + blend = ttface->blend; if ( !blend->coords ) { /* select default instance coordinates */ /* if no instance is selected yet */ - if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) return error; } @@ -2767,12 +3249,12 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "TT_Get_MM_Blend:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } - if ( face->doblend ) + if ( ttface->doblend ) { for ( i = 0; i < nc; i++ ) coords[i] = blend->normalizedcoords[i]; @@ -2819,15 +3301,16 @@ * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - TT_Set_Var_Design( TT_Face face, + TT_Set_Var_Design( FT_Face face, /* TT_Face */ FT_UInt num_coords, FT_Fixed* coords ) { + TT_Face ttface = (TT_Face)face; FT_Error error = FT_Err_Ok; GX_Blend blend; FT_MM_Var* mmvar; FT_UInt i; - FT_Memory memory = face->root.memory; + FT_Memory memory = FT_FACE_MEMORY( face ); FT_Fixed* c; FT_Fixed* n; @@ -2836,19 +3319,19 @@ FT_Bool have_diff = 0; - if ( !face->blend ) + if ( !ttface->blend ) { if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) goto Exit; } - blend = face->blend; + blend = ttface->blend; mmvar = blend->mmvar; if ( num_coords > mmvar->num_axis ) { FT_TRACE2(( "TT_Set_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", mmvar->num_axis, num_coords )); num_coords = mmvar->num_axis; } @@ -2870,13 +3353,13 @@ } } - if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) + if ( FT_IS_NAMED_INSTANCE( face ) ) { FT_UInt instance_index; FT_Var_Named_Style* named_style; - instance_index = (FT_UInt)face->root.face_index >> 16; + instance_index = (FT_UInt)face->face_index >> 16; named_style = mmvar->namedstyle + instance_index - 1; n = named_style->coords + num_coords; @@ -2913,21 +3396,25 @@ if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) ) goto Exit; - if ( !face->blend->avar_loaded ) - ft_var_load_avar( face ); + if ( !ttface->blend->avar_loaded ) + ft_var_load_avar( ttface ); - FT_TRACE5(( "TT_Set_Var_Design:\n" - " normalized design coordinates:\n" )); - ft_var_to_normalized( face, num_coords, blend->coords, normalized ); + FT_TRACE5(( "TT_Set_Var_Design:\n" )); + FT_TRACE5(( " normalized design coordinates:\n" )); + ft_var_to_normalized( ttface, num_coords, blend->coords, normalized ); - error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 ); + error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 ); if ( error ) goto Exit; - if ( num_coords ) - face->root.face_flags |= FT_FACE_FLAG_VARIATION; - else - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; + for ( i = 0; i < num_coords; i++ ) + { + if ( normalized[i] ) + { + error = -2; /* -2 means is_variable. */ + break; + } + } Exit: FT_FREE( normalized ); @@ -2961,28 +3448,31 @@ * FreeType error code. 0~means success. */ FT_LOCAL_DEF( FT_Error ) - TT_Get_Var_Design( TT_Face face, + TT_Get_Var_Design( FT_Face face, /* TT_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Error error = FT_Err_Ok; - GX_Blend blend; - FT_UInt i, nc; + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + GX_Blend blend; + FT_MM_Var* mmvar; + FT_Var_Axis* a; + FT_UInt i, nc; - if ( !face->blend ) + if ( !ttface->blend ) { if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) return error; } - blend = face->blend; + blend = ttface->blend; if ( !blend->coords ) { /* select default instance coordinates */ /* if no instance is selected yet */ - if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) ) + if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) ) return error; } @@ -2990,24 +3480,26 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "TT_Get_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } - if ( face->doblend ) + mmvar = blend->mmvar; + a = mmvar->axis; + if ( ttface->doblend ) { - for ( i = 0; i < nc; i++ ) + for ( i = 0; i < nc; i++, a++ ) coords[i] = blend->coords[i]; } else { - for ( i = 0; i < nc; i++ ) - coords[i] = 0; + for ( i = 0; i < nc; i++, a++ ) + coords[i] = a->def; } - for ( ; i < num_coords; i++ ) - coords[i] = 0; + for ( ; i < num_coords; i++, a++ ) + coords[i] = a->def; return FT_Err_Ok; } @@ -3031,38 +3523,44 @@ * Value 0 indicates to not use an instance. * * @Return: - * FreeType error code. 0~means success. + * FreeType error code. 0~means success, -1 means success and unchanged + * axis values. */ FT_LOCAL_DEF( FT_Error ) - TT_Set_Named_Instance( TT_Face face, + TT_Set_Named_Instance( FT_Face face, /* TT_Face */ FT_UInt instance_index ) { - FT_Error error = FT_ERR( Invalid_Argument ); + TT_Face ttface = (TT_Face)face; + FT_Error error; GX_Blend blend; FT_MM_Var* mmvar; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UInt num_instances; - if ( !face->blend ) + if ( !ttface->blend ) { if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) goto Exit; } - blend = face->blend; + blend = ttface->blend; mmvar = blend->mmvar; - num_instances = (FT_UInt)face->root.style_flags >> 16; + num_instances = (FT_UInt)face->style_flags >> 16; /* `instance_index' starts with value 1, thus `>' */ if ( instance_index > num_instances ) + { + error = FT_ERR( Invalid_Argument ); goto Exit; + } if ( instance_index > 0 ) { - FT_Memory memory = face->root.memory; - SFNT_Service sfnt = (SFNT_Service)face->sfnt; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; FT_Var_Named_Style* named_style; FT_String* style_name; @@ -3070,40 +3568,92 @@ named_style = mmvar->namedstyle + instance_index - 1; - error = sfnt->get_name( face, + error = sfnt->get_name( ttface, (FT_UShort)named_style->strid, &style_name ); if ( error ) goto Exit; /* set (or replace) style name */ - FT_FREE( face->root.style_name ); - face->root.style_name = style_name; + FT_FREE( face->style_name ); + face->style_name = style_name; /* finally, select the named instance */ error = TT_Set_Var_Design( face, mmvar->num_axis, named_style->coords ); - if ( error ) - { - /* internal error code -1 means `no change' */ - if ( error == -1 ) - error = FT_Err_Ok; - goto Exit; - } } else + { + /* restore non-VF style name */ + FT_FREE( face->style_name ); + if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) ) + goto Exit; error = TT_Set_Var_Design( face, 0, NULL ); + } - face->root.face_index = ( instance_index << 16 ) | - ( face->root.face_index & 0xFFFFL ); - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; + if ( error == -1 || error == -2 ) + error = FT_Err_Ok; Exit: return error; } + /************************************************************************** + * + * @Function: + * TT_Get_Default_Named_Instance + * + * @Description: + * Get the default named instance. + * + * @Input: + * face :: + * A handle to the source face. + * + * @Output: + * instance_index :: + * The default named instance index. + * + * @Return: + * FreeType error code. 0~means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ) + { + TT_Face ttface = (TT_Face)face; + FT_Error error = FT_Err_Ok; + + + if ( !ttface->blend ) + { + if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) ) + goto Exit; + } + + *instance_index = ttface->var_default_named_instance; + + Exit: + return error; + } + + + /* This function triggers (lazy) recomputation of the `postscript_name` */ + /* field in `TT_Face`. */ + + FT_LOCAL_DEF( void ) + tt_construct_ps_name( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( ttface->postscript_name ); + } + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -3113,6 +3663,8 @@ /*************************************************************************/ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + static FT_Error tt_cvt_ready_iterator( FT_ListNode node, void* user ) @@ -3127,6 +3679,9 @@ return FT_Err_Ok; } +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + /************************************************************************** * @@ -3155,6 +3710,8 @@ tt_face_vary_cvt( TT_Face face, FT_Stream stream ) { +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + FT_Error error; FT_Memory memory = stream->memory; @@ -3169,9 +3726,10 @@ 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_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; GX_Blend blend = face->blend; @@ -3190,18 +3748,18 @@ if ( !blend ) { - FT_TRACE2(( "\n" - "tt_face_vary_cvt: no blend specified\n" )); - error = FT_Err_Ok; - goto Exit; + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no blend specified\n" )); + + return FT_Err_Ok; } if ( !face->cvt ) { - FT_TRACE2(( "\n" - "tt_face_vary_cvt: no `cvt ' table\n" )); - error = FT_Err_Ok; - goto Exit; + FT_TRACE2(( "\n" )); + FT_TRACE2(( "tt_face_vary_cvt: no `cvt ' table\n" )); + + return FT_Err_Ok; } error = face->goto_table( face, TTAG_cvar, stream, &table_len ); @@ -3209,15 +3767,11 @@ { FT_TRACE2(( "is missing\n" )); - error = FT_Err_Ok; - goto Exit; + return FT_Err_Ok; } if ( FT_FRAME_ENTER( table_len ) ) - { - error = FT_Err_Ok; - goto Exit; - } + return FT_Err_Ok; table_start = FT_Stream_FTell( stream ); if ( FT_GET_LONG() != 0x00010000L ) @@ -3230,11 +3784,6 @@ FT_TRACE2(( "loaded\n" )); - 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 = FT_GET_USHORT(); @@ -3257,21 +3806,24 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, - table_len, - &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); } - FT_TRACE5(( "cvar: there %s %d tuple%s:\n", + FT_TRACE5(( "cvar: there %s %u tuple%s:\n", ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) - goto FExit; + if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) || + FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) + goto Exit; + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) { @@ -3280,7 +3832,7 @@ FT_Fixed apply; - FT_TRACE6(( " tuple %d:\n", i )); + FT_TRACE6(( " tuple %u:\n", i )); tupleDataSize = FT_GET_USHORT(); tupleIndex = FT_GET_USHORT(); @@ -3288,32 +3840,19 @@ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + tuple_coords = peak_coords; } - else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; + else { FT_TRACE2(( "tt_face_vary_cvt:" " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto FExit; - } - else - { - if ( !blend->tuplecoords ) - { - FT_TRACE2(( "tt_face_vary_cvt:" - " no valid tuple coordinates available\n" )); - - error = FT_THROW( Invalid_Table ); - goto FExit; - } - - FT_MEM_COPY( - tuple_coords, - blend->tuplecoords + - ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, - blend->num_axis * sizeof ( FT_Fixed ) ); + goto Exit; } if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) @@ -3342,28 +3881,24 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, - table_len, - &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); points = localpoints; } else { + localpoints = NULL; points = sharedpoints; point_count = spoint_count; } deltas = ft_var_readpackeddeltas( stream, - table_len, point_count == 0 ? face->cvt_size : point_count ); - if ( !points || - !deltas || - ( localpoints == ALL_POINTS && point_count != face->cvt_size ) ) + if ( !points || !deltas ) ; /* failure, ignore it */ - else if ( localpoints == ALL_POINTS ) + else if ( points == ALL_POINTS ) { #ifdef FT_DEBUG_LEVEL_TRACE int count = 0; @@ -3384,12 +3919,12 @@ #ifdef FT_DEBUG_LEVEL_TRACE if ( old_cvt_delta != cvt_deltas[j] ) { - FT_TRACE7(( " %d: %f -> %f\n", + FT_TRACE7(( " %u: %f -> %f\n", j, - ( FT_fdot6ToFixed( face->cvt[j] ) + - old_cvt_delta ) / 65536.0, - ( FT_fdot6ToFixed( face->cvt[j] ) + - cvt_deltas[j] ) / 65536.0 )); + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[j] ) + + cvt_deltas[j] ) / 65536 )); count++; } #endif @@ -3428,10 +3963,10 @@ { FT_TRACE7(( " %d: %f -> %f\n", pindex, - ( FT_fdot6ToFixed( face->cvt[pindex] ) + - old_cvt_delta ) / 65536.0, - ( FT_fdot6ToFixed( face->cvt[pindex] ) + - cvt_deltas[pindex] ) / 65536.0 )); + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + old_cvt_delta ) / 65536, + (double)( FT_fdot6ToFixed( face->cvt[pindex] ) + + cvt_deltas[pindex] ) / 65536 )); count++; } #endif @@ -3457,24 +3992,32 @@ for ( i = 0; i < face->cvt_size; i++ ) face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] ); - FExit: - FT_FRAME_EXIT(); - - Exit: - if ( sharedpoints != ALL_POINTS ) - FT_FREE( sharedpoints ); - FT_FREE( tuple_coords ); - FT_FREE( im_start_coords ); - FT_FREE( im_end_coords ); - FT_FREE( cvt_deltas ); - - /* iterate over all FT_Size objects and set `cvt_ready' to -1 */ - /* to trigger rescaling of all CVT values */ + /* Iterate over all `FT_Size` objects and set `cvt_ready` to -1 */ + /* to trigger rescaling of all CVT values. */ FT_List_Iterate( &root->sizes_list, tt_cvt_ready_iterator, NULL ); + Exit: + if ( sharedpoints != ALL_POINTS ) + FT_FREE( sharedpoints ); + FT_FREE( cvt_deltas ); + FT_FREE( peak_coords ); + + FExit: + FT_FRAME_EXIT(); + return error; + +#else /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + FT_UNUSED( face ); + FT_UNUSED( stream ); + + return FT_Err_Ok; + +#endif /* !TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + } @@ -3686,20 +4229,12 @@ * @Description: * Apply the appropriate deltas to 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. - * * @InOut: + * loader :: + * A handle to the loader object. + * * outline :: - * The outline to change. + * The outline to change, with appended phantom points. * * @Output: * unrounded :: @@ -3710,15 +4245,16 @@ * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - TT_Vary_Apply_Glyph_Deltas( TT_Face face, - FT_UInt glyph_index, + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, FT_Outline* outline, - FT_Vector* unrounded, - FT_UInt n_points ) + FT_Vector* unrounded ) { - FT_Error error; - FT_Stream stream = face->root.stream; - FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + TT_Face face = loader->face; + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; + FT_UInt glyph_index = loader->glyph_index; + FT_UInt n_points = (FT_UInt)outline->n_points + 4; FT_Vector* points_org = NULL; /* coordinates in 16.16 format */ FT_Vector* points_out = NULL; /* coordinates in 16.16 format */ @@ -3733,9 +4269,19 @@ 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 peak_coords_size; + FT_UInt point_deltas_x_size; + FT_UInt points_org_size; + FT_UInt points_out_size; + FT_UInt has_delta_size; + FT_UInt pool_size; + FT_Byte* pool = NULL; + FT_Byte* p; + + FT_Fixed* peak_coords = NULL; + FT_Fixed* tuple_coords; + FT_Fixed* im_start_coords; + FT_Fixed* im_end_coords; GX_Blend blend = face->blend; @@ -3752,45 +4298,38 @@ FT_Fixed* point_deltas_y = NULL; - if ( !face->doblend || !blend ) - return FT_THROW( Invalid_Argument ); - for ( i = 0; i < n_points; i++ ) { unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x ); unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y ); } + if ( !face->doblend ) + goto Exit; + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + if ( glyph_index >= blend->gv_glyphcnt || blend->glyphoffsets[glyph_index] == blend->glyphoffsets[glyph_index + 1] ) { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" - " no variation data for this glyph\n" )); + " no variation data for glyph %u\n", glyph_index )); return FT_Err_Ok; } - if ( FT_NEW_ARRAY( points_org, n_points ) || - FT_NEW_ARRAY( points_out, n_points ) || - FT_NEW_ARRAY( has_delta, n_points ) ) - goto Fail1; - dataSize = blend->glyphoffsets[glyph_index + 1] - blend->glyphoffsets[glyph_index]; if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || FT_FRAME_ENTER( dataSize ) ) - goto Fail1; + return error; glyph_start = FT_Stream_FTell( stream ); /* each set of glyph variation data is formatted similarly to `cvar' */ - 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 = FT_GET_USHORT(); @@ -3802,7 +4341,7 @@ " invalid glyph variation array header\n" )); error = FT_THROW( Invalid_Table ); - goto Fail2; + goto FExit; } offsetToData += glyph_start; @@ -3813,22 +4352,51 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, - blend->gvar_size, - &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + offsetToData = FT_Stream_FTell( stream ); FT_Stream_SeekSet( stream, here ); } - FT_TRACE5(( "gvar: there %s %d tuple%s:\n", + FT_TRACE5(( "gvar: there %s %u tuple%s:\n", ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - if ( FT_NEW_ARRAY( point_deltas_x, n_points ) || - FT_NEW_ARRAY( point_deltas_y, n_points ) ) - goto Fail3; + peak_coords_size = ALIGN_SIZE( 3 * blend->num_axis * + sizeof ( *peak_coords ) ); + point_deltas_x_size = ALIGN_SIZE( 2 * n_points * + sizeof ( *point_deltas_x ) ); + points_org_size = ALIGN_SIZE( n_points * sizeof ( *points_org ) ); + points_out_size = ALIGN_SIZE( n_points * sizeof ( *points_out ) ); + has_delta_size = ALIGN_SIZE( n_points * sizeof ( *has_delta ) ); + + pool_size = peak_coords_size + + point_deltas_x_size + + points_org_size + + points_out_size + + has_delta_size; + + if ( FT_ALLOC( pool, pool_size ) ) + goto Exit; + + p = pool; + peak_coords = (FT_Fixed*)p; + p += peak_coords_size; + point_deltas_x = (FT_Fixed*)p; + p += point_deltas_x_size; + points_org = (FT_Vector*)p; + p += points_org_size; + points_out = (FT_Vector*)p; + p += points_out_size; + has_delta = (FT_Bool*)p; + + FT_ARRAY_ZERO( point_deltas_x, 2 * n_points ); + + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; + point_deltas_y = point_deltas_x + n_points; for ( j = 0; j < n_points; j++ ) { @@ -3836,44 +4404,93 @@ points_org[j].y = FT_intToFixed( outline->points[j].y ); } - for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) + p = stream->cursor; + + tupleCount &= GX_TC_TUPLE_COUNT_MASK; + for ( i = 0; i < tupleCount; i++ ) { - FT_UInt tupleDataSize; - FT_UInt tupleIndex; - FT_Fixed apply; + FT_UInt tupleDataSize; + FT_UInt tupleIndex; + FT_Fixed apply; + FT_Fixed* tupleScalars; - FT_TRACE6(( " tuple %d:\n", i )); + FT_TRACE6(( " tuple %u:\n", i )); - tupleDataSize = FT_GET_USHORT(); - tupleIndex = FT_GET_USHORT(); + tupleScalars = blend->tuplescalars; + + /* Enter frame for four bytes. */ + if ( 4 > stream->limit - p ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + tupleDataSize = FT_NEXT_USHORT( p ); + tupleIndex = FT_NEXT_USHORT( p ); + + if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) + tupleScalars = NULL; if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { + if ( 2 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + peak_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); + + tuple_coords = peak_coords; + tupleScalars = NULL; } - else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) + else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) + { + FT_Fixed scalar = + tupleScalars + ? tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] + : (FT_Fixed)-0x20000; + + + if ( scalar != (FT_Fixed)-0x20000 ) + { + apply = scalar; + goto apply_found; + } + + tuple_coords = blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * + blend->num_axis; + } + else { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto Fail3; + goto Exit; } - else - FT_MEM_COPY( - tuple_coords, - blend->tuplecoords + - ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, - blend->num_axis * sizeof ( FT_Fixed ) ); if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { + if ( 4 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + for ( j = 0; j < blend->num_axis; j++ ) - im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + im_start_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); for ( j = 0; j < blend->num_axis; j++ ) - im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); + im_end_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); } apply = ft_var_apply_tuple( blend, @@ -3882,6 +4499,11 @@ im_start_coords, im_end_coords ); + if ( tupleScalars ) + tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] = apply; + + apply_found: + if ( apply == 0 ) /* tuple isn't active for our blend */ { offsetToData += tupleDataSize; @@ -3894,9 +4516,7 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, - blend->gvar_size, - &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count ); points = localpoints; } else @@ -3906,11 +4526,9 @@ } deltas_x = ft_var_readpackeddeltas( stream, - blend->gvar_size, point_count == 0 ? n_points : point_count ); deltas_y = ft_var_readpackeddeltas( stream, - blend->gvar_size, point_count == 0 ? n_points : point_count ); @@ -3936,50 +4554,22 @@ FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply ); - if ( j < n_points - 4 ) - { - point_deltas_x[j] = old_point_delta_x + point_delta_x; - point_deltas_y[j] = old_point_delta_y + point_delta_y; - } - else - { - /* To avoid double adjustment of advance width or height, */ - /* adjust phantom points only if there is no HVAR or VVAR */ - /* support, respectively. */ - if ( j == ( n_points - 4 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_LSB ) ) - point_deltas_x[j] = old_point_delta_x + point_delta_x; - - else if ( j == ( n_points - 3 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_HADVANCE ) ) - point_deltas_x[j] = old_point_delta_x + point_delta_x; - - else if ( j == ( n_points - 2 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_TSB ) ) - point_deltas_y[j] = old_point_delta_y + point_delta_y; - - else if ( j == ( n_points - 1 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_VADVANCE ) ) - point_deltas_y[j] = old_point_delta_y + point_delta_y; - } + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; #ifdef FT_DEBUG_LEVEL_TRACE if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + FT_TRACE7(( " %u: (%f, %f) -> (%f, %f)\n", j, - ( FT_intToFixed( outline->points[j].x ) + - old_point_delta_x ) / 65536.0, - ( FT_intToFixed( outline->points[j].y ) + - old_point_delta_y ) / 65536.0, - ( FT_intToFixed( outline->points[j].x ) + - point_deltas_x[j] ) / 65536.0, - ( FT_intToFixed( outline->points[j].y ) + - point_deltas_y[j] ) / 65536.0 )); + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); count++; } #endif @@ -4038,50 +4628,22 @@ FT_Pos point_delta_y = points_out[j].y - points_org[j].y; - if ( j < n_points - 4 ) - { - point_deltas_x[j] = old_point_delta_x + point_delta_x; - point_deltas_y[j] = old_point_delta_y + point_delta_y; - } - else - { - /* To avoid double adjustment of advance width or height, */ - /* adjust phantom points only if there is no HVAR or VVAR */ - /* support, respectively. */ - if ( j == ( n_points - 4 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_LSB ) ) - point_deltas_x[j] = old_point_delta_x + point_delta_x; - - else if ( j == ( n_points - 3 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_HADVANCE ) ) - point_deltas_x[j] = old_point_delta_x + point_delta_x; - - else if ( j == ( n_points - 2 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_TSB ) ) - point_deltas_y[j] = old_point_delta_y + point_delta_y; - - else if ( j == ( n_points - 1 ) && - !( face->variation_support & - TT_FACE_FLAG_VAR_VADVANCE ) ) - point_deltas_y[j] = old_point_delta_y + point_delta_y; - } + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; #ifdef FT_DEBUG_LEVEL_TRACE if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", + FT_TRACE7(( " %u: (%f, %f) -> (%f, %f)\n", j, - ( FT_intToFixed( outline->points[j].x ) + - old_point_delta_x ) / 65536.0, - ( FT_intToFixed( outline->points[j].y ) + - old_point_delta_y ) / 65536.0, - ( FT_intToFixed( outline->points[j].x ) + - point_deltas_x[j] ) / 65536.0, - ( FT_intToFixed( outline->points[j].y ) + - point_deltas_y[j] ) / 65536.0 )); + (double)( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536, + (double)( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536, + (double)( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536 )); count++; } #endif @@ -4105,6 +4667,24 @@ FT_TRACE5(( "\n" )); + /* To avoid double adjustment of advance width or height, */ + /* do not move phantom points if there is HVAR or VVAR */ + /* support, respectively. */ + if ( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) + { + point_deltas_x[n_points - 4] = 0; + point_deltas_y[n_points - 4] = 0; + point_deltas_x[n_points - 3] = 0; + point_deltas_y[n_points - 3] = 0; + } + if ( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) + { + point_deltas_x[n_points - 2] = 0; + point_deltas_y[n_points - 2] = 0; + point_deltas_x[n_points - 1] = 0; + point_deltas_y[n_points - 1] = 0; + } + for ( i = 0; i < n_points; i++ ) { unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] ); @@ -4114,24 +4694,32 @@ outline->points[i].y += FT_fixedToInt( point_deltas_y[i] ); } - Fail3: - FT_FREE( point_deltas_x ); - FT_FREE( point_deltas_y ); + /* To avoid double adjustment of advance width or height, */ + /* adjust phantom points only if there is no HVAR or VVAR */ + /* support, respectively. */ + if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) + { + loader->pp1 = outline->points[n_points - 4]; + loader->pp2 = outline->points[n_points - 3]; + loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x - + unrounded[n_points - 4].x ) / 64; + } + if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) + { + loader->pp3 = outline->points[n_points - 2]; + loader->pp4 = outline->points[n_points - 1]; + loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].y - + unrounded[n_points - 2].y ) / 64; + } - Fail2: + Exit: if ( sharedpoints != ALL_POINTS ) FT_FREE( sharedpoints ); - FT_FREE( tuple_coords ); - FT_FREE( im_start_coords ); - FT_FREE( im_end_coords ); + FT_FREE( pool ); + FExit: FT_FRAME_EXIT(); - Fail1: - FT_FREE( points_org ); - FT_FREE( points_out ); - FT_FREE( has_delta ); - return error; } @@ -4147,22 +4735,25 @@ * the MM machinery in case it isn't loaded yet. */ FT_LOCAL_DEF( FT_Error ) - tt_get_var_blend( TT_Face face, + tt_get_var_blend( FT_Face face, /* TT_Face */ FT_UInt *num_coords, FT_Fixed* *coords, FT_Fixed* *normalizedcoords, FT_MM_Var* *mm_var ) { - if ( face->blend ) + TT_Face ttface = (TT_Face)face; + + + if ( ttface->blend ) { if ( num_coords ) - *num_coords = face->blend->num_axis; + *num_coords = ttface->blend->num_axis; if ( coords ) - *coords = face->blend->coords; + *coords = ttface->blend->coords; if ( normalizedcoords ) - *normalizedcoords = face->blend->normalizedcoords; + *normalizedcoords = ttface->blend->normalizedcoords; if ( mm_var ) - *mm_var = face->blend->mmvar; + *mm_var = ttface->blend->mmvar; } else { @@ -4178,8 +4769,8 @@ } - static void - ft_var_done_item_variation_store( TT_Face face, + FT_LOCAL_DEF( void ) + tt_var_done_item_variation_store( FT_Face face, GX_ItemVarStore itemStore ) { FT_Memory memory = FT_FACE_MEMORY( face ); @@ -4207,6 +4798,18 @@ } + FT_LOCAL_DEF( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( deltaSetIdxMap->innerIndex ); + FT_FREE( deltaSetIdxMap->outerIndex ); + } + + /************************************************************************** * * @Function: @@ -4216,10 +4819,11 @@ * Free the blend internal data structure. */ FT_LOCAL_DEF( void ) - tt_done_blend( TT_Face face ) + tt_done_blend( FT_Face face ) { + TT_Face ttface = (TT_Face)face; FT_Memory memory = FT_FACE_MEMORY( face ); - GX_Blend blend = face->blend; + GX_Blend blend = ttface->blend; if ( blend ) @@ -4235,42 +4839,54 @@ FT_FREE( blend->normalized_stylecoords ); FT_FREE( blend->mmvar ); - if ( blend->avar_segment ) + if ( blend->avar_table ) { - for ( i = 0; i < num_axes; i++ ) - FT_FREE( blend->avar_segment[i].correspondence ); - FT_FREE( blend->avar_segment ); + if ( blend->avar_table->avar_segment ) + { + for ( i = 0; i < num_axes; i++ ) + FT_FREE( blend->avar_table->avar_segment[i].correspondence ); + FT_FREE( blend->avar_table->avar_segment ); + } + + tt_var_done_item_variation_store( face, + &blend->avar_table->itemStore ); + + tt_var_done_delta_set_index_map( face, + &blend->avar_table->axisMap ); + + FT_FREE( blend->avar_table ); } if ( blend->hvar_table ) { - ft_var_done_item_variation_store( face, + tt_var_done_item_variation_store( face, &blend->hvar_table->itemStore ); - FT_FREE( blend->hvar_table->widthMap.innerIndex ); - FT_FREE( blend->hvar_table->widthMap.outerIndex ); + tt_var_done_delta_set_index_map( face, + &blend->hvar_table->widthMap ); FT_FREE( blend->hvar_table ); } if ( blend->vvar_table ) { - ft_var_done_item_variation_store( face, + tt_var_done_item_variation_store( face, &blend->vvar_table->itemStore ); - FT_FREE( blend->vvar_table->widthMap.innerIndex ); - FT_FREE( blend->vvar_table->widthMap.outerIndex ); + tt_var_done_delta_set_index_map( face, + &blend->vvar_table->widthMap ); FT_FREE( blend->vvar_table ); } if ( blend->mvar_table ) { - ft_var_done_item_variation_store( face, + tt_var_done_item_variation_store( face, &blend->mvar_table->itemStore ); FT_FREE( blend->mvar_table->values ); FT_FREE( blend->mvar_table ); } + FT_FREE( blend->tuplescalars ); FT_FREE( blend->tuplecoords ); FT_FREE( blend->glyphoffsets ); FT_FREE( blend ); @@ -4280,7 +4896,7 @@ #else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* ANSI C doesn't like empty source files */ - typedef int _tt_gxvar_dummy; + typedef int tt_gxvar_dummy_; #endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */ diff --git a/src/thirdparty/freetype2/src/truetype/ttgxvar.h b/src/thirdparty/freetype2/src/truetype/ttgxvar.h index 07c99b640..568c8027b 100644 --- a/src/thirdparty/freetype2/src/truetype/ttgxvar.h +++ b/src/thirdparty/freetype2/src/truetype/ttgxvar.h @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader (specification) * - * Copyright (C) 2004-2019 by + * Copyright (C) 2004-2025 by * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,7 @@ #define TTGXVAR_H_ -#include +#include #include "ttobjs.h" @@ -63,55 +63,21 @@ FT_BEGIN_HEADER } GX_AVarSegmentRec, *GX_AVarSegment; - typedef struct GX_ItemVarDataRec_ + /************************************************************************** + * + * @Struct: + * GX_AVarTableRec + * + * @Description: + * Data from the `avar' table. + */ + typedef struct GX_AVarTableRec_ { - FT_UInt itemCount; /* number of delta sets per item */ - FT_UInt regionIdxCount; /* number of region indices in this data */ - FT_UInt* regionIndices; /* array of `regionCount' indices; */ - /* these index `varRegionList' */ - FT_Short* deltaSet; /* array of `itemCount' deltas */ - /* use `innerIndex' for this array */ + GX_AVarSegment avar_segment; /* avar_segment[num_axis] */ + GX_ItemVarStoreRec itemStore; /* Item Variation Store */ + GX_DeltaSetIdxMapRec axisMap; /* Axis Mapping */ - } GX_ItemVarDataRec, *GX_ItemVarData; - - - /* contribution of one axis to a region */ - typedef struct GX_AxisCoordsRec_ - { - FT_Fixed startCoord; - FT_Fixed peakCoord; /* zero means no effect (factor = 1) */ - FT_Fixed endCoord; - - } GX_AxisCoordsRec, *GX_AxisCoords; - - - typedef struct GX_VarRegionRec_ - { - GX_AxisCoords axisList; /* array of axisCount records */ - - } GX_VarRegionRec, *GX_VarRegion; - - - /* item variation store */ - typedef struct GX_ItemVarStoreRec_ - { - FT_UInt dataCount; - GX_ItemVarData varData; /* array of dataCount records; */ - /* use `outerIndex' for this array */ - FT_UShort axisCount; - FT_UInt regionCount; /* total number of regions defined */ - GX_VarRegion varRegionList; - - } GX_ItemVarStoreRec, *GX_ItemVarStore; - - - typedef struct GX_DeltaSetIdxMapRec_ - { - FT_UInt mapCount; - FT_UInt* outerIndex; /* indices to item var data */ - FT_UInt* innerIndex; /* indices to delta set */ - - } GX_DeltaSetIdxMapRec, *GX_DeltaSetIdxMap; + } GX_AVarTableRec, *GX_AVarTable; /************************************************************************** @@ -246,7 +212,7 @@ FT_BEGIN_HEADER * A Boolean; if set, FreeType tried to load (and parse) the `avar' * table. * - * avar_segment :: + * avar_table :: * Data from the `avar' table. * * hvar_loaded :: @@ -289,6 +255,10 @@ FT_BEGIN_HEADER * A two-dimensional array that holds the shared tuple coordinates * in the `gvar' table. * + * tuplescalars :: + * A one-dimensional array that holds the shared tuple + * scalars in the `gvar' table for current face coordinates. + * * gv_glyphcnt :: * The number of glyphs handled in the `gvar' table. * @@ -311,7 +281,7 @@ FT_BEGIN_HEADER /* normalized_stylecoords[num_namedstyles][num_axis] */ FT_Bool avar_loaded; - GX_AVarSegment avar_segment; /* avar_segment[num_axis] */ + GX_AVarTable avar_table; FT_Bool hvar_loaded; FT_Bool hvar_checked; @@ -327,6 +297,7 @@ FT_BEGIN_HEADER FT_UInt tuplecount; FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */ + FT_Fixed* tuplescalars; /* tuplescalars[tuplecount] */ FT_UInt gv_glyphcnt; FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ @@ -377,70 +348,103 @@ FT_BEGIN_HEADER #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' ) +#define TTAG_ital FT_MAKE_TAG( 'i', 't', 'a', 'l' ) FT_LOCAL( FT_Error ) - TT_Set_MM_Blend( TT_Face face, + TT_Set_MM_Blend( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - TT_Get_MM_Blend( TT_Face face, + TT_Get_MM_Blend( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - TT_Set_Var_Design( TT_Face face, + TT_Set_Var_Design( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - TT_Get_MM_Var( TT_Face face, + TT_Get_MM_Var( FT_Face face, FT_MM_Var* *master ); FT_LOCAL( FT_Error ) - TT_Get_Var_Design( TT_Face face, + TT_Get_Var_Design( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - TT_Set_Named_Instance( TT_Face face, + TT_Set_Named_Instance( FT_Face face, FT_UInt instance_index ); + FT_LOCAL( FT_Error ) + TT_Get_Default_Named_Instance( FT_Face face, + FT_UInt *instance_index ); + + FT_LOCAL( void ) + tt_construct_ps_name( FT_Face face ); + FT_LOCAL( FT_Error ) tt_face_vary_cvt( TT_Face face, FT_Stream stream ); FT_LOCAL( FT_Error ) - TT_Vary_Apply_Glyph_Deltas( TT_Face face, - FT_UInt glyph_index, + TT_Vary_Apply_Glyph_Deltas( TT_Loader loader, FT_Outline* outline, - FT_Vector* unrounded, - FT_UInt n_points ); + FT_Vector* unrounded ); FT_LOCAL( FT_Error ) - tt_hadvance_adjust( TT_Face face, + tt_hadvance_adjust( FT_Face face, FT_UInt gindex, FT_Int *adelta ); FT_LOCAL( FT_Error ) - tt_vadvance_adjust( TT_Face face, + tt_vadvance_adjust( FT_Face face, FT_UInt gindex, FT_Int *adelta ); FT_LOCAL( void ) - tt_apply_mvar( TT_Face face ); + tt_apply_mvar( FT_Face face ); FT_LOCAL( FT_Error ) - tt_get_var_blend( TT_Face face, + tt_var_load_item_variation_store( FT_Face face, + FT_ULong offset, + GX_ItemVarStore itemStore ); + + FT_LOCAL( FT_Error ) + tt_var_load_delta_set_index_mapping( FT_Face face, + FT_ULong offset, + GX_DeltaSetIdxMap map, + GX_ItemVarStore itemStore, + FT_ULong table_len ); + + FT_LOCAL( FT_ItemVarDelta ) + tt_var_get_item_delta( FT_Face face, + GX_ItemVarStore itemStore, + FT_UInt outerIndex, + FT_UInt innerIndex ); + + FT_LOCAL( void ) + tt_var_done_item_variation_store( FT_Face face, + GX_ItemVarStore itemStore ); + + FT_LOCAL( void ) + tt_var_done_delta_set_index_map( FT_Face face, + GX_DeltaSetIdxMap deltaSetIdxMap ); + + + FT_LOCAL( FT_Error ) + tt_get_var_blend( FT_Face face, FT_UInt *num_coords, FT_Fixed* *coords, FT_Fixed* *normalizedcoords, FT_MM_Var* *mm_var ); FT_LOCAL( void ) - tt_done_blend( TT_Face face ); + tt_done_blend( FT_Face face ); #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ diff --git a/src/thirdparty/freetype2/src/truetype/ttinterp.c b/src/thirdparty/freetype2/src/truetype/ttinterp.c index 70434e172..7b26c9a9d 100644 --- a/src/thirdparty/freetype2/src/truetype/ttinterp.c +++ b/src/thirdparty/freetype2/src/truetype/ttinterp.c @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,25 +20,22 @@ /* issues; many thanks! */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H -#include FT_TRIGONOMETRY_H -#include FT_SYSTEM_H -#include FT_DRIVER_H -#include FT_MULTIPLE_MASTERS_H +#include +#include +#include +#include +#include +#include + +#ifdef TT_USE_BYTECODE_INTERPRETER #include "ttinterp.h" #include "tterrors.h" -#include "ttsubpix.h" #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include "ttgxvar.h" #endif -#ifdef TT_USE_BYTECODE_INTERPRETER - - /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -53,12 +50,6 @@ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ TT_INTERPRETER_VERSION_35 ) -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY -#define SUBPIXEL_HINTING_INFINALITY \ - ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ - TT_INTERPRETER_VERSION_38 ) -#endif - #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL #define SUBPIXEL_HINTING_MINIMAL \ ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \ @@ -97,6 +88,32 @@ #define FAILURE 1 + /* The default value for `scan_control' is documented as FALSE in the */ + /* TrueType specification. This is confusing since it implies a */ + /* Boolean value. However, this is not the case, thus both the */ + /* default values of our `scan_type' and `scan_control' fields (which */ + /* the documentation's `scan_control' variable is split into) are */ + /* zero. */ + /* */ + /* The rounding compensation should logically belong here but poorly */ + /* described in the OpenType specs. It was probably important in the */ + /* days of dot matrix printers. The values are referenced by color */ + /* as Gray, Black, and White in order. The Apple specification says */ + /* that the Gray compensation is always zero. The fourth value is */ + /* not described at all, but Greg says that it is the same as Gray. */ + /* FreeType sets all compensation values to zero. */ + + const TT_GraphicsState tt_default_graphics_state = + { + 0, 0, 0, 1, 1, 1, + { 0x4000, 0 }, { 0x4000, 0 }, { 0x4000, 0 }, + 1, 1, { 0, 0, 0, 0 }, + + 64, 68, 0, 0, 9, 3, + TRUE, 0, FALSE, 0 + }; + + /************************************************************************** * * CODERANGE FUNCTIONS @@ -104,53 +121,6 @@ */ - /************************************************************************** - * - * @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. - */ - FT_LOCAL_DEF( void ) - 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 ); - - /* 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( IP <= coderange->size ); - - exec->code = coderange->base; - exec->codeSize = coderange->size; - exec->IP = IP; - exec->curRange = range; - } - - /************************************************************************** * * @Function: @@ -176,13 +146,19 @@ FT_LOCAL_DEF( void ) TT_Set_CodeRange( TT_ExecContext exec, FT_Int range, - void* base, + FT_Byte* base, FT_Long length ) { FT_ASSERT( range >= 1 && range <= 3 ); - exec->codeRangeTable[range - 1].base = (FT_Byte*)base; + exec->codeRangeTable[range - 1].base = base; exec->codeRangeTable[range - 1].size = length; + + exec->code = base; + exec->codeSize = length; + exec->IP = 0; + exec->curRange = range; + exec->iniRange = range; } @@ -232,9 +208,6 @@ * exec :: * A handle to the target execution context. * - * memory :: - * A handle to the parent memory object. - * * @Note: * Only the glyph loader and debugger should call this function. */ @@ -248,9 +221,13 @@ exec->maxPoints = 0; exec->maxContours = 0; - /* free stack */ - FT_FREE( exec->stack ); - exec->stackSize = 0; + /* free glyf cvt working area */ + FT_FREE( exec->glyfCvt ); + exec->glyfCvtSize = 0; + + /* free glyf storage working area */ + FT_FREE( exec->glyfStorage ); + exec->glyfStoreSize = 0; /* free call stack */ FT_FREE( exec->callStack ); @@ -268,115 +245,6 @@ } - /************************************************************************** - * - * @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 FT_Err_Ok; - - Fail_Memory: - FT_ERROR(( "Init_Context: not enough memory for %p\n", 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. - */ - FT_LOCAL_DEF( FT_Error ) - Update_Max( FT_Memory memory, - FT_ULong* size, - FT_ULong 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 FT_Err_Ok; - } - - /************************************************************************** * * @Function: @@ -401,88 +269,34 @@ * * @Note: * Only the glyph loader and debugger should call this function. + * + * Note that not all members of `TT_ExecContext` get initialized. */ 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; + FT_Memory memory = exec->memory; 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->pointSize = size->point_size; - exec->tt_metrics = size->ttmetrics; - exec->metrics = *size->metrics; + /* CVT and storage are not persistent in FreeType */ + /* reset them after they might have been modifief */ + exec->storage = exec->stack + exec->stackSize; + exec->cvt = exec->storage + exec->storeSize; - exec->maxFunc = size->max_func; - exec->maxIns = size->max_ins; + /* free previous glyph code range */ + FT_FREE( exec->glyphIns ); + exec->glyphSize = 0; - for ( i = 0; i < TT_MAX_CODE_RANGES; i++ ) - exec->codeRangeTable[i] = size->codeRangeTable[i]; + exec->pointSize = size->point_size; + exec->tt_metrics = size->ttmetrics; + exec->metrics = *size->metrics; - /* 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; - - /* In case of multi-threading it can happen that the old size object */ - /* no longer exists, thus we must clear all glyph zone references. */ - FT_ZERO( &exec->zp0 ); - exec->zp1 = exec->zp0; - exec->zp2 = exec->zp0; - } - - /* XXX: We reserve a little more elements on the stack to deal safely */ - /* with broken fonts like arialbs, courbs, timesbs, etc. */ - tmp = (FT_ULong)exec->stackSize; - error = Update_Max( exec->memory, - &tmp, - sizeof ( FT_F26Dot6 ), - (void*)&exec->stack, - maxp->maxStackElements + 32 ); - exec->stackSize = (FT_Long)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; + exec->twilight = size->twilight; return FT_Err_Ok; } @@ -511,89 +325,22 @@ TT_Save_Context( TT_ExecContext exec, TT_Size size ) { - FT_Int i; + /* UNDOCUMENTED! */ + /* Only these GS values can be modified by the CVT program. */ - - /* XXX: 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]; + size->GS.minimum_distance = exec->GS.minimum_distance; + size->GS.control_value_cutin = exec->GS.control_value_cutin; + size->GS.single_width_cutin = exec->GS.single_width_cutin; + size->GS.single_width_value = exec->GS.single_width_value; + size->GS.delta_base = exec->GS.delta_base; + size->GS.delta_shift = exec->GS.delta_shift; + size->GS.auto_flip = exec->GS.auto_flip; + size->GS.instruct_control = exec->GS.instruct_control; + size->GS.scan_control = exec->GS.scan_control; + size->GS.scan_type = exec->GS.scan_type; } - /************************************************************************** - * - * @Function: - * TT_Run_Context - * - * @Description: - * Executes one or more instructions in the execution context. - * - * @Input: - * exec :: - * A handle to the target execution context. - * - * @Return: - * TrueType error code. 0 means success. - */ - FT_LOCAL_DEF( FT_Error ) - TT_Run_Context( TT_ExecContext exec ) - { - TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ); - - 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; - - 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; - - return exec->face->interpreter( exec ); - } - - - /* The default value for `scan_control' is documented as FALSE in the */ - /* TrueType specification. This is confusing since it implies a */ - /* Boolean value. However, this is not the case, thus both the */ - /* default values of our `scan_type' and `scan_control' fields (which */ - /* the documentation's `scan_control' variable is split into) are */ - /* zero. */ - - const TT_GraphicsState tt_default_graphics_state = - { - 0, 0, 0, - { 0x4000, 0 }, - { 0x4000, 0 }, - { 0x4000, 0 }, - - 1, 64, 1, - TRUE, 68, 0, 0, 9, 3, - 0, FALSE, 0, 1, 1, 1 - }; - - /* documentation is in ttinterp.h */ FT_EXPORT_DEF( TT_ExecContext ) @@ -602,7 +349,8 @@ FT_Memory memory; FT_Error error; - TT_ExecContext exec = NULL; + TT_ExecContext exec = NULL; + FT_DebugHook_Func interp; if ( !driver ) @@ -610,19 +358,28 @@ memory = driver->root.root.memory; - /* allocate object */ + /* allocate object and zero everything inside */ if ( FT_NEW( exec ) ) goto Fail; - /* initialize it; in case of error this deallocates `exec' too */ - error = Init_Context( exec, memory ); - if ( error ) - goto Fail; + /* set `exec->interpreter' according to the debug hook present, */ + /* which is used by 'ttdebug'. */ + interp = driver->root.root.library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE]; - return exec; + if ( interp ) + exec->interpreter = (TT_Interpreter)interp; + else + exec->interpreter = (TT_Interpreter)TT_RunIns; + + /* create callStack here, other allocations delayed */ + exec->memory = memory; + exec->callSize = 32; + + if ( FT_QNEW_ARRAY( exec->callStack, exec->callSize ) ) + FT_FREE( exec ); Fail: - return NULL; + return exec; } @@ -1277,20 +1034,35 @@ #undef PACK -#ifndef FT_CONFIG_OPTION_NO_ASSEMBLER +#ifdef FT_INT64 + +#define TT_MulFix14( a, b ) TT_MulFix14_64( a, b ) + + static inline FT_F26Dot6 + TT_MulFix14_64( FT_F26Dot6 a, + FT_F2Dot14 b ) + { + FT_Int64 ab = MUL_INT64( a, b ); + + + ab = ADD_INT64( ab, 0x2000 + ( ab >> 63 ) ); /* rounding phase */ + + return (FT_F26Dot6)( ab >> 14 ); + } + +#elif !defined( FT_CONFIG_OPTION_NO_ASSEMBLER ) #if defined( __arm__ ) && \ ( defined( __thumb2__ ) || !defined( __thumb__ ) ) #define TT_MulFix14 TT_MulFix14_arm - static FT_Int32 + static __inline FT_Int32 TT_MulFix14_arm( FT_Int32 a, - FT_Int b ) + FT_Int32 b ) { FT_Int32 t, t2; - #if defined( __CC_ARM ) || defined( __ARMCC__ ) __asm @@ -1316,8 +1088,8 @@ #endif "adds %1, %1, %0\n\t" /* %1 += %0 */ "adc %2, %2, #0\n\t" /* %2 += carry */ - "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */ - "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */ + "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 14 */ + "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 18 */ : "=r"(a), "=&r"(t2), "=&r"(t) : "r"(a), "r"(b) : "cc" ); @@ -1327,49 +1099,60 @@ return a; } -#endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */ +#elif defined( __i386__ ) || defined( _M_IX86 ) -#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ +#define TT_MulFix14 TT_MulFix14_i386 + /* documentation is in freetype.h */ -#if defined( __GNUC__ ) && \ - ( defined( __i386__ ) || defined( __x86_64__ ) ) - -#define TT_MulFix14 TT_MulFix14_long_long - - /* Temporarily disable the warning that C90 doesn't support `long long'. */ -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic push -#endif -#pragma GCC diagnostic ignored "-Wlong-long" - - /* This is declared `noinline' because inlining the function results */ - /* in slower code. The `pure' attribute indicates that the result */ - /* only depends on the parameters. */ - static __attribute__(( noinline )) - __attribute__(( pure )) FT_Int32 - TT_MulFix14_long_long( FT_Int32 a, - FT_Int b ) + static __inline FT_Int32 + TT_MulFixi14_i386( FT_Int32 a, + FT_Int32 b ) { + FT_Int32 result; - long long ret = (long long)a * b; +#if defined( __GNUC__ ) - /* The following line assumes that right shifting of signed values */ - /* will actually preserve the sign bit. The exact behaviour is */ - /* undefined, but this is true on x86 and x86_64. */ - long long tmp = ret >> 63; + __asm__ __volatile__ ( + "imul %%edx\n" + "movl %%edx, %%ecx\n" + "sarl $31, %%ecx\n" + "addl $0x2000, %%ecx\n" + "addl %%ecx, %%eax\n" + "adcl $0, %%edx\n" + "shrl $14, %%eax\n" + "shll $18, %%edx\n" + "addl %%edx, %%eax\n" + : "=a"(result), "=d"(b) + : "a"(a), "d"(b) + : "%ecx", "cc" ); +#elif defined( _MSC_VER) - ret += 0x2000 + tmp; + __asm + { + mov eax, a + mov edx, b + imul edx + mov ecx, edx + sar ecx, 31 + add ecx, 2000h + add eax, ecx + adc edx, 0 + shr eax, 14 + shl edx, 18 + add eax, edx + mov result, eax + } - return (FT_Int32)( ret >> 14 ); +#endif + + return result; } -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic pop -#endif +#endif /* __i386__ || _M_IX86 */ -#endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */ +#endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */ #ifndef TT_MulFix14 @@ -1379,92 +1162,59 @@ /* for platforms where sizeof(int) == 2. */ static FT_Int32 TT_MulFix14( FT_Int32 a, - FT_Int b ) + FT_Int16 b ) { - FT_Int32 sign; - FT_UInt32 ah, al, mid, lo, hi; + FT_Int32 m, hi; + FT_UInt32 l, lo; - sign = a ^ b; + /* compute a*b as 64-bit (hi_lo) value */ + l = (FT_UInt32)( ( a & 0xFFFFU ) * b ); + m = ( a >> 16 ) * b; - if ( a < 0 ) - a = -a; - if ( b < 0 ) - b = -b; + lo = l + ( (FT_UInt32)m << 16 ); + hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l ); - ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU ); - al = (FT_UInt32)( a & 0xFFFFU ); + /* divide the result by 2^14 with rounding */ + l = lo + 0x2000U + (FT_UInt32)( hi >> 31 ); /* rounding phase */ + hi += ( l < lo ); - 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; + return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); } #endif /* !TT_MulFix14 */ -#if defined( __GNUC__ ) && \ - ( defined( __i386__ ) || \ - defined( __x86_64__ ) || \ - defined( __arm__ ) ) - -#define TT_DotFix14 TT_DotFix14_long_long - -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic push -#endif -#pragma GCC diagnostic ignored "-Wlong-long" - - static __attribute__(( pure )) FT_Int32 - TT_DotFix14_long_long( FT_Int32 ax, - FT_Int32 ay, - FT_Int bx, - FT_Int by ) - { - /* Temporarily disable the warning that C90 doesn't support */ - /* `long long'. */ - - long long temp1 = (long long)ax * bx; - long long temp2 = (long long)ay * by; - - - temp1 += temp2; - temp2 = temp1 >> 63; - temp1 += 0x2000 + temp2; - - return (FT_Int32)( temp1 >> 14 ); - - } - -#if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406 -#pragma GCC diagnostic pop -#endif - -#endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */ - - -#ifndef TT_DotFix14 +#ifdef FT_INT64 /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */ - static FT_Int32 - TT_DotFix14( FT_Int32 ax, - FT_Int32 ay, - FT_Int bx, - FT_Int by ) + static inline FT_F26Dot6 + TT_DotFix14( FT_F26Dot6 ax, + FT_F26Dot6 ay, + FT_F2Dot14 bx, + FT_F2Dot14 by ) { - FT_Int32 m, s, hi1, hi2, hi; + FT_Int64 c = ADD_INT64( MUL_INT64( ax, bx ), MUL_INT64( ay, by ) ); + + + c = ADD_INT64( c, 0x2000 + ( c >> 63 ) ); /* rounding phase */ + + return (FT_F26Dot6)( c >> 14 ); + } + +#else + + static inline FT_F26Dot6 + TT_DotFix14( FT_F26Dot6 ax, + FT_F26Dot6 ay, + FT_F2Dot14 bx, + FT_F2Dot14 by ) + { + FT_Int32 m, hi1, hi2, hi; FT_UInt32 l, lo1, lo2, lo; - /* compute ax*bx as 64-bit value */ + /* compute ax*bx as 64-bit (hi_lo) value */ l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx ); m = ( ax >> 16 ) * bx; @@ -1483,18 +1233,13 @@ 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; + l = lo + 0x2000U + (FT_UInt32)( hi >> 31 ); /* rounding phase */ hi += ( l < lo ); - return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); + return (FT_F26Dot6)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) ); } -#endif /* TT_DotFix14 */ +#endif /* !FT_INT64 */ /************************************************************************** @@ -1573,11 +1318,37 @@ } + static void + Modify_CVT_Check( TT_ExecContext exc ) + { + if ( exc->iniRange == tt_coderange_glyph && + exc->cvt != exc->glyfCvt ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfCvtSize = exc->cvtSize; + FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize ); + exc->cvt = exc->glyfCvt; + } + } + + FT_CALLBACK_DEF( void ) Write_CVT( TT_ExecContext exc, FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = value; } @@ -1587,6 +1358,10 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) ); } @@ -1596,6 +1371,10 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], value ); } @@ -1605,36 +1384,15 @@ FT_ULong idx, FT_F26Dot6 value ) { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[idx] = ADD_LONG( exc->cvt[idx], FT_DivFix( value, Current_Ratio( exc ) ) ); } - /************************************************************************** - * - * @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( TT_ExecContext exc ) - { - /* Reading a byte stream so there is no endianness (DaveP) */ - exc->IP += 2; - return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) + - exc->code[exc->IP - 1] ); - } - - /************************************************************************** * * @Function: @@ -1688,6 +1446,7 @@ exc->code = range->base; exc->codeSize = range->size; exc->IP = aIP; + exc->length = 0; exc->curRange = aRange; return SUCCESS; @@ -1750,59 +1509,33 @@ FT_UShort point, FT_F26Dot6 distance ) { - FT_F26Dot6 v; + FT_Fixed v; - v = exc->GS.freeVector.x; - + v = exc->moveVector.x; if ( v != 0 ) { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - ( !exc->ignore_x_mode || - ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* Exception to the post-IUP curfew: Allow the x component of */ /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ /* diagonal stems like on `Z' and `z' post-IUP. */ - if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); - else + if ( !exc->backward_compatibility ) #endif - - if ( NO_SUBPIXEL_HINTING ) zone->cur[point].x = ADD_LONG( zone->cur[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; } - v = exc->GS.freeVector.y; - + v = exc->moveVector.y; if ( v != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif zone->cur[point].y = ADD_LONG( zone->cur[point].y, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } @@ -1835,24 +1568,20 @@ FT_UShort point, FT_F26Dot6 distance ) { - FT_F26Dot6 v; + FT_Fixed v; - v = exc->GS.freeVector.x; + v = exc->moveVector.x; if ( v != 0 ) zone->org[point].x = ADD_LONG( zone->org[point].x, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); - v = exc->GS.freeVector.y; + v = exc->moveVector.y; if ( v != 0 ) zone->org[point].y = ADD_LONG( zone->org[point].y, - FT_MulDiv( distance, - v, - exc->F_dot_P ) ); + FT_MulFix( distance, v ) ); } @@ -1873,19 +1602,9 @@ FT_UShort point, FT_F26Dot6 distance ) { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility ) - zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); - else + if ( !exc->backward_compatibility ) #endif - - if ( NO_SUBPIXEL_HINTING ) zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance ); zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; @@ -1901,9 +1620,8 @@ FT_UNUSED( exc ); #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance ); @@ -1968,7 +1686,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2012,7 +1729,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2058,7 +1774,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2106,7 +1821,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2151,7 +1865,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2197,7 +1910,6 @@ FT_F26Dot6 compensation ) { FT_F26Dot6 val; - FT_UNUSED( exc ); @@ -2327,59 +2039,6 @@ } - /************************************************************************** - * - * @Function: - * Compute_Round - * - * @Description: - * Sets the rounding mode. - * - * @Input: - * round_mode :: - * The rounding mode to be used. - */ - static void - Compute_Round( TT_ExecContext exc, - FT_Byte round_mode ) - { - switch ( round_mode ) - { - case TT_Round_Off: - exc->func_round = (TT_Round_Func)Round_None; - break; - - case TT_Round_To_Grid: - exc->func_round = (TT_Round_Func)Round_To_Grid; - break; - - case TT_Round_Up_To_Grid: - exc->func_round = (TT_Round_Func)Round_Up_To_Grid; - break; - - case TT_Round_Down_To_Grid: - exc->func_round = (TT_Round_Func)Round_Down_To_Grid; - break; - - case TT_Round_To_Half_Grid: - exc->func_round = (TT_Round_Func)Round_To_Half_Grid; - break; - - case TT_Round_To_Double_Grid: - exc->func_round = (TT_Round_Func)Round_To_Double_Grid; - break; - - case TT_Round_Super: - exc->func_round = (TT_Round_Func)Round_Super; - break; - - case TT_Round_Super_45: - exc->func_round = (TT_Round_Func)Round_Super_45; - break; - } - } - - /************************************************************************** * * @Function: @@ -2581,14 +2240,45 @@ static void Compute_Funcs( TT_ExecContext exc ) { - if ( exc->GS.freeVector.x == 0x4000 ) - exc->F_dot_P = exc->GS.projVector.x; - else if ( exc->GS.freeVector.y == 0x4000 ) - exc->F_dot_P = exc->GS.projVector.y; + FT_Long F_dot_P = + ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + + (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y + + 0x2000L ) >> 14; + + + if ( F_dot_P >= 0x3FFEL ) + { + /* commonly collinear */ + exc->moveVector.x = exc->GS.freeVector.x * 4; + exc->moveVector.y = exc->GS.freeVector.y * 4; + } + else if ( -0x400L < F_dot_P && F_dot_P < 0x400L ) + { + /* prohibitively orthogonal */ + exc->moveVector.x = 0; + exc->moveVector.y = 0; + } else - exc->F_dot_P = - ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x + - (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14; + { + exc->moveVector.x = exc->GS.freeVector.x * 0x10000L / F_dot_P; + exc->moveVector.y = exc->GS.freeVector.y * 0x10000L / F_dot_P; + } + + if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.x == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_X; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; + } + else if ( F_dot_P >= 0x3FFEL && exc->GS.freeVector.y == 0x4000 ) + { + exc->func_move = (TT_Move_Func)Direct_Move_Y; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y; + } + else + { + exc->func_move = (TT_Move_Func)Direct_Move; + exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; + } if ( exc->GS.projVector.x == 0x4000 ) exc->func_project = (TT_Project_Func)Project_x; @@ -2604,29 +2294,6 @@ else exc->func_dualproj = (TT_Project_Func)Dual_Project; - exc->func_move = (TT_Move_Func)Direct_Move; - exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig; - - if ( exc->F_dot_P == 0x4000L ) - { - if ( exc->GS.freeVector.x == 0x4000 ) - { - exc->func_move = (TT_Move_Func)Direct_Move_X; - exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X; - } - else if ( exc->GS.freeVector.y == 0x4000 ) - { - exc->func_move = (TT_Move_Func)Direct_Move_Y; - exc->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( exc->F_dot_P ) < 0x400L ) - exc->F_dot_P = 0x4000L; - /* Disable cached aspect ratio */ exc->tt_metrics.ratio = 0; } @@ -2899,7 +2566,7 @@ Ins_ODD( TT_ExecContext exc, FT_Long* args ) { - args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 ); + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 64 ); } @@ -2913,7 +2580,7 @@ Ins_EVEN( TT_ExecContext exc, FT_Long* args ) { - args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 0 ); + args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 64 ) == 0 ); } @@ -3086,28 +2753,7 @@ args[0] = 0; } else - { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* subpixel hinting - avoid Typeman Dstroke and */ - /* IStroke and Vacuform rounds */ - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - ( ( I == 24 && - ( exc->face->sph_found_func_flags & - ( SPH_FDEF_SPACING_1 | - SPH_FDEF_SPACING_2 ) ) ) || - ( I == 22 && - ( exc->sph_in_func_flags & - SPH_FDEF_TYPEMAN_STROKES ) ) || - ( I == 8 && - ( exc->face->sph_found_func_flags & - SPH_FDEF_VACUFORM_ROUND_1 ) && - exc->iup_called ) ) ) - args[0] = 0; - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - args[0] = exc->storage[I]; - } + args[0] = exc->storage[I]; } @@ -3130,7 +2776,28 @@ ARRAY_BOUND_ERROR; } else + { + if ( exc->iniRange == tt_coderange_glyph && + exc->storage != exc->glyfStorage ) + { + FT_Memory memory = exc->memory; + FT_Error error; + + + FT_MEM_QRENEW_ARRAY( exc->glyfStorage, + exc->glyfStoreSize, + exc->storeSize ); + exc->error = error; + if ( error ) + return; + + exc->glyfStoreSize = exc->storeSize; + FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize ); + exc->storage = exc->glyfStorage; + } + exc->storage[I] = args[1]; + } } @@ -3243,10 +2910,8 @@ Ins_ROUND( TT_ExecContext exc, FT_Long* args ) { - args[0] = exc->func_round( - exc, - args[0], - exc->tt_metrics.compensations[exc->opcode - 0x68] ); + args[0] = exc->func_round( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); } @@ -3260,10 +2925,8 @@ Ins_NROUND( TT_ExecContext exc, FT_Long* args ) { - args[0] = Round_None( - exc, - args[0], - exc->tt_metrics.compensations[exc->opcode - 0x6C] ); + args[0] = Round_None( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); } @@ -3317,13 +2980,11 @@ } else { - K = exc->stack[exc->args - L]; + K = args[-L]; - FT_ARRAY_MOVE( &exc->stack[exc->args - L ], - &exc->stack[exc->args - L + 1], - ( L - 1 ) ); + FT_ARRAY_MOVE( args - L, args - L + 1, L - 1 ); - exc->stack[exc->args - 1] = K; + args[-1] = K; } } @@ -3350,7 +3011,7 @@ args[0] = 0; } else - args[0] = exc->stack[exc->args - L]; + args[0] = args[-L]; } @@ -3420,8 +3081,7 @@ exc->length = 2 - exc->length * exc->code[exc->IP + 1]; } - if ( exc->IP + exc->length <= exc->codeSize ) - return SUCCESS; + return SUCCESS; } Fail_Overflow: @@ -3469,6 +3129,9 @@ nIfs--; Out = FT_BOOL( nIfs == 0 ); break; + + default: + break; } } while ( Out == 0 ); } @@ -3502,6 +3165,9 @@ case 0x59: /* EIF */ nIfs--; break; + + default: + break; } } while ( nIfs != 0 ); } @@ -3536,7 +3202,7 @@ return; } - exc->IP += args[0]; + exc->IP = ADD_LONG( exc->IP, args[0] ); if ( exc->IP < 0 || ( exc->callTop > 0 && exc->IP > exc->callStack[exc->callTop - 1].Def->end ) ) @@ -3545,7 +3211,7 @@ return; } - exc->step_ins = FALSE; + exc->length = 0; if ( args[0] < 0 ) { @@ -3606,109 +3272,9 @@ TT_DefRecord* rec; TT_DefRecord* limit; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* arguments to opcodes are skipped by `SKIP_Code' */ - FT_Byte opcode_pattern[9][12] = { - /* #0 inline delta function 1 */ - { - 0x4B, /* PPEM */ - 0x53, /* GTEQ */ - 0x23, /* SWAP */ - 0x4B, /* PPEM */ - 0x51, /* LTEQ */ - 0x5A, /* AND */ - 0x58, /* IF */ - 0x38, /* SHPIX */ - 0x1B, /* ELSE */ - 0x21, /* POP */ - 0x21, /* POP */ - 0x59 /* EIF */ - }, - /* #1 inline delta function 2 */ - { - 0x4B, /* PPEM */ - 0x54, /* EQ */ - 0x58, /* IF */ - 0x38, /* SHPIX */ - 0x1B, /* ELSE */ - 0x21, /* POP */ - 0x21, /* POP */ - 0x59 /* EIF */ - }, - /* #2 diagonal stroke function */ - { - 0x20, /* DUP */ - 0x20, /* DUP */ - 0xB0, /* PUSHB_1 */ - /* 1 */ - 0x60, /* ADD */ - 0x46, /* GC_cur */ - 0xB0, /* PUSHB_1 */ - /* 64 */ - 0x23, /* SWAP */ - 0x42 /* WS */ - }, - /* #3 VacuFormRound function */ - { - 0x45, /* RCVT */ - 0x23, /* SWAP */ - 0x46, /* GC_cur */ - 0x60, /* ADD */ - 0x20, /* DUP */ - 0xB0 /* PUSHB_1 */ - /* 38 */ - }, - /* #4 TTFautohint bytecode (old) */ - { - 0x20, /* DUP */ - 0x64, /* ABS */ - 0xB0, /* PUSHB_1 */ - /* 32 */ - 0x60, /* ADD */ - 0x66, /* FLOOR */ - 0x23, /* SWAP */ - 0xB0 /* PUSHB_1 */ - }, - /* #5 spacing function 1 */ - { - 0x01, /* SVTCA_x */ - 0xB0, /* PUSHB_1 */ - /* 24 */ - 0x43, /* RS */ - 0x58 /* IF */ - }, - /* #6 spacing function 2 */ - { - 0x01, /* SVTCA_x */ - 0x18, /* RTG */ - 0xB0, /* PUSHB_1 */ - /* 24 */ - 0x43, /* RS */ - 0x58 /* IF */ - }, - /* #7 TypeMan Talk DiagEndCtrl function */ - { - 0x01, /* SVTCA_x */ - 0x20, /* DUP */ - 0xB0, /* PUSHB_1 */ - /* 3 */ - 0x25, /* CINDEX */ - }, - /* #8 TypeMan Talk Align */ - { - 0x06, /* SPVTL */ - 0x7D, /* RDTG */ - }, - }; - FT_UShort opcode_patterns = 9; - FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 }; - FT_UShort i; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - /* FDEF is only allowed in `prep' or `fpgm' */ - if ( exc->curRange == tt_coderange_glyph ) + if ( exc->iniRange == tt_coderange_glyph ) { exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); return; @@ -3718,7 +3284,7 @@ /* We will then parse the current table. */ rec = exc->FDefs; - limit = rec + exc->numFDefs; + limit = FT_OFFSET( rec, exc->numFDefs ); n = (FT_ULong)args[0]; for ( ; rec < limit; rec++ ) @@ -3746,150 +3312,32 @@ return; } - rec->range = exc->curRange; - rec->opc = (FT_UInt16)n; - rec->start = exc->IP + 1; - rec->active = TRUE; - rec->inline_delta = FALSE; - rec->sph_fdef_flags = 0x0000; + rec->range = exc->curRange; + rec->opc = (FT_UInt16)n; + rec->start = exc->IP + 1; + rec->active = TRUE; if ( n > exc->maxFunc ) exc->maxFunc = (FT_UInt16)n; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* We don't know for sure these are typeman functions, */ - /* however they are only active when RS 22 is called */ - if ( n >= 64 && n <= 66 ) - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES; -#endif - /* Now skip the whole function definition. */ /* We don't allow nested IDEFS & FDEFs. */ while ( SkipCode( exc ) == SUCCESS ) { - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( SUBPIXEL_HINTING_INFINALITY ) - { - for ( i = 0; i < opcode_patterns; i++ ) - { - if ( opcode_pointer[i] < opcode_size[i] && - exc->opcode == opcode_pattern[i][opcode_pointer[i]] ) - { - opcode_pointer[i] += 1; - - if ( opcode_pointer[i] == opcode_size[i] ) - { - FT_TRACE6(( "sph: Function %d, opcode ptrn: %d, %s %s\n", - i, n, - exc->face->root.family_name, - exc->face->root.style_name )); - - switch ( i ) - { - case 0: - rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1; - exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1; - break; - - case 1: - rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2; - exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2; - break; - - case 2: - switch ( n ) - { - /* needs to be implemented still */ - case 58: - rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE; - exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE; - } - break; - - case 3: - switch ( n ) - { - case 0: - rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1; - exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1; - } - break; - - case 4: - /* probably not necessary to detect anymore */ - rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1; - exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1; - break; - - case 5: - switch ( n ) - { - case 0: - case 1: - case 2: - case 4: - case 7: - case 8: - rec->sph_fdef_flags |= SPH_FDEF_SPACING_1; - exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1; - } - break; - - case 6: - switch ( n ) - { - case 0: - case 1: - case 2: - case 4: - case 7: - case 8: - rec->sph_fdef_flags |= SPH_FDEF_SPACING_2; - exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2; - } - break; - - case 7: - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - break; - - case 8: -#if 0 - rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; - exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL; -#endif - break; - } - opcode_pointer[i] = 0; - } - } - - else - opcode_pointer[i] = 0; - } - - /* Set sph_compatibility_mode only when deltas are detected */ - exc->face->sph_compatibility_mode = - ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) | - ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ); - } - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - switch ( exc->opcode ) { - case 0x89: /* IDEF */ - case 0x2C: /* FDEF */ + case 0x89: /* IDEF */ + case 0x2C: /* FDEF */ exc->error = FT_THROW( Nested_DEFS ); return; case 0x2D: /* ENDF */ rec->end = exc->IP; return; + + default: + break; } } } @@ -3907,10 +3355,6 @@ TT_CallRec* pRec; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - exc->sph_in_func_flags = 0x0000; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */ { exc->error = FT_THROW( ENDF_In_Exec_Stream ); @@ -3923,12 +3367,11 @@ pRec->Cur_Count--; - exc->step_ins = FALSE; - if ( pRec->Cur_Count > 0 ) { exc->callTop++; - exc->IP = pRec->Def->start; + exc->IP = pRec->Def->start; + exc->length = 0; } else /* Loop through the current function */ @@ -3965,6 +3408,9 @@ if ( BOUNDSL( F, exc->maxFunc + 1 ) ) goto Fail; + if ( !exc->FDefs ) + 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 */ @@ -3995,17 +3441,6 @@ if ( !def->active ) goto Fail; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - ( ( exc->iup_called && - ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) || - ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) ) - goto Fail; - else - exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - /* check the call stack */ if ( exc->callTop >= exc->callSize ) { @@ -4024,8 +3459,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; - return; Fail: @@ -4062,7 +3495,7 @@ /* */ /* If this isn't true, we need to look up the function table. */ - def = exc->FDefs + F; + def = FT_OFFSET( exc->FDefs, F ); if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F ) { /* look up the FDefs table */ @@ -4070,7 +3503,7 @@ def = exc->FDefs; - limit = def + exc->numFDefs; + limit = FT_OFFSET( def, exc->numFDefs ); while ( def < limit && def->opc != F ) def++; @@ -4083,15 +3516,6 @@ if ( !def->active ) goto Fail; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) - goto Fail; - else - exc->sph_in_func_flags = def->sph_fdef_flags; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - /* check stack */ if ( exc->callTop >= exc->callSize ) { @@ -4112,8 +3536,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; - exc->loopcall_counter += (FT_ULong)args[0]; if ( exc->loopcall_counter > exc->loopcall_counter_max ) exc->error = FT_THROW( Execution_Too_Long ); @@ -4141,7 +3563,7 @@ /* we enable IDEF only in `prep' or `fpgm' */ - if ( exc->curRange == tt_coderange_glyph ) + if ( exc->iniRange == tt_coderange_glyph ) { exc->error = FT_THROW( DEF_In_Glyf_Bytecode ); return; @@ -4150,7 +3572,7 @@ /* First of all, look for the same function in our table */ def = exc->IDefs; - limit = def + exc->numIDefs; + limit = FT_OFFSET( def, exc->numIDefs ); for ( ; def < limit; def++ ) if ( def->opc == (FT_ULong)args[0] ) @@ -4193,9 +3615,13 @@ case 0x2C: /* FDEF */ exc->error = FT_THROW( Nested_DEFS ); return; + case 0x2D: /* ENDF */ def->end = exc->IP; return; + + default: + break; } } } @@ -4218,10 +3644,23 @@ Ins_NPUSHB( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)exc->code[exc->IP + 1]; + if ( ++IP >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } + + L = exc->code[IP]; + + if ( IP + L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -4229,10 +3668,11 @@ return; } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K + 1]; + for ( K = 0; K < L; K++ ) + args[K] = exc->code[++IP]; exc->new_top += L; + exc->IP = IP; } @@ -4246,10 +3686,23 @@ Ins_NPUSHW( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)exc->code[exc->IP + 1]; + if ( ++IP >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } + + L = exc->code[IP]; + + if ( IP + 2 * L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -4257,13 +3710,12 @@ return; } - exc->IP += 2; + /* note casting for sign-extension */ + for ( K = 0; K < L; K++, IP += 2 ) + args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2]; - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - - exc->step_ins = FALSE; exc->new_top += L; + exc->IP = IP; } @@ -4277,10 +3729,17 @@ Ins_PUSHB( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)( exc->opcode - 0xB0 + 1 ); + L = exc->opcode - 0xB0 + 1; + + if ( IP + L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -4288,8 +3747,10 @@ return; } - for ( K = 1; K <= L; K++ ) - args[K - 1] = exc->code[exc->IP + K]; + for ( K = 0; K < L; K++ ) + args[K] = exc->code[++IP]; + + exc->IP = IP; } @@ -4303,10 +3764,17 @@ Ins_PUSHW( TT_ExecContext exc, FT_Long* args ) { - FT_UShort L, K; + FT_Long IP = exc->IP; + FT_Int L, K; - L = (FT_UShort)( exc->opcode - 0xB8 + 1 ); + L = exc->opcode - 0xB8 + 1; + + if ( IP + 2 * L >= exc->codeSize ) + { + exc->error = FT_THROW( Code_Overflow ); + return; + } if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) ) { @@ -4314,12 +3782,11 @@ return; } - exc->IP++; + /* note casting for sign-extension */ + for ( K = 0; K < L; K++, IP += 2 ) + args[K] = (FT_Short)( exc->code[IP + 1] << 8 ) | exc->code[IP + 2]; - for ( K = 0; K < L; K++ ) - args[K] = GetShortIns( exc ); - - exc->step_ins = FALSE; + exc->IP = IP; } @@ -4370,7 +3837,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -4490,15 +3957,12 @@ Ins_SPVFS( TT_ExecContext exc, FT_Long* args ) { - 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; + Y = (FT_Short)args[1]; + X = (FT_Short)args[0]; Normalize( X, Y, &exc->GS.projVector ); @@ -4517,15 +3981,12 @@ Ins_SFVFS( TT_ExecContext exc, FT_Long* args ) { - 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; + Y = (FT_Short)args[1]; + X = (FT_Short)args[0]; Normalize( X, Y, &exc->GS.freeVector ); Compute_Funcs( exc ); @@ -4997,14 +4458,6 @@ } } -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */ - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - FT_ABS( D ) == 64 ) - D += 1; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - args[0] = D; } @@ -5058,7 +4511,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -5082,7 +4535,7 @@ if ( ( opcode & 1 ) != 0 ) { - C = B; /* counter clockwise rotation */ + C = B; /* counter-clockwise rotation */ B = A; A = NEG_LONG( C ); } @@ -5256,26 +4709,26 @@ } } - exc->GS.instruct_control &= ~(FT_Byte)Kf; - exc->GS.instruct_control |= (FT_Byte)L; - - if ( K == 3 ) + /* INSTCTRL should only be used in the CVT program */ + if ( exc->iniRange == tt_coderange_cvt ) { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* INSTCTRL modifying flag 3 also has an effect */ - /* outside of the CVT program */ - if ( SUBPIXEL_HINTING_INFINALITY ) - exc->ignore_x_mode = FT_BOOL( L == 4 ); -#endif + exc->GS.instruct_control &= ~(FT_Byte)Kf; + exc->GS.instruct_control |= (FT_Byte)L; + } + /* except to change the subpixel flags temporarily */ + else if ( exc->iniRange == tt_coderange_glyph && K == 3 ) + { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* Native ClearType fonts sign a waiver that turns off all backward */ /* compatibility hacks and lets them program points to the grid like */ /* it's 1996. They might sign a waiver for just one glyph, though. */ if ( SUBPIXEL_HINTING_MINIMAL ) - exc->backward_compatibility = !FT_BOOL( L == 4 ); + exc->backward_compatibility = ( L & 4 ) ^ 4; #endif } + else if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Invalid_Reference ); } @@ -5355,32 +4808,31 @@ * Stack: uint32... --> */ static void - Ins_FLIPPT( TT_ExecContext exc ) + Ins_FLIPPT( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_UShort point; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) - goto Fail; -#endif - - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } - while ( exc->GS.loop > 0 ) - { - exc->args--; + exc->new_top -= loop; - point = (FT_UShort)exc->stack[exc->args]; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility == 0x7 ) + goto Fail; +#endif + + while ( loop-- ) + { + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->pts.n_points ) ) { @@ -5392,13 +4844,10 @@ } else exc->pts.tags[point] ^= FT_CURVE_TAG_ON; - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5417,10 +4866,7 @@ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) + if ( exc->backward_compatibility == 0x7 ) return; #endif @@ -5455,10 +4901,7 @@ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) + if ( exc->backward_compatibility == 0x7 ) return; #endif @@ -5514,8 +4957,8 @@ d = PROJECT( zp.cur + p, zp.org + p ); - *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P ); - *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P ); + *x = FT_MulFix( d, exc->moveVector.x ); + *y = FT_MulFix( d, exc->moveVector.y ); return SUCCESS; } @@ -5532,8 +4975,8 @@ if ( exc->GS.freeVector.x != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( !exc->backward_compatibility ) #endif exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); @@ -5544,10 +4987,8 @@ if ( exc->GS.freeVector.y != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility && - exc->iupx_called && - exc->iupy_called ) ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) #endif exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); @@ -5564,8 +5005,10 @@ * Stack: uint32... --> */ static void - Ins_SHP( TT_ExecContext exc ) + Ins_SHP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; TT_GlyphZoneRec zp; FT_UShort refp; @@ -5573,20 +5016,21 @@ FT_UShort point; - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); + exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } + exc->new_top -= loop; + if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) return; - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5597,20 +5041,11 @@ } } else -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* doesn't follow Cleartype spec but produces better result */ - if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode ) - Move_Zp2_Point( exc, point, 0, dy, TRUE ); - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ Move_Zp2_Point( exc, point, dx, dy, TRUE ); - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5632,11 +5067,11 @@ FT_UShort refp; FT_F26Dot6 dx, dy; - FT_Short contour, bounds; + FT_UShort contour, bounds; FT_UShort start, limit, i; - contour = (FT_Short)args[0]; + contour = (FT_UShort)args[0]; bounds = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours; if ( BOUNDS( contour, bounds ) ) @@ -5652,15 +5087,13 @@ if ( contour == 0 ) start = 0; else - start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 - - exc->zp2.first_point ); + start = exc->zp2.contours[contour - 1] + 1 - exc->zp2.first_point; /* we use the number of points if in the twilight zone */ if ( exc->GS.gep2 == 0 ) limit = exc->zp2.n_points; else - limit = (FT_UShort)( exc->zp2.contours[contour] - - exc->zp2.first_point + 1 ); + limit = exc->zp2.contours[contour] + 1 - exc->zp2.first_point; for ( i = start; i < limit; i++ ) { @@ -5703,9 +5136,9 @@ /* Normal zone's `n_points' includes phantoms, so must */ /* use end of last contour. */ if ( exc->GS.gep2 == 0 ) - limit = (FT_UShort)exc->zp2.n_points; + limit = exc->zp2.n_points; else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) - limit = (FT_UShort)( exc->zp2.contours[exc->zp2.n_contours - 1] + 1 ); + limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; else limit = 0; @@ -5728,11 +5161,9 @@ Ins_SHPIX( TT_ExecContext exc, FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_F26Dot6 dx, dy; FT_UShort point; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_Int B1, B2; -#endif #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 || @@ -5740,22 +5171,21 @@ #endif - - if ( exc->top < exc->GS.loop + 1 ) + if ( exc->new_top < loop ) { if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); + exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } + exc->new_top -= loop; + dx = TT_MulFix14( args[0], exc->GS.freeVector.x ); dy = TT_MulFix14( args[0], exc->GS.freeVector.y ); - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5766,90 +5196,8 @@ } } else -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY ) - { - /* If not using ignore_x_mode rendering, allow ZP2 move. */ - /* If inline deltas aren't allowed, skip ZP2 move. */ - /* If using ignore_x_mode rendering, allow ZP2 point move if: */ - /* - freedom vector is y and sph_compatibility_mode is off */ - /* - the glyph is composite and the move is in the Y direction */ - /* - the glyph is specifically set to allow SHPIX moves */ - /* - the move is on a previously Y-touched point */ - - if ( exc->ignore_x_mode ) - { - /* save point for later comparison */ - if ( exc->GS.freeVector.y != 0 ) - B1 = exc->zp2.cur[point].y; - else - B1 = exc->zp2.cur[point].x; - - if ( !exc->face->sph_compatibility_mode && - exc->GS.freeVector.y != 0 ) - { - Move_Zp2_Point( exc, point, dx, dy, TRUE ); - - /* save new point */ - if ( exc->GS.freeVector.y != 0 ) - { - B2 = exc->zp2.cur[point].y; - - /* reverse any disallowed moves */ - if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && - ( B1 & 63 ) != 0 && - ( B2 & 63 ) != 0 && - B1 != B2 ) - Move_Zp2_Point( exc, - point, - NEG_LONG( dx ), - NEG_LONG( dy ), - TRUE ); - } - } - else if ( exc->face->sph_compatibility_mode ) - { - if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) - { - dx = FT_PIX_ROUND( B1 + dx ) - B1; - dy = FT_PIX_ROUND( B1 + dy ) - B1; - } - - /* skip post-iup deltas */ - if ( exc->iup_called && - ( ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) || - ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) ) - goto Skip; - - if ( !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) && - ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || - ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) || - ( exc->sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) ) - Move_Zp2_Point( exc, point, 0, dy, TRUE ); - - /* save new point */ - if ( exc->GS.freeVector.y != 0 ) - { - B2 = exc->zp2.cur[point].y; - - /* reverse any disallowed moves */ - if ( ( B1 & 63 ) == 0 && - ( B2 & 63 ) != 0 && - B1 != B2 ) - Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE ); - } - } - else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL ) - Move_Zp2_Point( exc, point, dx, dy, TRUE ); - } - else - Move_Zp2_Point( exc, point, dx, dy, TRUE ); - } - else -#endif #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) + if ( exc->backward_compatibility ) { /* Special case: allow SHPIX to move points in the twilight zone. */ /* Otherwise, treat SHPIX the same as DELTAP. Unbreaks various */ @@ -5857,7 +5205,7 @@ /* that would glitch severely after calling ALIGNRP after a */ /* blocked SHPIX. */ if ( in_twilight || - ( !( exc->iupx_called && exc->iupy_called ) && + ( exc->backward_compatibility != 0x7 && ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) Move_Zp2_Point( exc, point, 0, dy, TRUE ); @@ -5865,16 +5213,10 @@ else #endif Move_Zp2_Point( exc, point, dx, dy, TRUE ); - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - Skip: -#endif - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -5890,22 +5232,8 @@ { FT_UShort point = 0; FT_F26Dot6 distance; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_F26Dot6 control_value_cutin = 0; - FT_F26Dot6 delta; - if ( SUBPIXEL_HINTING_INFINALITY ) - { - control_value_cutin = exc->GS.control_value_cutin; - - if ( exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) - control_value_cutin = 0; - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - point = (FT_UShort)args[0]; if ( BOUNDS( point, exc->zp1.n_points ) || @@ -5927,19 +5255,6 @@ distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 ); -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - delta = SUB_LONG( distance, args[1] ); - if ( delta < 0 ) - delta = NEG_LONG( delta ); - - /* subpixel hinting - make MSIRP respect CVT cut-in; */ - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - delta >= control_value_cutin ) - distance = args[1]; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->func_move( exc, &exc->zp1, point, @@ -5980,22 +5295,7 @@ if ( ( exc->opcode & 1 ) != 0 ) { cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) - distance = SUB_LONG( - Round_None( exc, - cur_dist, - exc->tt_metrics.compensations[0] ), - cur_dist ); - else -#endif - distance = SUB_LONG( - exc->func_round( exc, - cur_dist, - exc->tt_metrics.compensations[0] ), - cur_dist ); + distance = SUB_LONG( exc->func_round( exc, cur_dist, 0 ), cur_dist ); } else distance = 0; @@ -6021,21 +5321,10 @@ FT_UShort point; FT_F26Dot6 distance; FT_F26Dot6 org_dist; - FT_F26Dot6 control_value_cutin; - control_value_cutin = exc->GS.control_value_cutin; - cvtEntry = (FT_ULong)args[1]; - point = (FT_UShort)args[0]; - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - exc->GS.freeVector.y == 0 && - !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) - control_value_cutin = 0; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; if ( BOUNDS( point, exc->zp0.n_points ) || BOUNDSL( cvtEntry, exc->cvtSize ) ) @@ -6069,32 +5358,18 @@ if ( exc->GS.gep0 == 0 ) /* If in twilight zone */ { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */ - /* Determined via experimentation and may be incorrect... */ - if ( !( SUBPIXEL_HINTING_INFINALITY && - ( exc->ignore_x_mode && - exc->face->sph_compatibility_mode ) ) ) -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->zp0.org[point].x = TT_MulFix14( distance, - exc->GS.freeVector.x ); + exc->zp0.org[point].x = TT_MulFix14( distance, + exc->GS.freeVector.x ); exc->zp0.org[point].y = TT_MulFix14( distance, - exc->GS.freeVector.y ), + exc->GS.freeVector.y ); exc->zp0.cur[point] = exc->zp0.org[point]; } -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) && - distance > 0 && - exc->GS.freeVector.y != 0 ) - distance = 0; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ org_dist = FAST_PROJECT( &exc->zp0.cur[point] ); if ( ( exc->opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; FT_F26Dot6 delta; @@ -6105,18 +5380,7 @@ if ( delta > control_value_cutin ) distance = org_dist; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) - distance = Round_None( exc, - distance, - exc->tt_metrics.compensations[0] ); - else -#endif - distance = exc->func_round( exc, - distance, - exc->tt_metrics.compensations[0] ); + distance = exc->func_round( exc, distance, 0 ); } exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); @@ -6138,19 +5402,9 @@ FT_Long* args ) { FT_UShort point = 0; - FT_F26Dot6 org_dist, distance, minimum_distance; + FT_F26Dot6 org_dist, distance, compensation; - minimum_distance = exc->GS.minimum_distance; - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) - minimum_distance = 0; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - point = (FT_UShort)args[0]; if ( BOUNDS( point, exc->zp1.n_points ) || @@ -6217,33 +5471,20 @@ /* round flag */ + compensation = exc->GS.compensation[exc->opcode & 3]; + if ( ( exc->opcode & 4 ) != 0 ) - { -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 ) - distance = Round_None( - exc, - org_dist, - exc->tt_metrics.compensations[exc->opcode & 3] ); - else -#endif - distance = exc->func_round( - exc, - org_dist, - exc->tt_metrics.compensations[exc->opcode & 3] ); - } + distance = exc->func_round( exc, org_dist, compensation ); else - distance = Round_None( - exc, - org_dist, - exc->tt_metrics.compensations[exc->opcode & 3] ); + distance = Round_None( exc, org_dist, compensation ); /* minimum distance flag */ if ( ( exc->opcode & 8 ) != 0 ) { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + if ( org_dist >= 0 ) { if ( distance < minimum_distance ) @@ -6288,29 +5529,13 @@ distance, cur_dist, org_dist, - control_value_cutin, - minimum_distance; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_Int B1 = 0; /* pacify compiler */ - FT_Int B2 = 0; - FT_Bool reverse_move = FALSE; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + compensation; FT_F26Dot6 delta; - minimum_distance = exc->GS.minimum_distance; - control_value_cutin = exc->GS.control_value_cutin; - point = (FT_UShort)args[0]; - cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) ); - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.x != 0 && - !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) - control_value_cutin = minimum_distance = 0; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( ADD_LONG( args[1], 1 ) ); /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ @@ -6346,12 +5571,14 @@ /* twilight points (confirmed by Greg Hitchcock) */ if ( exc->GS.gep1 == 0 ) { - exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x + - TT_MulFix14( cvt_dist, - exc->GS.freeVector.x ); - exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y + - TT_MulFix14( cvt_dist, - exc->GS.freeVector.y ); + exc->zp1.org[point].x = ADD_LONG( + exc->zp0.org[exc->GS.rp0].x, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.x ) ); + exc->zp1.org[point].y = ADD_LONG( + exc->zp0.org[exc->GS.rp0].y, + TT_MulFix14( cvt_dist, + exc->GS.freeVector.y ) ); exc->zp1.cur[point] = exc->zp1.org[point]; } @@ -6366,21 +5593,10 @@ cvt_dist = NEG_LONG( cvt_dist ); } -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.freeVector.y != 0 && - ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) ) - { - if ( cur_dist < -64 ) - cvt_dist -= 16; - else if ( cur_dist > 64 && cur_dist < 84 ) - cvt_dist += 32; - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - /* control value cut-in and round */ + compensation = exc->GS.compensation[exc->opcode & 3]; + if ( ( exc->opcode & 4 ) != 0 ) { /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ @@ -6388,6 +5604,9 @@ if ( exc->GS.gep0 == exc->GS.gep1 ) { + FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; + + /* XXX: According to Greg Hitchcock, the following wording is */ /* the right one: */ /* */ @@ -6408,39 +5627,18 @@ cvt_dist = org_dist; } - distance = exc->func_round( - exc, - cvt_dist, - exc->tt_metrics.compensations[exc->opcode & 3] ); + distance = exc->func_round( exc, cvt_dist, compensation ); } else - { - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /* do cvt cut-in always in MIRP for sph */ - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->GS.gep0 == exc->GS.gep1 ) - { - delta = SUB_LONG( cvt_dist, org_dist ); - if ( delta < 0 ) - delta = NEG_LONG( delta ); - - if ( delta > control_value_cutin ) - cvt_dist = org_dist; - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - distance = Round_None( - exc, - cvt_dist, - exc->tt_metrics.compensations[exc->opcode & 3] ); - } + distance = Round_None( exc, cvt_dist, compensation ); /* minimum distance test */ if ( ( exc->opcode & 8 ) != 0 ) { + FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; + + if ( org_dist >= 0 ) { if ( distance < minimum_distance ) @@ -6453,68 +5651,17 @@ } } -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY ) - { - B1 = exc->zp1.cur[point].y; - - /* Round moves if necessary */ - if ( exc->ignore_x_mode && - exc->GS.freeVector.y != 0 && - ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) ) - distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist; - - if ( exc->ignore_x_mode && - exc->GS.freeVector.y != 0 && - ( exc->opcode & 16 ) == 0 && - ( exc->opcode & 8 ) == 0 && - ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) ) - distance += 64; - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, cur_dist ) ); -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY ) - { - B2 = exc->zp1.cur[point].y; - - /* Reverse move if necessary */ - if ( exc->ignore_x_mode ) - { - if ( exc->face->sph_compatibility_mode && - exc->GS.freeVector.y != 0 && - ( B1 & 63 ) == 0 && - ( B2 & 63 ) != 0 ) - reverse_move = TRUE; - - if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) && - exc->GS.freeVector.y != 0 && - ( B2 & 63 ) != 0 && - ( B1 & 63 ) != 0 ) - reverse_move = TRUE; - } - - if ( reverse_move ) - exc->func_move( exc, - &exc->zp1, - point, - SUB_LONG( cur_dist, distance ) ); - } - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - Fail: exc->GS.rp1 = exc->GS.rp0; + exc->GS.rp2 = point; if ( ( exc->opcode & 16 ) != 0 ) exc->GS.rp0 = point; - - exc->GS.rp2 = point; } @@ -6525,36 +5672,33 @@ * Stack: uint32 uint32... --> */ static void - Ins_ALIGNRP( TT_ExecContext exc ) + Ins_ALIGNRP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_UShort point; FT_F26Dot6 distance; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->iup_called && - ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) ) + if ( exc->new_top < loop ) { - exc->error = FT_THROW( Invalid_Reference ); + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); goto Fail; } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - if ( exc->top < exc->GS.loop || - BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) + exc->new_top -= loop; + + if ( BOUNDS( exc->GS.rp0, exc->zp0.n_points ) ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); goto Fail; } - while ( exc->GS.loop > 0 ) + while ( loop-- ) { - exc->args--; - - point = (FT_UShort)exc->stack[exc->args]; + point = (FT_UShort)*(--args); if ( BOUNDS( point, exc->zp1.n_points ) ) { @@ -6571,13 +5715,10 @@ exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) ); } - - exc->GS.loop--; } Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -6719,15 +5860,26 @@ /* SOMETIMES, DUMBER CODE IS BETTER CODE */ static void - Ins_IP( TT_ExecContext exc ) + Ins_IP( TT_ExecContext exc, + FT_Long* args ) { + FT_Long loop = exc->GS.loop; FT_F26Dot6 old_range, cur_range; FT_Vector* orus_base; FT_Vector* cur_base; FT_Int twilight; - if ( exc->top < exc->GS.loop ) + if ( exc->new_top < loop ) + { + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); + goto Fail; + } + + exc->new_top -= loop; + + if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); @@ -6743,13 +5895,6 @@ exc->GS.gep1 == 0 || exc->GS.gep2 == 0 ); - if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); - goto Fail; - } - if ( twilight ) orus_base = &exc->zp0.org[exc->GS.rp1]; else @@ -6761,8 +5906,7 @@ /* 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( exc->GS.rp1, exc->zp0.n_points ) || - BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) + if ( BOUNDS( exc->GS.rp2, exc->zp1.n_points ) ) { old_range = 0; cur_range = 0; @@ -6791,9 +5935,9 @@ cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base ); } - for ( ; exc->GS.loop > 0; exc->GS.loop-- ) + while ( loop-- ) { - FT_UInt point = (FT_UInt)exc->stack[--exc->args]; + FT_UInt point = (FT_UInt)*(--args); FT_F26Dot6 org_dist, cur_dist, new_dist; @@ -6865,7 +6009,6 @@ Fail: exc->GS.loop = 1; - exc->new_top = exc->args; } @@ -6916,7 +6059,7 @@ static void - _iup_worker_shift( IUP_Worker worker, + iup_worker_shift_( IUP_Worker worker, FT_UInt p1, FT_UInt p2, FT_UInt p ) @@ -6938,7 +6081,7 @@ static void - _iup_worker_interpolate( IUP_Worker worker, + iup_worker_interpolate_( IUP_Worker worker, FT_UInt p1, FT_UInt p2, FT_UInt ref1, @@ -7064,17 +6207,10 @@ /* See `ttinterp.h' for details on backward compatibility mode. */ /* Allow IUP until it has been called on both axes. Immediately */ /* return on subsequent ones. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) - { - if ( exc->iupx_called && exc->iupy_called ) - return; - - if ( exc->opcode & 1 ) - exc->iupx_called = TRUE; - else - exc->iupy_called = TRUE; - } + if ( exc->backward_compatibility == 0x7 ) + return; + else if ( exc->backward_compatibility ) + exc->backward_compatibility |= 1 << ( exc->opcode & 1 ); #endif /* ignore empty outlines */ @@ -7100,16 +6236,6 @@ contour = 0; point = 0; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode ) - { - exc->iup_called = TRUE; - if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP ) - return; - } -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - do { end_point = exc->pts.contours[contour] - exc->pts.first_point; @@ -7132,7 +6258,7 @@ { if ( ( exc->pts.tags[point] & mask ) != 0 ) { - _iup_worker_interpolate( &V, + iup_worker_interpolate_( &V, cur_touched + 1, point - 1, cur_touched, @@ -7144,17 +6270,17 @@ } if ( cur_touched == first_touched ) - _iup_worker_shift( &V, first_point, end_point, cur_touched ); + iup_worker_shift_( &V, first_point, end_point, cur_touched ); else { - _iup_worker_interpolate( &V, + iup_worker_interpolate_( &V, (FT_UShort)( cur_touched + 1 ), end_point, cur_touched, first_touched ); if ( first_touched > 0 ) - _iup_worker_interpolate( &V, + iup_worker_interpolate_( &V, first_point, first_touched - 1, cur_touched, @@ -7176,39 +6302,50 @@ Ins_DELTAP( TT_ExecContext exc, FT_Long* args ) { - FT_ULong nump, k; + FT_Long nump; FT_UShort A; - FT_ULong C, P; - FT_Long B; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_UShort B1, B2; + FT_Long B, P, F; - if ( SUBPIXEL_HINTING_INFINALITY && - exc->ignore_x_mode && - exc->iup_called && - ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) - goto Fail; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ + nump = args[0]; /* signed value for convenience */ - P = (FT_ULong)exc->func_cur_ppem( exc ); - 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 ( nump < 0 || nump > exc->new_top / 2 ) { - if ( exc->args < 2 ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - exc->args = 0; - goto Fail; - } + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); - exc->args -= 2; + nump = exc->new_top / 2; + } - A = (FT_UShort)exc->stack[exc->args + 1]; - B = exc->stack[exc->args]; + exc->new_top -= 2 * nump; + + P = exc->func_cur_ppem( exc ) - exc->GS.delta_base; + + switch ( exc->opcode ) + { + case 0x5D: + break; + + case 0x71: + P -= 16; + break; + + case 0x72: + P -= 32; + break; + } + + /* check applicable range of adjusted ppem */ + if ( P & ~0xF ) /* P < 0 || P > 15 */ + return; + + P <<= 4; + F = 1L << ( 6 - exc->GS.delta_shift ); + + while ( nump-- ) + { + A = (FT_UShort)*(--args); + B = *(--args); /* XXX: Because some popular fonts contain some invalid DeltaP */ /* instructions, we simply ignore them when the stacked */ @@ -7216,120 +6353,38 @@ /* error. As a delta instruction doesn't change a glyph */ /* in great ways, this shouldn't be a problem. */ - if ( !BOUNDS( A, exc->zp0.n_points ) ) + if ( BOUNDS( A, exc->zp0.n_points ) ) { - C = ( (FT_ULong)B & 0xF0 ) >> 4; - - switch ( exc->opcode ) + if ( exc->pedantic_hinting ) { - case 0x5D: - break; - - case 0x71: - C += 16; - break; - - case 0x72: - C += 32; - break; - } - - C += exc->GS.delta_base; - - if ( P == C ) - { - B = ( (FT_ULong)B & 0xF ) - 8; - if ( B >= 0 ) - B++; - B *= 1L << ( 6 - exc->GS.delta_shift ); - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( SUBPIXEL_HINTING_INFINALITY ) - { - /* - * Allow delta move if - * - * - not using ignore_x_mode rendering, - * - glyph is specifically set to allow it, or - * - glyph is composite and freedom vector is not in subpixel - * direction. - */ - if ( !exc->ignore_x_mode || - ( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) || - ( exc->is_composite && exc->GS.freeVector.y != 0 ) ) - exc->func_move( exc, &exc->zp0, A, B ); - - /* Otherwise, apply subpixel hinting and compatibility mode */ - /* rules, always skipping deltas in subpixel direction. */ - else if ( exc->ignore_x_mode && exc->GS.freeVector.y != 0 ) - { - /* save the y value of the point now; compare after move */ - B1 = (FT_UShort)exc->zp0.cur[A].y; - - /* Standard subpixel hinting: Allow y move for y-touched */ - /* points. This messes up DejaVu ... */ - if ( !exc->face->sph_compatibility_mode && - ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) - exc->func_move( exc, &exc->zp0, A, B ); - - /* compatibility mode */ - else if ( exc->face->sph_compatibility_mode && - !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) ) - { - if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) - B = FT_PIX_ROUND( B1 + B ) - B1; - - /* Allow delta move if using sph_compatibility_mode, */ - /* IUP has not been called, and point is touched on Y. */ - if ( !exc->iup_called && - ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) - exc->func_move( exc, &exc->zp0, A, B ); - } - - B2 = (FT_UShort)exc->zp0.cur[A].y; - - /* Reverse this move if it results in a disallowed move */ - if ( exc->GS.freeVector.y != 0 && - ( ( exc->face->sph_compatibility_mode && - ( B1 & 63 ) == 0 && - ( B2 & 63 ) != 0 ) || - ( ( exc->sph_tweak_flags & - SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) && - ( B1 & 63 ) != 0 && - ( B2 & 63 ) != 0 ) ) ) - exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) ); - } - } - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - { - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* See `ttinterp.h' for details on backward compatibility */ - /* mode. */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->backward_compatibility ) - { - if ( !( exc->iupx_called && exc->iupy_called ) && - ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || - ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) - exc->func_move( exc, &exc->zp0, A, B ); - } - else -#endif - exc->func_move( exc, &exc->zp0, A, B ); - } + exc->error = FT_THROW( Invalid_Reference ); + return; } } else - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Invalid_Reference ); - } + { + if ( ( B & 0xF0 ) == P ) + { + B = ( B & 0xF ) - 8; + if ( B >= 0 ) + B++; + B *= F; - Fail: - exc->new_top = exc->args; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility ) + { + if ( exc->backward_compatibility != 0x7 && + ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || + ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) ) + exc->func_move( exc, &exc->zp0, A, B ); + } + else +#endif + exc->func_move( exc, &exc->zp0, A, B ); + } + } + } } @@ -7343,28 +6398,50 @@ Ins_DELTAC( TT_ExecContext exc, FT_Long* args ) { - FT_ULong nump, k; - FT_ULong A, C, P; - FT_Long B; + FT_Long nump; + FT_ULong A; + FT_Long B, P, F; - P = (FT_ULong)exc->func_cur_ppem( exc ); - nump = (FT_ULong)args[0]; + nump = args[0]; /* signed value for convenience */ - for ( k = 1; k <= nump; k++ ) + if ( nump < 0 || nump > exc->new_top / 2 ) { - if ( exc->args < 2 ) - { - if ( exc->pedantic_hinting ) - exc->error = FT_THROW( Too_Few_Arguments ); - exc->args = 0; - goto Fail; - } + if ( exc->pedantic_hinting ) + exc->error = FT_THROW( Too_Few_Arguments ); - exc->args -= 2; + nump = exc->new_top / 2; + } - A = (FT_ULong)exc->stack[exc->args + 1]; - B = exc->stack[exc->args]; + exc->new_top -= 2 * nump; + + P = exc->func_cur_ppem( exc ) - exc->GS.delta_base; + + switch ( exc->opcode ) + { + case 0x73: + break; + + case 0x74: + P -= 16; + break; + + case 0x75: + P -= 32; + break; + } + + /* check applicable range of adjusted ppem */ + if ( P & ~0xF ) /* P < 0 || P > 15 */ + return; + + P <<= 4; + F = 1L << ( 6 - exc->GS.delta_shift ); + + while ( nump-- ) + { + A = (FT_ULong)*(--args); + B = *(--args); if ( BOUNDSL( A, exc->cvtSize ) ) { @@ -7376,38 +6453,17 @@ } else { - C = ( (FT_ULong)B & 0xF0 ) >> 4; - - switch ( exc->opcode ) + if ( ( B & 0xF0 ) == P ) { - case 0x73: - break; - - case 0x74: - C += 16; - break; - - case 0x75: - C += 32; - break; - } - - C += exc->GS.delta_base; - - if ( P == C ) - { - B = ( (FT_ULong)B & 0xF ) - 8; + B = ( B & 0xF ) - 8; if ( B >= 0 ) B++; - B *= 1L << ( 6 - exc->GS.delta_shift ); + B *= F; exc->func_move_cvt( exc, A, B ); } } } - - Fail: - exc->new_top = exc->args; } @@ -7423,14 +6479,6 @@ * GETINFO[]: GET INFOrmation * Opcode range: 0x88 * Stack: uint32 --> uint32 - * - * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May - * 2015) not documented in the OpenType specification. - * - * Selector bit 11 is incorrectly described as bit 8, while the - * real meaning of bit 8 (vertical LCD subpixels) stays - * undocumented. The same mistake can be found in Greg Hitchcock's - * whitepaper. */ static void Ins_GETINFO( TT_ExecContext exc, @@ -7442,31 +6490,8 @@ K = 0; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - /********************************* - * RASTERIZER VERSION - * Selector Bit: 0 - * Return Bit(s): 0-7 - */ - if ( SUBPIXEL_HINTING_INFINALITY && - ( args[0] & 1 ) != 0 && - exc->subpixel_hinting ) - { - if ( exc->ignore_x_mode ) - { - /* if in ClearType backward compatibility mode, */ - /* we sometimes change the TrueType version dynamically */ - K = exc->rasterizer_version; - FT_TRACE6(( "Setting rasterizer version %d\n", - exc->rasterizer_version )); - } - else - K = TT_INTERPRETER_VERSION_38; - } - else -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - if ( ( args[0] & 1 ) != 0 ) - K = driver->interpreter_version; + if ( ( args[0] & 1 ) != 0 ) + K = driver->interpreter_version; /********************************* * GLYPH ROTATED @@ -7489,8 +6514,6 @@ * VARIATION GLYPH * Selector Bit: 3 * Return Bit(s): 10 - * - * XXX: UNDOCUMENTED! */ if ( (args[0] & 8 ) != 0 && exc->face->blend ) K |= 1 << 10; @@ -7510,7 +6533,7 @@ /* Otherwise, instructions may behave weirdly and rendering results */ /* may differ between v35 and v40 mode, e.g., in `Times New Roman */ /* Bold Italic'. */ - if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean ) + if ( SUBPIXEL_HINTING_MINIMAL && exc->mode != FT_RENDER_MODE_MONO ) { /********************************* * HINTING FOR SUBPIXEL @@ -7527,7 +6550,7 @@ * Selector Bit: 8 * Return Bit(s): 15 */ - if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean ) + if ( ( args[0] & 256 ) != 0 && exc->mode == FT_RENDER_MODE_LCD_V ) K |= 1 << 15; /********************************* @@ -7548,7 +6571,7 @@ * The only smoothing method FreeType supports unless someone sets * FT_LOAD_TARGET_MONO. */ - if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean ) + if ( ( args[0] & 2048 ) != 0 && exc->mode != FT_RENDER_MODE_MONO ) K |= 1 << 18; /********************************* @@ -7560,94 +6583,14 @@ * Grayscale rendering is what FreeType does anyway unless someone * sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V) */ - if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype ) + if ( ( args[0] & 4096 ) != 0 && + exc->mode != FT_RENDER_MODE_MONO && + exc->mode != FT_RENDER_MODE_LCD && + exc->mode != FT_RENDER_MODE_LCD_V ) K |= 1 << 19; } #endif -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( SUBPIXEL_HINTING_INFINALITY && - exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 ) - { - - if ( exc->rasterizer_version >= 37 ) - { - /********************************* - * HINTING FOR SUBPIXEL - * Selector Bit: 6 - * Return Bit(s): 13 - */ - if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting ) - K |= 1 << 13; - - /********************************* - * COMPATIBLE WIDTHS ENABLED - * Selector Bit: 7 - * Return Bit(s): 14 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 128 ) != 0 && exc->compatible_widths ) - K |= 1 << 14; - - /********************************* - * VERTICAL LCD SUBPIXELS? - * Selector Bit: 8 - * Return Bit(s): 15 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd ) - K |= 1 << 15; - - /********************************* - * HINTING FOR BGR? - * Selector Bit: 9 - * Return Bit(s): 16 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 512 ) != 0 && exc->bgr ) - K |= 1 << 16; - - if ( exc->rasterizer_version >= 38 ) - { - /********************************* - * SUBPIXEL POSITIONED? - * Selector Bit: 10 - * Return Bit(s): 17 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned ) - K |= 1 << 17; - - /********************************* - * SYMMETRICAL SMOOTHING - * Selector Bit: 11 - * Return Bit(s): 18 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing ) - K |= 1 << 18; - - /********************************* - * GRAY CLEARTYPE - * Selector Bit: 12 - * Return Bit(s): 19 - * - * Functionality still needs to be added - */ - if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype ) - K |= 1 << 19; - } - } - } - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - args[0] = K; } @@ -7690,6 +6633,8 @@ for ( i = 0; i < num_axes; i++ ) args[i] = 0; } + + exc->new_top += num_axes; } @@ -7715,7 +6660,7 @@ Ins_UNKNOWN( TT_ExecContext exc ) { TT_DefRecord* def = exc->IDefs; - TT_DefRecord* limit = def + exc->numIDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); for ( ; def < limit; def++ ) @@ -7740,7 +6685,6 @@ Ins_Goto_CodeRange( exc, def->range, def->start ); - exc->step_ins = FALSE; return; } } @@ -7782,133 +6726,28 @@ /* documentation is in ttinterp.h */ FT_EXPORT_DEF( FT_Error ) - TT_RunIns( TT_ExecContext exc ) + TT_RunIns( void* exec ) { - FT_ULong ins_counter = 0; /* executed instructions counter */ - FT_ULong num_twilight_points; - FT_UShort i; + TT_ExecContext exc = (TT_ExecContext)exec; + FT_ULong ins_counter = 0; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - FT_Byte opcode_pattern[1][2] = { - /* #8 TypeMan Talk Align */ - { - 0x06, /* SPVTL */ - 0x7D, /* RDTG */ - }, - }; - FT_UShort opcode_patterns = 1; - FT_UShort opcode_pointer[1] = { 0 }; - FT_UShort opcode_size[1] = { 1 }; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - exc->iup_called = FALSE; -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* - * Toggle backward compatibility according to what font wants, except - * when - * - * 1) we have a `tricky' font that heavily relies on the interpreter to - * render glyphs correctly, for example DFKai-SB, or - * 2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested. - * - * In those cases, backward compatibility needs to be turned off to get - * correct rendering. The rendering is then completely up to the - * font's programming. - * - */ - if ( SUBPIXEL_HINTING_MINIMAL && - exc->subpixel_hinting_lean && - !FT_IS_TRICKY( &exc->face->root ) ) - exc->backward_compatibility = !( exc->GS.instruct_control & 4 ); - else - exc->backward_compatibility = FALSE; - - exc->iupx_called = FALSE; - exc->iupy_called = FALSE; -#endif - - /* We restrict the number of twilight points to a reasonable, */ - /* heuristic value to avoid slow execution of malformed bytecode. */ - num_twilight_points = FT_MAX( 30, - 2 * ( exc->pts.n_points + exc->cvtSize ) ); - if ( exc->twilight.n_points > num_twilight_points ) - { - if ( num_twilight_points > 0xFFFFU ) - num_twilight_points = 0xFFFFU; - - FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" - " from %d to the more reasonable value %d\n", - exc->twilight.n_points, - num_twilight_points )); - exc->twilight.n_points = (FT_UShort)num_twilight_points; - } - - /* Set up loop detectors. We restrict the number of LOOPCALL loops */ - /* and the number of JMPR, JROT, and JROF calls with a negative */ - /* argument to values that depend on various parameters like the */ - /* size of the CVT table or the number of points in the current */ - /* glyph (if applicable). */ - /* */ - /* The idea is that in real-world bytecode you either iterate over */ - /* all CVT entries (in the `prep' table), or over all points (or */ - /* contours, in the `glyf' table) of a glyph, and such iterations */ - /* don't happen very often. */ - exc->loopcall_counter = 0; - exc->neg_jump_counter = 0; - - /* The maximum values are heuristic. */ - if ( exc->pts.n_points ) - exc->loopcall_counter_max = FT_MAX( 50, - 10 * exc->pts.n_points ) + - FT_MAX( 50, - exc->cvtSize / 10 ); - else - exc->loopcall_counter_max = 300 + 8 * exc->cvtSize; - - /* as a protection against an unreasonable number of CVT entries */ - /* we assume at most 100 control values per glyph for the counter */ - if ( exc->loopcall_counter_max > - 100 * (FT_ULong)exc->face->root.num_glyphs ) - exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs; - - FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" - " to %d\n", exc->loopcall_counter_max )); - - exc->neg_jump_counter_max = exc->loopcall_counter_max; - FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" - " to %d\n", exc->neg_jump_counter_max )); - - /* set PPEM and CVT functions */ - exc->tt_metrics.ratio = 0; - if ( exc->metrics.x_ppem != exc->metrics.y_ppem ) - { - /* non-square pixels, use the stretched routines */ - exc->func_cur_ppem = Current_Ppem_Stretched; - exc->func_read_cvt = Read_CVT_Stretched; - exc->func_write_cvt = Write_CVT_Stretched; - exc->func_move_cvt = Move_CVT_Stretched; - } - else - { - /* square pixels, use normal routines */ - exc->func_cur_ppem = Current_Ppem; - exc->func_read_cvt = Read_CVT; - exc->func_write_cvt = Write_CVT; - exc->func_move_cvt = Move_CVT; - } - - Compute_Funcs( exc ); - Compute_Round( exc, (FT_Byte)exc->GS.round_state ); do { + /* increment instruction counter and check if we didn't */ + /* run this program for too long (e.g. infinite loops). */ + if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) + { + exc->error = FT_THROW( Execution_Too_Long ); + goto LErrorLabel_; + } + + exc->error = FT_Err_Ok; exc->opcode = exc->code[exc->IP]; + exc->length = 1; #ifdef FT_DEBUG_LEVEL_TRACE + if ( ft_trace_levels[trace_ttinterp] >= 6 ) { FT_Long cnt = FT_MIN( 8, exc->top ); FT_Long n; @@ -7917,29 +6756,18 @@ /* if tracing level is 7, show current code position */ /* and the first few stack elements also */ FT_TRACE6(( " " )); - FT_TRACE7(( "%06d ", exc->IP )); + FT_TRACE7(( "%06ld ", exc->IP )); FT_TRACE6(( "%s", opcode_name[exc->opcode] + 2 )); FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A' ? 2 : 12 - ( *opcode_name[exc->opcode] - '0' ), "#" )); for ( n = 1; n <= cnt; n++ ) - FT_TRACE7(( " %d", exc->stack[exc->top - n] )); + FT_TRACE7(( " %ld", exc->stack[exc->top - n] )); FT_TRACE6(( "\n" )); } #endif /* FT_DEBUG_LEVEL_TRACE */ - if ( ( exc->length = opcode_length[exc->opcode] ) < 0 ) - { - if ( exc->IP + 1 >= exc->codeSize ) - goto LErrorCodeOverflow_; - - exc->length = 2 - exc->length * exc->code[exc->IP + 1]; - } - - if ( exc->IP + exc->length > exc->codeSize ) - goto LErrorCodeOverflow_; - /* First, let's check for empty stack and overflow */ exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 ); @@ -7947,6 +6775,9 @@ /* One can also interpret it as the index of the last argument. */ if ( exc->args < 0 ) { + FT_UShort i; + + if ( exc->pedantic_hinting ) { exc->error = FT_THROW( Too_Few_Arguments ); @@ -7959,21 +6790,7 @@ exc->args = 0; } -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( exc->opcode == 0x91 ) - { - /* this is very special: GETVARIATION returns */ - /* a variable number of arguments */ - - /* it is the job of the application to `activate' GX handling, */ - /* this is, calling any of the GX API functions on the current */ - /* font to select a variation instance */ - if ( exc->face->blend ) - exc->new_top = exc->args + exc->face->blend->num_axis; - } - else -#endif - exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 ); + exc->new_top = exc->args + ( Pop_Push_Count[exc->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' */ @@ -7984,42 +6801,6 @@ goto LErrorLabel_; } - exc->step_ins = TRUE; - exc->error = FT_Err_Ok; - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - if ( SUBPIXEL_HINTING_INFINALITY ) - { - for ( i = 0; i < opcode_patterns; i++ ) - { - if ( opcode_pointer[i] < opcode_size[i] && - exc->opcode == opcode_pattern[i][opcode_pointer[i]] ) - { - opcode_pointer[i] += 1; - - if ( opcode_pointer[i] == opcode_size[i] ) - { - FT_TRACE6(( "sph: opcode ptrn: %d, %s %s\n", - i, - exc->face->root.family_name, - exc->face->root.style_name )); - - switch ( i ) - { - case 0: - break; - } - opcode_pointer[i] = 0; - } - } - else - opcode_pointer[i] = 0; - } - } - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - { FT_Long* args = exc->stack + exc->args; FT_Byte opcode = exc->opcode; @@ -8202,7 +6983,7 @@ case 0x32: /* SHP */ case 0x33: /* SHP */ - Ins_SHP( exc ); + Ins_SHP( exc, args ); break; case 0x34: /* SHC */ @@ -8220,7 +7001,7 @@ break; case 0x39: /* IP */ - Ins_IP( exc ); + Ins_IP( exc, args ); break; case 0x3A: /* MSIRP */ @@ -8229,7 +7010,7 @@ break; case 0x3C: /* AlignRP */ - Ins_ALIGNRP( exc ); + Ins_ALIGNRP( exc, args ); break; case 0x3D: /* RTDG */ @@ -8465,7 +7246,7 @@ break; case 0x80: /* FLIPPT */ - Ins_FLIPPT( exc ); + Ins_FLIPPT( exc, args ); break; case 0x81: /* FLIPRGON */ @@ -8526,7 +7307,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT case 0x91: /* it is the job of the application to `activate' GX handling, */ - /* this is, calling any of the GX API functions on the current */ + /* that is, calling any of the GX API functions on the current */ /* font to select a variation instance */ if ( exc->face->blend ) Ins_GETVARIATION( exc, args ); @@ -8563,13 +7344,13 @@ { switch ( exc->error ) { - /* looking for redefined instructions */ case FT_ERR( Invalid_Opcode ): { TT_DefRecord* def = exc->IDefs; - TT_DefRecord* limit = def + exc->numIDefs; + TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); + /* looking for redefined instructions */ for ( ; def < limit; def++ ) { if ( def->active && exc->opcode == (FT_Byte)def->opc ) @@ -8599,34 +7380,15 @@ } } } - - exc->error = FT_THROW( 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 + FALL_THROUGH; default: goto LErrorLabel_; - -#if 0 - break; -#endif } } exc->top = exc->new_top; - - if ( exc->step_ins ) - exc->IP += exc->length; - - /* increment instruction counter and check if we didn't */ - /* run this program for too long (e.g. infinite loops). */ - if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES ) - return FT_THROW( Execution_Too_Long ); + exc->IP += exc->length; LSuiteLabel_: if ( exc->IP >= exc->codeSize ) @@ -8642,13 +7404,11 @@ } while ( !exc->instruction_trap ); LNo_Error_: - FT_TRACE4(( " %d instruction%s executed\n", + FT_TRACE4(( " %lu instruction%s executed\n", ins_counter, ins_counter == 1 ? "" : "s" )); - return FT_Err_Ok; - LErrorCodeOverflow_: - exc->error = FT_THROW( Code_Overflow ); + return FT_Err_Ok; LErrorLabel_: if ( exc->error && !exc->instruction_trap ) @@ -8657,10 +7417,130 @@ return exc->error; } + + /************************************************************************** + * + * @Function: + * TT_Run_Context + * + * @Description: + * Executes one or more instructions in the execution context. + * + * @Input: + * exec :: + * A handle to the target execution context. + * + * @Return: + * TrueType error code. 0 means success. + */ + FT_LOCAL_DEF( FT_Error ) + TT_Run_Context( TT_ExecContext exec, + TT_Size size ) + { + FT_ULong num_twilight_points; + + + exec->zp0 = exec->pts; + exec->zp1 = exec->pts; + exec->zp2 = exec->pts; + + /* We restrict the number of twilight points to a reasonable, */ + /* heuristic value to avoid slow execution of malformed bytecode. */ + /* The selected value is large enough to support fonts hinted */ + /* with `ttfautohint`, which uses twilight points to store */ + /* vertical coordinates of (auto-hinter) segments. */ + num_twilight_points = FT_MAX( 30, + 2 * ( exec->pts.n_points + exec->cvtSize ) ); + if ( exec->twilight.n_points > num_twilight_points ) + { + if ( num_twilight_points > 0xFFFFU ) + num_twilight_points = 0xFFFFU; + + FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n" )); + FT_TRACE5(( " from %d to the more reasonable value %lu\n", + exec->twilight.n_points, + num_twilight_points )); + exec->twilight.n_points = (FT_UShort)num_twilight_points; + } + + /* Set up loop detectors. We restrict the number of LOOPCALL loops */ + /* and the number of JMPR, JROT, and JROF calls with a negative */ + /* argument to values that depend on various parameters like the */ + /* size of the CVT table or the number of points in the current */ + /* glyph (if applicable). */ + /* */ + /* The idea is that in real-world bytecode you either iterate over */ + /* all CVT entries (in the `prep' table), or over all points (or */ + /* contours, in the `glyf' table) of a glyph, and such iterations */ + /* don't happen very often. */ + exec->loopcall_counter = 0; + exec->neg_jump_counter = 0; + + /* The maximum values are heuristic. */ + if ( exec->pts.n_points ) + exec->loopcall_counter_max = FT_MAX( 50, + 10 * exec->pts.n_points ) + + FT_MAX( 50, + exec->cvtSize / 10 ); + else + exec->loopcall_counter_max = 300 + 22 * exec->cvtSize; + + /* as a protection against an unreasonable number of CVT entries */ + /* we assume at most 100 control values per glyph for the counter */ + if ( exec->loopcall_counter_max > + 100 * (FT_ULong)exec->face->root.num_glyphs ) + exec->loopcall_counter_max = 100 * (FT_ULong)exec->face->root.num_glyphs; + + FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL" + " to %lu\n", exec->loopcall_counter_max )); + + exec->neg_jump_counter_max = exec->loopcall_counter_max; + FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps" + " to %lu\n", exec->neg_jump_counter_max )); + + /* set PPEM and CVT functions */ + if ( exec->metrics.x_ppem != exec->metrics.y_ppem ) + { + /* non-square pixels, use the stretched routines */ + exec->func_cur_ppem = Current_Ppem_Stretched; + exec->func_read_cvt = Read_CVT_Stretched; + exec->func_write_cvt = Write_CVT_Stretched; + exec->func_move_cvt = Move_CVT_Stretched; + } + else + { + /* square pixels, use normal routines */ + exec->func_cur_ppem = Current_Ppem; + exec->func_read_cvt = Read_CVT; + exec->func_write_cvt = Write_CVT; + exec->func_move_cvt = Move_CVT; + } + + /* reset graphics state */ + exec->GS = size->GS; + exec->func_round = (TT_Round_Func)Round_To_Grid; + Compute_Funcs( exec ); + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Reset IUP tracking bits in the backward compatibility mode. */ + /* See `ttinterp.h' for details. */ + exec->backward_compatibility &= ~0x3; +#endif + + /* some glyphs leave something on the stack, */ + /* so we clean it before a new execution. */ + exec->top = 0; + exec->callTop = 0; + + exec->instruction_trap = FALSE; + + return exec->interpreter( exec ); + } + #else /* !TT_USE_BYTECODE_INTERPRETER */ /* ANSI C doesn't like empty source files */ - typedef int _tt_interp_dummy; + typedef int tt_interp_dummy_; #endif /* !TT_USE_BYTECODE_INTERPRETER */ diff --git a/src/thirdparty/freetype2/src/truetype/ttinterp.h b/src/thirdparty/freetype2/src/truetype/ttinterp.h index 0cb1e892f..2e69d1918 100644 --- a/src/thirdparty/freetype2/src/truetype/ttinterp.h +++ b/src/thirdparty/freetype2/src/truetype/ttinterp.h @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,7 +19,6 @@ #ifndef TTINTERP_H_ #define TTINTERP_H_ -#include #include "ttobjs.h" @@ -40,6 +39,60 @@ FT_BEGIN_HEADER #define TT_Round_Super_45 7 + /************************************************************************** + * + * 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_Long 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_Long end; /* where does it end? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + + } TT_DefRecord, *TT_DefArray; + + /************************************************************************** * * Function types used by the interpreter, depending on various modes @@ -99,147 +152,110 @@ FT_BEGIN_HEADER } TT_CallRec, *TT_CallStack; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - /************************************************************************** - * - * These structures define rules used to tweak subpixel hinting for - * various fonts. "", 0, "", NULL value indicates to match any value. - */ - -#define SPH_MAX_NAME_SIZE 32 -#define SPH_MAX_CLASS_MEMBERS 100 - - typedef struct SPH_TweakRule_ - { - const char family[SPH_MAX_NAME_SIZE]; - const FT_UInt ppem; - const char style[SPH_MAX_NAME_SIZE]; - const FT_ULong glyph; - - } SPH_TweakRule; - - - typedef struct SPH_ScaleRule_ - { - const char family[SPH_MAX_NAME_SIZE]; - const FT_UInt ppem; - const char style[SPH_MAX_NAME_SIZE]; - const FT_ULong glyph; - const FT_ULong scale; - - } SPH_ScaleRule; - - - typedef struct SPH_Font_Class_ - { - const char name[SPH_MAX_NAME_SIZE]; - const char member[SPH_MAX_CLASS_MEMBERS][SPH_MAX_NAME_SIZE]; - - } SPH_Font_Class; - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - /************************************************************************** * * The main structure for the interpreter which collects all necessary * variables and states. + * + * Members that are initialized by `TT_Load_Context` are marked with '!'. + * Members that are initialized by `TT_Run_Context` are marked with '@'. */ typedef struct TT_ExecContextRec_ { - TT_Face face; - TT_Size size; + TT_Face face; /* ! */ + TT_Size size; /* ! */ FT_Memory memory; + TT_Interpreter interpreter; /* instructions state */ FT_Error error; /* last execution error */ - FT_Long top; /* top of exec. stack */ + FT_Long top; /* @! top of exec. stack */ - FT_Long stackSize; /* size of exec. stack */ - FT_Long* stack; /* current exec. stack */ + FT_Long stackSize; /* ! size of exec. stack */ + FT_Long* stack; /* ! current exec. stack */ FT_Long args; - FT_Long new_top; /* new top after exec. */ + FT_Long new_top; /* new top after exec. */ - TT_GlyphZoneRec zp0, /* zone records */ - zp1, - zp2, - pts, - twilight; + TT_GlyphZoneRec zp0, /* @! zone records */ + zp1, /* @! */ + zp2, /* @! */ + pts, /* ! */ + twilight; /* ! */ - FT_Long pointSize; /* in 26.6 format */ - FT_Size_Metrics metrics; - TT_Size_Metrics tt_metrics; /* size metrics */ + FT_Long pointSize; /* ! in 26.6 format */ + FT_Size_Metrics metrics; /* ! */ + TT_Size_Metrics tt_metrics; /* ! size metrics */ - TT_GraphicsState GS; /* current graphics state */ + TT_GraphicsState GS; /* !@ current graphics state */ + FT_Int iniRange; /* initial code range number */ 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_Byte opcode; /* current opcode */ + FT_Int length; /* opcode length or increment */ - FT_Bool step_ins; /* true if the interpreter must */ - /* increment IP after ins. exec */ - FT_ULong cvtSize; - FT_Long* cvt; + FT_ULong cvtSize; /* ! */ + FT_Long* cvt; /* ! */ + FT_ULong glyfCvtSize; + FT_Long* glyfCvt; /* cvt working copy for glyph */ - FT_UInt glyphSize; /* glyph instructions buffer size */ - FT_Byte* glyphIns; /* glyph instructions buffer */ + 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 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 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_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_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 */ + 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_UShort storeSize; /* ! size of current storage */ + FT_Long* storage; /* ! storage area */ + FT_UShort glyfStoreSize; + FT_Long* glyfStorage; /* storage working copy for glyph */ FT_F26Dot6 period; /* values used for the */ FT_F26Dot6 phase; /* `SuperRounding' */ FT_F26Dot6 threshold; - FT_Bool instruction_trap; /* If `True', the interpreter will */ - /* exit after each instruction */ + FT_Bool instruction_trap; /* ! If `True', the interpreter */ + /* exits 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_Round_Func func_round; /* current rounding function */ + + FT_Vector moveVector; /* "projected" freedom vector */ 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; /* current point move function */ TT_Move_Func func_move_orig; /* move original position function */ TT_Cur_Ppem_Func func_cur_ppem; /* get current proj. ppem value */ @@ -362,68 +378,15 @@ FT_BEGIN_HEADER * */ - /* Using v40 implies subpixel hinting, unless FT_RENDER_MODE_MONO has been - * requested. Used to detect interpreter */ - /* version switches. `_lean' to differentiate from the Infinality */ - /* `subpixel_hinting', which is managed differently. */ - FT_Bool subpixel_hinting_lean; + /* Activate backward compatibility (bit 2) and track IUP (bits 0-1). */ + /* If this is zero, it means that the interpreter is either in v35 */ + /* or in native ClearType mode. */ + FT_Int backward_compatibility; - /* Long side of a LCD subpixel is vertical (e.g., screen is rotated). */ - /* `_lean' to differentiate from the Infinality `vertical_lcd', which */ - /* is managed differently. */ - FT_Bool vertical_lcd_lean; + FT_Render_Mode mode; /* target render mode */ - /* Default to backward compatibility mode in v40 interpreter. If */ - /* this is false, it implies the interpreter is in v35 or in native */ - /* ClearType mode. */ - FT_Bool backward_compatibility; - - /* Useful for detecting and denying post-IUP trickery that is usually */ - /* used to fix pixel patterns (`superhinting'). */ - FT_Bool iupx_called; - FT_Bool iupy_called; - - /* ClearType hinting and grayscale rendering, as used by Universal */ - /* Windows Platform apps (Windows 8 and above). Like the standard */ - /* colorful ClearType mode, it utilizes a vastly increased virtual */ - /* resolution on the x axis. Different from bi-level hinting and */ - /* grayscale rendering, the old mode from Win9x days that roughly */ - /* adheres to the physical pixel grid on both axes. */ - FT_Bool grayscale_cleartype; #endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - TT_Round_Func func_round_sphn; /* subpixel rounding function */ - - FT_Bool subpixel_hinting; /* Using subpixel hinting? */ - FT_Bool ignore_x_mode; /* Standard rendering mode for */ - /* subpixel hinting. On if gray */ - /* or subpixel hinting is on. */ - - /* The following 6 aren't fully implemented but here for MS rasterizer */ - /* compatibility. */ - FT_Bool compatible_widths; /* compatible widths? */ - FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */ - FT_Bool bgr; /* bgr instead of rgb? */ - FT_Bool vertical_lcd; /* long side of LCD subpixel */ - /* rectangles is horizontal */ - FT_Bool subpixel_positioned; /* subpixel positioned */ - /* (DirectWrite ClearType)? */ - FT_Bool gray_cleartype; /* ClearType hinting but */ - /* grayscale rendering */ - - FT_Int rasterizer_version; /* MS rasterizer version */ - - FT_Bool iup_called; /* IUP called for glyph? */ - - FT_ULong sph_tweak_flags; /* flags to control */ - /* hint tweaks */ - - FT_ULong sph_in_func_flags; /* flags to indicate if in */ - /* special functions */ - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - /* We maintain two counters (in addition to the instruction counter) */ /* that act as loop detectors for LOOPCALL and jump opcodes with */ /* negative arguments. */ @@ -438,16 +401,10 @@ FT_BEGIN_HEADER extern const TT_GraphicsState tt_default_graphics_state; -#ifdef TT_USE_BYTECODE_INTERPRETER - FT_LOCAL( void ) - TT_Goto_CodeRange( TT_ExecContext exec, - FT_Int range, - FT_Long IP ); - FT_LOCAL( void ) TT_Set_CodeRange( TT_ExecContext exec, FT_Int range, - void* base, + FT_Byte* base, FT_Long length ); FT_LOCAL( void ) @@ -455,31 +412,21 @@ FT_BEGIN_HEADER FT_Int range ); - FT_LOCAL( FT_Error ) - Update_Max( FT_Memory memory, - FT_ULong* size, - FT_ULong multiplier, - void* _pbuff, - FT_ULong new_max ); -#endif /* TT_USE_BYTECODE_INTERPRETER */ - - /************************************************************************** * * @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. + * Create a `TT_ExecContext`. Note that there is now an execution + * context per `TT_Size` that is not shared among faces. * * @Input: - * face :: - * A handle to the source face object. + * driver :: + * A handle to the driver, used for memory allocation. * * @Return: - * A handle to the execution context. Initialized for `face'. + * A handle to a new empty execution context. * * @Note: * Only the glyph loader and debugger should call this function. @@ -489,7 +436,6 @@ FT_BEGIN_HEADER TT_New_Context( TT_Driver driver ); -#ifdef TT_USE_BYTECODE_INTERPRETER FT_LOCAL( void ) TT_Done_Context( TT_ExecContext exec ); @@ -500,11 +446,11 @@ FT_BEGIN_HEADER FT_LOCAL( void ) TT_Save_Context( TT_ExecContext exec, - TT_Size ins ); + TT_Size size ); FT_LOCAL( FT_Error ) - TT_Run_Context( TT_ExecContext exec ); -#endif /* TT_USE_BYTECODE_INTERPRETER */ + TT_Run_Context( TT_ExecContext exec, + TT_Size size ); /************************************************************************** @@ -530,7 +476,7 @@ FT_BEGIN_HEADER * invoked by the TrueType debugger. */ FT_EXPORT( FT_Error ) - TT_RunIns( TT_ExecContext exec ); + TT_RunIns( void* exec ); FT_END_HEADER diff --git a/src/thirdparty/freetype2/src/truetype/ttobjs.c b/src/thirdparty/freetype2/src/truetype/ttobjs.c index e4775a51e..fd0c0ad14 100644 --- a/src/thirdparty/freetype2/src/truetype/ttobjs.c +++ b/src/thirdparty/freetype2/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ * * Objects manager (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include FT_INTERNAL_SFNT_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include #include "ttgload.h" #include "ttpload.h" @@ -68,23 +67,13 @@ * A pointer to the target glyph zone. */ FT_LOCAL_DEF( void ) - tt_glyphzone_done( TT_GlyphZone zone ) + tt_glyphzone_done( FT_Memory memory, + TT_GlyphZone zone ) { - FT_Memory memory = zone->memory; + FT_FREE( zone->org ); - - 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; - } + zone->n_points = 0; + zone->n_contours = 0; } @@ -116,32 +105,57 @@ FT_LOCAL_DEF( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort maxContours, TT_GlyphZone zone ) { FT_Error error; + FT_Long size = 3 * maxPoints * sizeof ( FT_Vector ) + + maxContours * sizeof ( FT_UShort ) + + maxPoints * sizeof ( FT_Byte ); - FT_ZERO( 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 ) ) + if ( !FT_ALLOC( zone->org, size ) ) { - tt_glyphzone_done( zone ); - } - else - { - zone->max_points = maxPoints; - zone->max_contours = maxContours; + zone->n_points = maxPoints; + zone->n_contours = maxContours; + + zone->cur = zone->org + maxPoints; + zone->orus = zone->cur + maxPoints; + zone->contours = (FT_UShort*)( zone->orus + maxPoints ); + zone->tags = (FT_Byte*)( zone->contours + maxContours ); + + zone->first_point = 0; } return error; } -#endif /* TT_USE_BYTECODE_INTERPRETER */ + + + /* + * Fonts embedded in PDFs are made unique by prepending randomization + * prefixes to their names: as defined in Section 5.5.3, 'Font Subsets', + * of the PDF Reference, they consist of 6 uppercase letters followed by + * the `+` sign. For safety, we do not skip prefixes violating this rule. + */ + + static const FT_String* + tt_skip_pdffont_random_tag( const FT_String* name ) + { + if ( ft_isupper( name[0] ) && + ft_isupper( name[1] ) && + ft_isupper( name[2] ) && + ft_isupper( name[3] ) && + ft_isupper( name[4] ) && + ft_isupper( name[5] ) && + '+' == name[6] && + name[7] ) + { + FT_TRACE7(( "name without randomization tag: %s\n", name + 7 )); + return name + 7; + } + + return name; + } /* Compare the face with a list of well-known `tricky' fonts. */ @@ -152,7 +166,7 @@ { #define TRICK_NAMES_MAX_CHARACTERS 19 -#define TRICK_NAMES_COUNT 26 +#define TRICK_NAMES_COUNT 20 static const char trick_names[TRICK_NAMES_COUNT] [TRICK_NAMES_MAX_CHARACTERS + 1] = @@ -172,22 +186,28 @@ "DFGirl-W6-WIN-BF", /* dftt-h6.ttf; version 1.00, 1993 */ "DFGothic-EB", /* DynaLab Inc. 1992-1995 */ "DFGyoSho-Lt", /* DynaLab Inc. 1992-1995 */ - "DFHei-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFHei", /* DynaLab Inc. 1992-1995 [DFHei-Bd-WIN-HK-BF] */ + /* covers "DFHei-Md-HK-BF", maybe DynaLab Inc. */ + "DFHSGothic-W5", /* DynaLab Inc. 1992-1995 */ "DFHSMincho-W3", /* DynaLab Inc. 1992-1995 */ "DFHSMincho-W7", /* DynaLab Inc. 1992-1995 */ "DFKaiSho-SB", /* dfkaisb.ttf */ - "DFKaiShu", - "DFKaiShu-Md-HK-BF", /* maybe DynaLab Inc. */ + "DFKaiShu", /* covers "DFKaiShu-Md-HK-BF", maybe DynaLab Inc. */ "DFKai-SB", /* kaiu.ttf; version 3.00, 1998 [DFKaiShu-SB-Estd-BF] */ - "DFMing-Bd-HK-BF", /* maybe DynaLab Inc. */ + + "DFMing", /* DynaLab Inc. 1992-1995 [DFMing-Md-WIN-HK-BF] */ + /* covers "DFMing-Bd-HK-BF", maybe DynaLab Inc. */ + "DLC", /* dftt-m7.ttf; version 1.00, 1993 [DLCMingBold] */ /* dftt-f5.ttf; version 1.00, 1993 [DLCFongSung] */ - "DLCHayMedium", /* dftt-b5.ttf; version 1.00, 1993 */ - "DLCHayBold", /* dftt-b7.ttf; version 1.00, 1993 */ - "DLCKaiMedium", /* dftt-k5.ttf; version 1.00, 1992 */ - "DLCLiShu", /* dftt-l5.ttf; version 1.00, 1992 */ - "DLCRoundBold", /* dftt-r7.ttf; version 1.00, 1993 */ + /* covers following */ + /* "DLCHayMedium", dftt-b5.ttf; version 1.00, 1993 */ + /* "DLCHayBold", dftt-b7.ttf; version 1.00, 1993 */ + /* "DLCKaiMedium", dftt-k5.ttf; version 1.00, 1992 */ + /* "DLCLiShu", dftt-l5.ttf; version 1.00, 1992 */ + /* "DLCRoundBold", dftt-r7.ttf; version 1.00, 1993 */ + "HuaTianKaiTi?", /* htkt2.ttf */ "HuaTianSongTi?", /* htst3.ttf */ "Ming(for ISO10646)", /* hkscsiic.ttf; version 0.12, 2007 [Ming] */ @@ -200,10 +220,12 @@ }; int nn; + const FT_String* name_without_tag; + name_without_tag = tt_skip_pdffont_random_tag( name ); for ( nn = 0; nn < TRICK_NAMES_COUNT; nn++ ) - if ( ft_strstr( name, trick_names[nn] ) ) + if ( ft_strstr( name_without_tag, trick_names[nn] ) ) return TRUE; return FALSE; @@ -223,17 +245,20 @@ { FT_Error error; FT_UInt32 checksum = 0; - FT_UInt i; + FT_Byte* p; + FT_Int shift; if ( FT_FRAME_ENTER( length ) ) return 0; - for ( ; length > 3; length -= 4 ) - checksum += (FT_UInt32)FT_GET_ULONG(); + p = (FT_Byte*)stream->cursor; - for ( i = 3; length > 0; length--, i-- ) - checksum += (FT_UInt32)FT_GET_BYTE() << ( i * 8 ); + for ( ; length > 3; length -= 4 ) + checksum += FT_NEXT_ULONG( p ); + + for ( shift = 24; length > 0; length--, shift -=8 ) + checksum += (FT_UInt32)FT_NEXT_BYTE( p ) << shift; FT_FRAME_EXIT(); @@ -278,10 +303,11 @@ tt_check_trickyness_sfnt_ids( TT_Face face ) { #define TRICK_SFNT_IDS_PER_FACE 3 -#define TRICK_SFNT_IDS_NUM_FACES 29 +#define TRICK_SFNT_IDS_NUM_FACES 31 static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES] - [TRICK_SFNT_IDS_PER_FACE] = { + [TRICK_SFNT_IDS_PER_FACE] = + { #define TRICK_SFNT_ID_cvt 0 #define TRICK_SFNT_ID_fpgm 1 @@ -431,6 +457,16 @@ { 0x00170003UL, 0x00000060UL }, /* cvt */ { 0xDBB4306EUL, 0x000058AAUL }, /* fpgm */ { 0xD643482AUL, 0x00000035UL } /* prep */ + }, + { /* DFHei-Bd-WIN-HK-BF, issue #1087 */ + { 0x1269EB58UL, 0x00000350UL }, /* cvt */ + { 0x5CD5957AUL, 0x00006A4EUL }, /* fpgm */ + { 0xF758323AUL, 0x00000380UL } /* prep */ + }, + { /* DFMing-Md-WIN-HK-BF, issue #1087 */ + { 0x122FEB0BUL, 0x00000350UL }, /* cvt */ + { 0x7F10919AUL, 0x000070A9UL }, /* fpgm */ + { 0x7CD7E7B7UL, 0x0000025CUL } /* prep */ } }; @@ -441,8 +477,7 @@ int j, k; - FT_MEM_SET( num_matched_ids, 0, - sizeof ( int ) * TRICK_SFNT_IDS_NUM_FACES ); + FT_ARRAY_ZERO( num_matched_ids, TRICK_SFNT_IDS_NUM_FACES ); has_cvt = FALSE; has_fpgm = FALSE; has_prep = FALSE; @@ -511,17 +546,27 @@ /* For first, check the face name for quick check. */ if ( face->family_name && tt_check_trickyness_family( face->family_name ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its family name: %s\n", face->family_name )); return TRUE; + } /* Type42 fonts may lack `name' tables, we thus try to identify */ /* tricky fonts by checking the checksums of Type42-persistent */ /* sfnt tables (`cvt', `fpgm', and `prep'). */ if ( tt_check_trickyness_sfnt_ids( (TT_Face)face ) ) + { + FT_TRACE3(( "found as a tricky font" + " by its cvt/fpgm/prep table checksum\n" )); return TRUE; + } return FALSE; } +#endif /* TT_USE_BYTECODE_INTERPRETER */ + /* Check whether `.notdef' is the only glyph in the `loca' table. */ static FT_Bool @@ -530,7 +575,7 @@ FT_Bool result = FALSE; TT_Face face = (TT_Face)ttface; - FT_UInt asize; + FT_ULong asize; FT_ULong i; FT_ULong glyph_index = 0; FT_UInt count = 0; @@ -538,7 +583,7 @@ for( i = 0; i < face->num_locations; i++ ) { - tt_face_get_location( face, i, &asize ); + tt_face_get_location( ttface, i, &asize ); if ( asize > 0 ) { count += 1; @@ -667,14 +712,17 @@ if ( error ) goto Exit; +#ifdef TT_USE_BYTECODE_INTERPRETER if ( tt_check_trickyness( ttface ) ) ttface->face_flags |= FT_FACE_FLAG_TRICKY; +#endif error = tt_face_load_hdmx( face, stream ); if ( error ) goto Exit; - if ( FT_IS_SCALABLE( ttface ) ) + if ( FT_IS_SCALABLE( ttface ) || + FT_HAS_SBIX( ttface ) ) { #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( !ttface->internal->incremental_interface ) @@ -713,8 +761,8 @@ tt_check_single_notdef( ttface ) ) { FT_TRACE5(( "tt_face_init:" - " Only the `.notdef' glyph has an outline.\n" - " " + " Only the `.notdef' glyph has an outline.\n" )); + FT_TRACE5(( " " " Resetting scalable flag to FALSE.\n" )); ttface->face_flags &= ~FT_FACE_FLAG_SCALABLE; @@ -723,22 +771,17 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - { FT_UInt instance_index = (FT_UInt)face_index >> 16; - if ( FT_HAS_MULTIPLE_MASTERS( ttface ) && - instance_index > 0 ) + if ( instance_index && FT_HAS_MULTIPLE_MASTERS( ttface ) ) { - error = TT_Set_Named_Instance( face, instance_index ); + error = FT_Set_Named_Instance( ttface, instance_index ); if ( error ) goto Exit; - - tt_apply_mvar( face ); } } - #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ /* initialize standard glyph loading routines */ @@ -804,7 +847,7 @@ face->cvt_program_size = 0; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - tt_done_blend( face ); + tt_done_blend( ttface ); face->blend = NULL; #endif } @@ -830,75 +873,40 @@ * size :: * A handle to the size object. * - * pedantic :: - * Set if bytecode execution should be pedantic. - * * @Return: * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_fpgm( TT_Size size, - FT_Bool pedantic ) + tt_size_run_fpgm( TT_Size size ) { TT_Face face = (TT_Face)size->root.face; - TT_ExecContext exec; + TT_ExecContext exec = size->context; FT_Error error; - exec = size->context; - error = TT_Load_Context( exec, face, size ); if ( error ) return error; - exec->callTop = 0; - exec->top = 0; - - exec->period = 64; - exec->phase = 0; - exec->threshold = 0; - - exec->instruction_trap = FALSE; - exec->F_dot_P = 0x4000L; - - exec->pedantic_hinting = pedantic; - - { - FT_Size_Metrics* size_metrics = &exec->metrics; - TT_Size_Metrics* tt_metrics = &exec->tt_metrics; - - - size_metrics->x_ppem = 0; - size_metrics->y_ppem = 0; - size_metrics->x_scale = 0; - size_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, - (FT_Long)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 ) { - TT_Goto_CodeRange( exec, tt_coderange_font, 0 ); + /* allow font program execution */ + TT_Set_CodeRange( exec, + tt_coderange_font, + face->font_program, + (FT_Long)face->font_program_size ); + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; FT_TRACE4(( "Executing `fpgm' table.\n" )); - error = face->interpreter( exec ); -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE4(( " interpretation failed with error code 0x%x\n", - error )); -#endif + error = TT_Run_Context( exec, size ); + FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", + error )); } else error = FT_Err_Ok; @@ -924,212 +932,146 @@ * size :: * A handle to the size object. * - * pedantic :: - * Set if bytecode execution should be pedantic. - * * @Return: * FreeType error code. 0 means success. */ FT_LOCAL_DEF( FT_Error ) - tt_size_run_prep( TT_Size size, - FT_Bool pedantic ) + tt_size_run_prep( TT_Size size ) { TT_Face face = (TT_Face)size->root.face; - TT_ExecContext exec; + TT_ExecContext exec = size->context; FT_Error error; FT_UInt i; - /* unscaled CVT values are already stored in 26.6 format */ - FT_Fixed scale = size->ttmetrics.scale >> 6; + /* set default GS, twilight points, and storage */ + /* before CV program can modify them. */ + size->GS = tt_default_graphics_state; - /* Scale the cvt values to the new ppem. */ - /* By default, we use the y ppem value for scaling. */ - FT_TRACE6(( "CVT values:\n" )); - for ( i = 0; i < size->cvt_size; i++ ) - { - size->cvt[i] = FT_MulFix( face->cvt[i], scale ); - FT_TRACE6(( " %3d: %f (%f)\n", - i, face->cvt[i] / 64.0, size->cvt[i] / 64.0 )); - } - FT_TRACE6(( "\n" )); - - exec = size->context; + /* all twilight points are originally zero */ + FT_ARRAY_ZERO( size->twilight.org, size->twilight.n_points ); + FT_ARRAY_ZERO( size->twilight.cur, size->twilight.n_points ); error = TT_Load_Context( exec, face, size ); if ( error ) return error; - exec->callTop = 0; - exec->top = 0; + /* clear storage area */ + FT_ARRAY_ZERO( exec->storage, exec->storeSize ); - exec->instruction_trap = FALSE; - - exec->pedantic_hinting = pedantic; - - TT_Set_CodeRange( exec, - tt_coderange_cvt, - face->cvt_program, - (FT_Long)face->cvt_program_size ); + /* Scale the cvt values to the new ppem. */ + /* By default, we use the y ppem value for scaling. */ + FT_TRACE6(( "CVT values:\n" )); + for ( i = 0; i < exec->cvtSize; i++ ) + { + /* Unscaled CVT values are already stored in 26.6 format. */ + /* Note that this scaling operation is very sensitive to rounding; */ + /* the integer division by 64 must be applied to the first argument. */ + exec->cvt[i] = FT_MulFix( face->cvt[i] / 64, size->ttmetrics.scale ); + FT_TRACE6(( " %3u: %f (%f)\n", + i, (double)face->cvt[i] / 64, (double)exec->cvt[i] / 64 )); + } + FT_TRACE6(( "\n" )); TT_Clear_CodeRange( exec, tt_coderange_glyph ); if ( face->cvt_program_size > 0 ) { - TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + /* allow CV program execution */ + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + (FT_Long)face->cvt_program_size ); + + exec->pts.n_points = 0; + exec->pts.n_contours = 0; FT_TRACE4(( "Executing `prep' table.\n" )); - error = face->interpreter( exec ); -#ifdef FT_DEBUG_LEVEL_TRACE - if ( error ) - FT_TRACE4(( " interpretation failed with error code 0x%x\n", - error )); -#endif + error = TT_Run_Context( exec, size ); + FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", + error )); } else error = FT_Err_Ok; size->cvt_ready = error; - /* UNDOCUMENTED! The MS rasterizer doesn't allow the following */ - /* graphics state variables to be modified by the CVT program. */ - - exec->GS.dualVector.x = 0x4000; - exec->GS.dualVector.y = 0; - exec->GS.projVector.x = 0x4000; - exec->GS.projVector.y = 0x0; - exec->GS.freeVector.x = 0x4000; - exec->GS.freeVector.y = 0x0; - - exec->GS.rp0 = 0; - exec->GS.rp1 = 0; - exec->GS.rp2 = 0; - - exec->GS.gep0 = 1; - exec->GS.gep1 = 1; - exec->GS.gep2 = 1; - - exec->GS.loop = 1; - - /* save as default graphics state */ - size->GS = exec->GS; - - TT_Save_Context( exec, size ); + if ( !error ) + TT_Save_Context( exec, size ); return error; } static void - tt_size_done_bytecode( FT_Size ftsize ) + tt_size_done_bytecode( TT_Size size ) { - TT_Size size = (TT_Size)ftsize; - TT_Face face = (TT_Face)ftsize->face; - FT_Memory memory = face->root.memory; + FT_Memory memory = size->root.face->memory; + TT_ExecContext exec = size->context; - if ( size->context ) + + if ( exec ) { - TT_Done_Context( size->context ); + FT_FREE( exec->stack ); + FT_FREE( exec->FDefs ); + + TT_Done_Context( exec ); size->context = NULL; } - 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 = -1; - size->cvt_ready = -1; + tt_glyphzone_done( memory, &size->twilight ); } /* 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_LOCAL_DEF( FT_Error ) + tt_size_init_bytecode( TT_Size size, FT_Bool pedantic ) { FT_Error error; - TT_Size size = (TT_Size)ftsize; - TT_Face face = (TT_Face)ftsize->face; - FT_Memory memory = face->root.memory; + TT_Face face = (TT_Face)size->root.face; + FT_Memory memory = size->root.face->memory; FT_UShort n_twilight; TT_MaxProfile* maxp = &face->max_profile; + TT_ExecContext exec; - /* clean up bytecode related data */ - FT_FREE( size->function_defs ); - FT_FREE( size->instruction_defs ); - FT_FREE( size->cvt ); - FT_FREE( size->storage ); + exec = TT_New_Context( (TT_Driver)face->root.driver ); + if ( !exec ) + return FT_THROW( Could_Not_Find_Context ); - if ( size->context ) - TT_Done_Context( size->context ); - tt_glyphzone_done( &size->twilight ); + exec->pedantic_hinting = pedantic; - size->bytecode_ready = -1; - size->cvt_ready = -1; + exec->maxFDefs = maxp->maxFunctionDefs; + exec->maxIDefs = maxp->maxInstructionDefs; - size->context = TT_New_Context( (TT_Driver)face->root.driver ); - - 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 */ - { - TT_Size_Metrics* tt_metrics = &size->ttmetrics; - - - tt_metrics->rotated = FALSE; - tt_metrics->stretched = FALSE; - - /* Set default engine compensation. Value 3 is not described */ - /* in the OpenType specification (as of Mai 2019), but Greg */ - /* says that MS handles it the same as `gray'. */ - /* */ - /* The Apple specification says that the compensation for */ - /* `gray' is always zero. FreeType doesn't do any */ - /* compensation at all. */ - tt_metrics->compensations[0] = 0; /* gray */ - tt_metrics->compensations[1] = 0; /* black */ - tt_metrics->compensations[2] = 0; /* white */ - tt_metrics->compensations[3] = 0; /* the same as gray */ - } - - /* 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 ) ) + if ( FT_NEW_ARRAY( exec->FDefs, exec->maxFDefs + exec->maxIDefs ) ) goto Exit; - /* reserve twilight zone */ + exec->IDefs = exec->FDefs + exec->maxFDefs; + + exec->numFDefs = 0; + exec->numIDefs = 0; + + exec->maxFunc = 0; + exec->maxIns = 0; + + /* XXX: We reserve a little more elements on the stack to deal */ + /* with broken fonts like arialbs, courbs, timesbs, etc. */ + exec->stackSize = maxp->maxStackElements + 32; + exec->storeSize = maxp->maxStorage; + exec->cvtSize = face->cvt_size; + + if ( FT_NEW_ARRAY( exec->stack, + exec->stackSize + + (FT_Long)( exec->storeSize + exec->cvtSize ) ) ) + goto Exit; + + /* reserve twilight zone and set GS before fpgm is executed, */ + /* just in case, even though fpgm should not touch them */ n_twilight = maxp->maxTwilightPoints; /* there are 4 phantom points (do we need this?) */ @@ -1139,20 +1081,12 @@ if ( error ) goto Exit; - size->twilight.n_points = n_twilight; + size->GS = tt_default_graphics_state; + size->cvt_ready = -1; + size->context = exec; - 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; - } + size->ttmetrics.rotated = FALSE; + size->ttmetrics.stretched = FALSE; /* Fine, now run the font program! */ @@ -1162,62 +1096,16 @@ /* to be executed just once; calling it again is completely useless */ /* and might even lead to extremely slow behaviour if it is malformed */ /* (containing an infinite loop, for example). */ - error = tt_size_run_fpgm( size, pedantic ); + error = tt_size_run_fpgm( size ); return error; Exit: if ( error ) - tt_size_done_bytecode( ftsize ); + tt_size_done_bytecode( size ); return error; } - - FT_LOCAL_DEF( FT_Error ) - tt_size_ready_bytecode( TT_Size size, - FT_Bool pedantic ) - { - FT_Error error = FT_Err_Ok; - - - if ( size->bytecode_ready < 0 ) - error = tt_size_init_bytecode( (FT_Size)size, pedantic ); - else - error = size->bytecode_ready; - - if ( error ) - goto Exit; - - /* rescale CVT when needed */ - if ( size->cvt_ready < 0 ) - { - FT_UInt i; - - - /* 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, pedantic ); - } - else - error = size->cvt_ready; - - Exit: - return error; - } - #endif /* TT_USE_BYTECODE_INTERPRETER */ @@ -1245,11 +1133,9 @@ #ifdef TT_USE_BYTECODE_INTERPRETER size->bytecode_ready = -1; - size->cvt_ready = -1; #endif - size->ttmetrics.valid = FALSE; - size->strike_index = 0xFFFFFFFFUL; + size->strike_index = 0xFFFFFFFFUL; return error; } @@ -1270,58 +1156,37 @@ FT_LOCAL_DEF( void ) tt_size_done( FT_Size ttsize ) /* TT_Size */ { - TT_Size size = (TT_Size)ttsize; - - #ifdef TT_USE_BYTECODE_INTERPRETER - tt_size_done_bytecode( ttsize ); + tt_size_done_bytecode( (TT_Size)ttsize ); +#else + FT_UNUSED( ttsize ); #endif - - size->ttmetrics.valid = FALSE; } /************************************************************************** * * @Function: - * tt_size_reset + * tt_size_reset_height * * @Description: - * Reset a TrueType size when resolutions and character dimensions - * have been changed. + * Recompute a TrueType size's ascender, descender, and height + * when resolutions and character dimensions have been changed. + * Used for variation fonts as an iterator function. * * @Input: - * size :: - * A handle to the target size object. - * - * only_height :: - * Only recompute ascender, descender, and height; - * this flag is used for variation fonts where - * `tt_size_reset' is used as an iterator function. + * ft_size :: + * A handle to the target TT_Size object. This function will be called + * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This + * function must take `FT_Size` as a result. The passed `FT_Size` is + * expected to point to a `TT_Size`. */ - FT_LOCAL_DEF( FT_Error ) - tt_size_reset( TT_Size size, - FT_Bool only_height ) + FT_LOCAL_DEF( void ) + tt_size_reset_height( FT_Size ft_size ) { - TT_Face face; - FT_Size_Metrics* size_metrics; - - - face = (TT_Face)size->root.face; - - /* nothing to do for CFF2 */ - if ( face->is_cff2 ) - return FT_Err_Ok; - - size->ttmetrics.valid = FALSE; - - size_metrics = &size->hinted_metrics; - - /* copy the result from base layer */ - *size_metrics = size->root.metrics; - - if ( size_metrics->x_ppem < 1 || size_metrics->y_ppem < 1 ) - return FT_THROW( Invalid_PPem ); + TT_Size size = (TT_Size)ft_size; + TT_Face face = (TT_Face)ft_size->face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; /* This bit flag, if set, indicates that the ppems must be */ /* rounded to integers. Nearly all TrueType fonts have this bit */ @@ -1340,15 +1205,39 @@ FT_MulFix( face->root.height, size_metrics->y_scale ) ); } + } - size->ttmetrics.valid = TRUE; - if ( only_height ) - { - /* we must not recompute the scaling values here since */ - /* `tt_size_reset' was already called (with only_height = 0) */ - return FT_Err_Ok; - } + /************************************************************************** + * + * @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 = (TT_Face)size->root.face; + FT_Size_Metrics* size_metrics = &size->hinted_metrics; + + + /* invalidate the size object first */ + size->ttmetrics.ppem = 0; + + if ( size->root.metrics.x_ppem == 0 || size->root.metrics.y_ppem == 0 ) + return FT_THROW( Invalid_PPem ); + + /* copy the result from base layer */ + *size_metrics = size->root.metrics; + + tt_size_reset_height( (FT_Size)size ); if ( face->header.Flags & 8 ) { @@ -1382,6 +1271,8 @@ size->ttmetrics.y_ratio = 0x10000L; } + size->widthp = tt_face_get_device_metrics( face, size_metrics->x_ppem, 0 ); + size->metrics = size_metrics; #ifdef TT_USE_BYTECODE_INTERPRETER @@ -1416,9 +1307,6 @@ TT_Driver driver = (TT_Driver)ttdriver; driver->interpreter_version = TT_INTERPRETER_VERSION_35; -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - driver->interpreter_version = TT_INTERPRETER_VERSION_38; -#endif #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL driver->interpreter_version = TT_INTERPRETER_VERSION_40; #endif diff --git a/src/thirdparty/freetype2/src/truetype/ttobjs.h b/src/thirdparty/freetype2/src/truetype/ttobjs.h index 9fc654d5d..28d6c7d85 100644 --- a/src/thirdparty/freetype2/src/truetype/ttobjs.h +++ b/src/thirdparty/freetype2/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ * * Objects manager (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define TTOBJS_H_ -#include -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include +#include FT_BEGIN_HEADER @@ -54,6 +53,8 @@ FT_BEGIN_HEADER typedef FT_GlyphSlot TT_GlyphSlot; +#ifdef TT_USE_BYTECODE_INTERPRETER + /************************************************************************** * * @Struct: @@ -68,21 +69,27 @@ FT_BEGIN_HEADER FT_UShort rp1; FT_UShort rp2; + FT_UShort gep0; + FT_UShort gep1; + FT_UShort gep2; + FT_UnitVector dualVector; FT_UnitVector projVector; FT_UnitVector freeVector; FT_Long loop; - FT_F26Dot6 minimum_distance; FT_Int round_state; + FT_F26Dot6 compensation[4]; /* device-specific compensations */ - FT_Bool auto_flip; + /* default values below can be modified by 'fpgm' and 'prep' */ + FT_F26Dot6 minimum_distance; FT_F26Dot6 control_value_cutin; FT_F26Dot6 single_width_cutin; FT_F26Dot6 single_width_value; FT_UShort delta_base; FT_UShort delta_shift; + FT_Bool auto_flip; FT_Byte instruct_control; /* According to Greg Hitchcock from Microsoft, the `scan_control' */ /* variable as documented in the TrueType specification is a 32-bit */ @@ -91,97 +98,23 @@ FT_BEGIN_HEADER 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 ); + tt_glyphzone_done( FT_Memory memory, + TT_GlyphZone zone ); FT_LOCAL( FT_Error ) tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, - FT_Short maxContours, + FT_UShort 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_Long 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_Long end; /* where does it end? */ - FT_UInt opc; /* function #, or instruction code */ - FT_Bool active; /* is it active? */ - FT_Bool inline_delta; /* is function that defines inline delta? */ - FT_ULong sph_fdef_flags; /* flags to identify special functions */ - - } 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; - - /************************************************************************** * * A note regarding non-squared pixels: @@ -254,13 +187,9 @@ FT_BEGIN_HEADER 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_UShort ppem; /* maximum ppem size */ FT_Bool rotated; /* `is the glyph rotated?'-flag */ FT_Bool stretched; /* `is the glyph stretched?'-flag */ @@ -283,33 +212,16 @@ FT_BEGIN_HEADER TT_Size_Metrics ttmetrics; + FT_Byte* widthp; /* glyph widths from the hdmx table */ + FT_ULong strike_index; /* 0xFFFFFFFF to indicate invalid */ #ifdef TT_USE_BYTECODE_INTERPRETER FT_Long point_size; /* for the `MPS' bytecode instruction */ - 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 */ TT_ExecContext context; @@ -376,22 +288,22 @@ FT_BEGIN_HEADER #ifdef TT_USE_BYTECODE_INTERPRETER FT_LOCAL( FT_Error ) - tt_size_run_fpgm( TT_Size size, - FT_Bool pedantic ); + tt_size_run_fpgm( TT_Size size ); FT_LOCAL( FT_Error ) - tt_size_run_prep( TT_Size size, - FT_Bool pedantic ); + tt_size_run_prep( TT_Size size ); FT_LOCAL( FT_Error ) - tt_size_ready_bytecode( TT_Size size, - FT_Bool pedantic ); + tt_size_init_bytecode( TT_Size size, + FT_Bool pedantic ); #endif /* TT_USE_BYTECODE_INTERPRETER */ + FT_LOCAL( void ) + tt_size_reset_height( FT_Size size ); + FT_LOCAL( FT_Error ) - tt_size_reset( TT_Size size, - FT_Bool only_height ); + tt_size_reset( TT_Size size ); /************************************************************************** diff --git a/src/thirdparty/freetype2/src/truetype/ttpload.c b/src/thirdparty/freetype2/src/truetype/ttpload.c index bc954c2db..827454d85 100644 --- a/src/thirdparty/freetype2/src/truetype/ttpload.c +++ b/src/thirdparty/freetype2/src/truetype/ttpload.c @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_OBJECTS_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H +#include +#include +#include +#include #include "ttpload.h" @@ -99,36 +98,23 @@ goto Exit; } - if ( face->header.Index_To_Loc_Format != 0 ) - { - shift = 2; + shift = face->header.Index_To_Loc_Format != 0 ? 2 : 1; - if ( table_len >= 0x40000L ) - { - FT_TRACE2(( "table too large\n" )); - table_len = 0x3FFFFL; - } - face->num_locations = table_len >> shift; - } - else + if ( table_len > 0x10000UL << shift ) { - shift = 1; - - if ( table_len >= 0x20000L ) - { - FT_TRACE2(( "table too large\n" )); - table_len = 0x1FFFFL; - } - face->num_locations = table_len >> shift; + FT_TRACE2(( "table too large\n" )); + table_len = 0x10000UL << shift; } + face->num_locations = table_len >> shift; + if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 ) { - FT_TRACE2(( "glyph count mismatch! loca: %d, maxp: %d\n", + FT_TRACE2(( "glyph count mismatch! loca: %lu, maxp: %ld\n", face->num_locations - 1, face->root.num_glyphs )); /* we only handle the case where `maxp' gives a larger value */ - if ( face->num_locations <= (FT_ULong)face->root.num_glyphs ) + if ( face->num_locations < (FT_ULong)face->root.num_glyphs + 1 ) { FT_ULong new_loca_len = ( (FT_ULong)face->root.num_glyphs + 1 ) << shift; @@ -165,7 +151,7 @@ face->num_locations = (FT_ULong)face->root.num_glyphs + 1; table_len = new_loca_len; - FT_TRACE2(( "adjusting num_locations to %d\n", + FT_TRACE2(( "adjusting num_locations to %lu\n", face->num_locations )); } else @@ -173,7 +159,7 @@ face->root.num_glyphs = face->num_locations ? (FT_Long)face->num_locations - 1 : 0; - FT_TRACE2(( "adjusting num_glyphs to %d\n", + FT_TRACE2(( "adjusting num_glyphs to %ld\n", face->root.num_glyphs )); } } @@ -194,10 +180,11 @@ FT_LOCAL_DEF( FT_ULong ) - tt_face_get_location( TT_Face face, - FT_UInt gindex, - FT_UInt *asize ) + tt_face_get_location( FT_Face face, /* TT_Face */ + FT_UInt gindex, + FT_ULong *asize ) { + TT_Face ttface = (TT_Face)face; FT_ULong pos1, pos2; FT_Byte* p; FT_Byte* p_limit; @@ -205,12 +192,12 @@ pos1 = pos2 = 0; - if ( gindex < face->num_locations ) + if ( gindex < ttface->num_locations ) { - if ( face->header.Index_To_Loc_Format != 0 ) + if ( ttface->header.Index_To_Loc_Format != 0 ) { - p = face->glyph_locations + gindex * 4; - p_limit = face->glyph_locations + face->num_locations * 4; + p = ttface->glyph_locations + gindex * 4; + p_limit = ttface->glyph_locations + ttface->num_locations * 4; pos1 = FT_NEXT_ULONG( p ); pos2 = pos1; @@ -220,8 +207,8 @@ } else { - p = face->glyph_locations + gindex * 2; - p_limit = face->glyph_locations + face->num_locations * 2; + p = ttface->glyph_locations + gindex * 2; + p_limit = ttface->glyph_locations + ttface->num_locations * 2; pos1 = FT_NEXT_USHORT( p ); pos2 = pos1; @@ -235,36 +222,39 @@ } /* Check broken location data. */ - if ( pos1 > face->glyf_len ) + if ( pos1 > ttface->glyf_len ) { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %ld,\n" - " " + " too large offset (0x%08lx) found for glyph index %u,\n", + pos1, gindex )); + FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", - pos1, gindex, face->glyf_len )); + ttface->glyf_len )); *asize = 0; return 0; } - if ( pos2 > face->glyf_len ) + if ( pos2 > ttface->glyf_len ) { /* We try to sanitize the last `loca' entry. */ - if ( gindex == face->num_locations - 2 ) + if ( gindex == ttface->num_locations - 2 ) { FT_TRACE1(( "tt_face_get_location:" - " too large size (%ld bytes) found for glyph index %ld,\n" - " " - " truncating at the end of `glyf' table to %ld bytes\n", - pos2 - pos1, gindex, face->glyf_len - pos1 )); - pos2 = face->glyf_len; + " too large size (%lu bytes) found for glyph index %u,\n", + pos2 - pos1, gindex )); + FT_TRACE1(( " " + " truncating at the end of `glyf' table to %lu bytes\n", + ttface->glyf_len - pos1 )); + pos2 = ttface->glyf_len; } else { FT_TRACE1(( "tt_face_get_location:" - " too large offset (0x%08lx) found for glyph index %ld,\n" - " " + " too large offset (0x%08lx) found for glyph index %u,\n", + pos2, gindex + 1 )); + FT_TRACE1(( " " " exceeding the end of `glyf' table (0x%08lx)\n", - pos2, gindex + 1, face->glyf_len )); + ttface->glyf_len )); *asize = 0; return 0; } @@ -279,9 +269,9 @@ /* We get (intentionally) a wrong, non-zero result in case the */ /* `glyf' table is missing. */ if ( pos2 >= pos1 ) - *asize = (FT_UInt)( pos2 - pos1 ); + *asize = (FT_ULong)( pos2 - pos1 ); else - *asize = (FT_UInt)( face->glyf_len - pos1 ); + *asize = (FT_ULong)( ttface->glyf_len - pos1 ); return pos1; } @@ -345,7 +335,7 @@ face->cvt_size = table_len / 2; - if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) ) + if ( FT_QNEW_ARRAY( face->cvt, face->cvt_size ) ) goto Exit; if ( FT_FRAME_ENTER( face->cvt_size * 2L ) ) @@ -429,7 +419,7 @@ if ( FT_FRAME_EXTRACT( table_len, face->font_program ) ) goto Exit; - FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size )); + FT_TRACE2(( "loaded, %12lu bytes\n", face->font_program_size )); } Exit: @@ -492,7 +482,7 @@ if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) ) goto Exit; - FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size )); + FT_TRACE2(( "loaded, %12lu bytes\n", face->cvt_program_size )); } Exit: @@ -509,6 +499,14 @@ } + FT_COMPARE_DEF( int ) + compare_ppem( const void* a, + const void* b ) + { + return **(FT_Byte**)a - **(FT_Byte**)b; + } + + /************************************************************************** * * @Function: @@ -558,12 +556,6 @@ 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, thus */ - /* explaining why `record_size' is a long (which we read as */ - /* unsigned long for convenience). In practice, two bytes are */ - /* 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 */ @@ -572,32 +564,46 @@ if ( record_size >= 0xFFFF0000UL ) record_size &= 0xFFFFU; + FT_TRACE2(( "Hdmx " )); + /* The limit for `num_records' is a heuristic value. */ - if ( num_records > 255 || - ( num_records > 0 && - ( record_size > 0x10001L || - record_size < 4 ) ) ) + if ( num_records > 255 || num_records == 0 ) { - error = FT_THROW( Invalid_File_Format ); + FT_TRACE2(( "with unreasonable %u records rejected\n", num_records )); goto Fail; } - if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) ) + /* Out-of-spec tables are rejected. The record size must be */ + /* equal to the number of glyphs + 2 + 32-bit padding. */ + if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) ) + { + FT_TRACE2(( "with record size off by %ld bytes rejected\n", + (FT_Long)record_size - + ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) )); + goto Fail; + } + + if ( FT_QNEW_ARRAY( face->hdmx_records, 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_records[nn] = p; + p += record_size; } + /* The records must be already sorted by ppem but it does not */ + /* hurt to make sure so that the binary search works later. */ + ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem ); + face->hdmx_record_count = nn; face->hdmx_table_size = table_size; face->hdmx_record_size = record_size; + FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size )); + Exit: return error; @@ -615,7 +621,7 @@ FT_Memory memory = stream->memory; - FT_FREE( face->hdmx_record_sizes ); + FT_FREE( face->hdmx_records ); FT_FRAME_RELEASE( face->hdmx_table ); } @@ -623,27 +629,34 @@ /************************************************************************** * * Return the advance width table for a given pixel size if it is found - * in the font's `hdmx' table (if any). + * in the font's `hdmx' table (if any). The records must be sorted for + * the binary search to work properly. */ 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; + FT_UInt min = 0; + FT_UInt max = face->hdmx_record_count; + FT_UInt mid; + FT_Byte* result = NULL; - for ( nn = 0; nn < face->hdmx_record_count; nn++ ) - if ( face->hdmx_record_sizes[nn] == ppem ) + while ( min < max ) + { + mid = ( min + max ) >> 1; + + if ( face->hdmx_records[mid][0] > ppem ) + max = mid; + else if ( face->hdmx_records[mid][0] < ppem ) + min = mid + 1; + else { - gindex += 2; - if ( gindex < record_size ) - result = record + nn * record_size + gindex; + result = face->hdmx_records[mid] + 2 + gindex; break; } + } return result; } diff --git a/src/thirdparty/freetype2/src/truetype/ttpload.h b/src/thirdparty/freetype2/src/truetype/ttpload.h index 022750e32..bb4d3c9cc 100644 --- a/src/thirdparty/freetype2/src/truetype/ttpload.h +++ b/src/thirdparty/freetype2/src/truetype/ttpload.h @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define TTPLOAD_H_ -#include -#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_BEGIN_HEADER @@ -32,9 +31,9 @@ FT_BEGIN_HEADER FT_Stream stream ); FT_LOCAL( FT_ULong ) - tt_face_get_location( TT_Face face, - FT_UInt gindex, - FT_UInt *asize ); + tt_face_get_location( FT_Face face, + FT_UInt gindex, + FT_ULong *asize ); FT_LOCAL( void ) tt_face_done_loca( TT_Face face ); diff --git a/src/thirdparty/freetype2/src/truetype/ttsubpix.c b/src/thirdparty/freetype2/src/truetype/ttsubpix.c deleted file mode 100644 index 23a2e5b44..000000000 --- a/src/thirdparty/freetype2/src/truetype/ttsubpix.c +++ /dev/null @@ -1,1014 +0,0 @@ -/**************************************************************************** - * - * ttsubpix.c - * - * TrueType Subpixel Hinting. - * - * Copyright (C) 2010-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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_TRUETYPE_TAGS_H -#include FT_OUTLINE_H -#include FT_DRIVER_H - -#include "ttsubpix.h" - - -#if defined( TT_USE_BYTECODE_INTERPRETER ) && \ - defined( TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY ) - - /************************************************************************** - * - * These rules affect how the TT Interpreter does hinting, with the - * goal of doing subpixel hinting by (in general) ignoring x moves. - * Some of these rules are fixes that go above and beyond the - * stated techniques in the MS whitepaper on Cleartype, due to - * artifacts in many glyphs. So, these rules make some glyphs render - * better than they do in the MS rasterizer. - * - * "" string or 0 int/char indicates to apply to all glyphs. - * "-" used as dummy placeholders, but any non-matching string works. - * - * Some of this could arguably be implemented in fontconfig, however: - * - * - Fontconfig can't set things on a glyph-by-glyph basis. - * - The tweaks that happen here are very low-level, from an average - * user's point of view and are best implemented in the hinter. - * - * The goal is to make the subpixel hinting techniques as generalized - * as possible across all fonts to prevent the need for extra rules such - * as these. - * - * The rule structure is designed so that entirely new rules can easily - * be added when a new compatibility feature is discovered. - * - * The rule structures could also use some enhancement to handle ranges. - * - * ****************** WORK IN PROGRESS ******************* - */ - - /* These are `classes' of fonts that can be grouped together and used in */ - /* rules below. A blank entry "" is required at the end of these! */ -#define FAMILY_CLASS_RULES_SIZE 7 - - static const SPH_Font_Class FAMILY_CLASS_Rules - [FAMILY_CLASS_RULES_SIZE] = - { - { "MS Legacy Fonts", - { "Aharoni", - "Andale Mono", - "Andalus", - "Angsana New", - "AngsanaUPC", - "Arabic Transparent", - "Arial Black", - "Arial Narrow", - "Arial Unicode MS", - "Arial", - "Batang", - "Browallia New", - "BrowalliaUPC", - "Comic Sans MS", - "Cordia New", - "CordiaUPC", - "Courier New", - "DFKai-SB", - "David Transparent", - "David", - "DilleniaUPC", - "Estrangelo Edessa", - "EucrosiaUPC", - "FangSong_GB2312", - "Fixed Miriam Transparent", - "FrankRuehl", - "Franklin Gothic Medium", - "FreesiaUPC", - "Garamond", - "Gautami", - "Georgia", - "Gulim", - "Impact", - "IrisUPC", - "JasmineUPC", - "KaiTi_GB2312", - "KodchiangUPC", - "Latha", - "Levenim MT", - "LilyUPC", - "Lucida Console", - "Lucida Sans Unicode", - "MS Gothic", - "MS Mincho", - "MV Boli", - "Mangal", - "Marlett", - "Microsoft Sans Serif", - "Mingliu", - "Miriam Fixed", - "Miriam Transparent", - "Miriam", - "Narkisim", - "Palatino Linotype", - "Raavi", - "Rod Transparent", - "Rod", - "Shruti", - "SimHei", - "Simplified Arabic Fixed", - "Simplified Arabic", - "Simsun", - "Sylfaen", - "Symbol", - "Tahoma", - "Times New Roman", - "Traditional Arabic", - "Trebuchet MS", - "Tunga", - "Verdana", - "Webdings", - "Wingdings", - "", - }, - }, - { "Core MS Legacy Fonts", - { "Arial Black", - "Arial Narrow", - "Arial Unicode MS", - "Arial", - "Comic Sans MS", - "Courier New", - "Garamond", - "Georgia", - "Impact", - "Lucida Console", - "Lucida Sans Unicode", - "Microsoft Sans Serif", - "Palatino Linotype", - "Tahoma", - "Times New Roman", - "Trebuchet MS", - "Verdana", - "", - }, - }, - { "Apple Legacy Fonts", - { "Geneva", - "Times", - "Monaco", - "Century", - "Chalkboard", - "Lobster", - "Century Gothic", - "Optima", - "Lucida Grande", - "Gill Sans", - "Baskerville", - "Helvetica", - "Helvetica Neue", - "", - }, - }, - { "Legacy Sans Fonts", - { "Andale Mono", - "Arial Unicode MS", - "Arial", - "Century Gothic", - "Comic Sans MS", - "Franklin Gothic Medium", - "Geneva", - "Lucida Console", - "Lucida Grande", - "Lucida Sans Unicode", - "Lucida Sans Typewriter", - "Microsoft Sans Serif", - "Monaco", - "Tahoma", - "Trebuchet MS", - "Verdana", - "", - }, - }, - - { "Misc Legacy Fonts", - { "Dark Courier", "", }, }, - { "Verdana Clones", - { "DejaVu Sans", - "Bitstream Vera Sans", "", }, }, - { "Verdana and Clones", - { "DejaVu Sans", - "Bitstream Vera Sans", - "Verdana", "", }, }, - }; - - - /* Define this to force natural (i.e. not bitmap-compatible) widths. */ - /* The default leans strongly towards natural widths except for a few */ - /* legacy fonts where a selective combination produces nicer results. */ -/* #define FORCE_NATURAL_WIDTHS */ - - - /* Define `classes' of styles that can be grouped together and used in */ - /* rules below. A blank entry "" is required at the end of these! */ -#define STYLE_CLASS_RULES_SIZE 5 - - static const SPH_Font_Class STYLE_CLASS_Rules - [STYLE_CLASS_RULES_SIZE] = - { - { "Regular Class", - { "Regular", - "Book", - "Medium", - "Roman", - "Normal", - "", - }, - }, - { "Regular/Italic Class", - { "Regular", - "Book", - "Medium", - "Italic", - "Oblique", - "Roman", - "Normal", - "", - }, - }, - { "Bold/BoldItalic Class", - { "Bold", - "Bold Italic", - "Black", - "", - }, - }, - { "Bold/Italic/BoldItalic Class", - { "Bold", - "Bold Italic", - "Black", - "Italic", - "Oblique", - "", - }, - }, - { "Regular/Bold Class", - { "Regular", - "Book", - "Medium", - "Normal", - "Roman", - "Bold", - "Black", - "", - }, - }, - }; - - - /* Force special legacy fixes for fonts. */ -#define COMPATIBILITY_MODE_RULES_SIZE 1 - - static const SPH_TweakRule COMPATIBILITY_MODE_Rules - [COMPATIBILITY_MODE_RULES_SIZE] = - { - { "Verdana Clones", 0, "", 0 }, - }; - - - /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */ -#define PIXEL_HINTING_RULES_SIZE 2 - - static const SPH_TweakRule PIXEL_HINTING_Rules - [PIXEL_HINTING_RULES_SIZE] = - { - /* these characters are almost always safe */ - { "Courier New", 12, "Italic", 'z' }, - { "Courier New", 11, "Italic", 'z' }, - }; - - - /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */ -#define DO_SHPIX_RULES_SIZE 1 - - static const SPH_TweakRule DO_SHPIX_Rules - [DO_SHPIX_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Skip Y moves that start with a point that is not on a Y pixel */ - /* boundary and don't move that point to a Y pixel boundary. */ -#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 4 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules - [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] = - { - /* fix vwxyz thinness*/ - { "Consolas", 0, "", 0 }, - /* Fix thin middle stems */ - { "Core MS Legacy Fonts", 0, "Regular", 0 }, - /* Cyrillic small letter I */ - { "Legacy Sans Fonts", 0, "", 0 }, - /* Fix artifacts with some Regular & Bold */ - { "Verdana Clones", 0, "", 0 }, - }; - - -#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions - [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - /* Fixes < and > */ - { "Courier New", 0, "Regular", 0 }, - }; - - - /* Skip Y moves that start with a point that is not on a Y pixel */ - /* boundary and don't move that point to a Y pixel boundary. */ -#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2 - - static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules - [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] = - { - /* Maintain thickness of diagonal in 'N' */ - { "Times New Roman", 0, "Regular/Bold Class", 'N' }, - { "Georgia", 0, "Regular/Bold Class", 'N' }, - }; - - - /* Skip Y moves that move a point off a Y pixel boundary. */ -#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1 - - static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules - [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - -#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions - [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Round moves that don't move a point to a Y pixel boundary. */ -#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2 - - static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules - [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] = - { - /* Droid font instructions don't snap Y to pixels */ - { "Droid Sans", 0, "Regular/Italic Class", 0 }, - { "Droid Sans Mono", 0, "", 0 }, - }; - - -#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1 - - static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions - [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Allow a Direct_Move along X freedom vector if matched. */ -#define ALLOW_X_DMOVE_RULES_SIZE 1 - - static const SPH_TweakRule ALLOW_X_DMOVE_Rules - [ALLOW_X_DMOVE_RULES_SIZE] = - { - /* Fixes vanishing diagonal in 4 */ - { "Verdana", 0, "Regular", '4' }, - }; - - - /* Return MS rasterizer version 35 if matched. */ -#define RASTERIZER_35_RULES_SIZE 8 - - static const SPH_TweakRule RASTERIZER_35_Rules - [RASTERIZER_35_RULES_SIZE] = - { - /* This seems to be the only way to make these look good */ - { "Times New Roman", 0, "Regular", 'i' }, - { "Times New Roman", 0, "Regular", 'j' }, - { "Times New Roman", 0, "Regular", 'm' }, - { "Times New Roman", 0, "Regular", 'r' }, - { "Times New Roman", 0, "Regular", 'a' }, - { "Times New Roman", 0, "Regular", 'n' }, - { "Times New Roman", 0, "Regular", 'p' }, - { "Times", 0, "", 0 }, - }; - - - /* Don't round to the subpixel grid. Round to pixel grid. */ -#define NORMAL_ROUND_RULES_SIZE 1 - - static const SPH_TweakRule NORMAL_ROUND_Rules - [NORMAL_ROUND_RULES_SIZE] = - { - /* Fix serif thickness for certain ppems */ - /* Can probably be generalized somehow */ - { "Courier New", 0, "", 0 }, - }; - - - /* Skip IUP instructions if matched. */ -#define SKIP_IUP_RULES_SIZE 1 - - static const SPH_TweakRule SKIP_IUP_Rules - [SKIP_IUP_RULES_SIZE] = - { - { "Arial", 13, "Regular", 'a' }, - }; - - - /* Skip MIAP Twilight hack if matched. */ -#define MIAP_HACK_RULES_SIZE 1 - - static const SPH_TweakRule MIAP_HACK_Rules - [MIAP_HACK_RULES_SIZE] = - { - { "Geneva", 12, "", 0 }, - }; - - - /* Skip DELTAP instructions if matched. */ -#define ALWAYS_SKIP_DELTAP_RULES_SIZE 23 - - static const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules - [ALWAYS_SKIP_DELTAP_RULES_SIZE] = - { - { "Georgia", 0, "Regular", 'k' }, - /* fix various problems with e in different versions */ - { "Trebuchet MS", 14, "Regular", 'e' }, - { "Trebuchet MS", 13, "Regular", 'e' }, - { "Trebuchet MS", 15, "Regular", 'e' }, - { "Trebuchet MS", 0, "Italic", 'v' }, - { "Trebuchet MS", 0, "Italic", 'w' }, - { "Trebuchet MS", 0, "Regular", 'Y' }, - { "Arial", 11, "Regular", 's' }, - /* prevent problems with '3' and others */ - { "Verdana", 10, "Regular", 0 }, - { "Verdana", 9, "Regular", 0 }, - /* Cyrillic small letter short I */ - { "Legacy Sans Fonts", 0, "", 0x438 }, - { "Legacy Sans Fonts", 0, "", 0x439 }, - { "Arial", 10, "Regular", '6' }, - { "Arial", 0, "Bold/BoldItalic Class", 'a' }, - /* Make horizontal stems consistent with the rest */ - { "Arial", 24, "Bold", 'a' }, - { "Arial", 25, "Bold", 'a' }, - { "Arial", 24, "Bold", 's' }, - { "Arial", 25, "Bold", 's' }, - { "Arial", 34, "Bold", 's' }, - { "Arial", 35, "Bold", 's' }, - { "Arial", 36, "Bold", 's' }, - { "Arial", 25, "Regular", 's' }, - { "Arial", 26, "Regular", 's' }, - }; - - - /* Always do DELTAP instructions if matched. */ -#define ALWAYS_DO_DELTAP_RULES_SIZE 1 - - static const SPH_TweakRule ALWAYS_DO_DELTAP_Rules - [ALWAYS_DO_DELTAP_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Don't allow ALIGNRP after IUP. */ -#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules - [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] = - { - /* Prevent creation of dents in outline */ - { "-", 0, "", 0 }, - }; - - - /* Don't allow DELTAP after IUP. */ -#define NO_DELTAP_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules - [NO_DELTAP_AFTER_IUP_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - - /* Don't allow CALL after IUP. */ -#define NO_CALL_AFTER_IUP_RULES_SIZE 1 - - static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules - [NO_CALL_AFTER_IUP_RULES_SIZE] = - { - /* Prevent creation of dents in outline */ - { "-", 0, "", 0 }, - }; - - - /* De-embolden these glyphs slightly. */ -#define DEEMBOLDEN_RULES_SIZE 9 - - static const SPH_TweakRule DEEMBOLDEN_Rules - [DEEMBOLDEN_RULES_SIZE] = - { - { "Courier New", 0, "Bold", 'A' }, - { "Courier New", 0, "Bold", 'W' }, - { "Courier New", 0, "Bold", 'w' }, - { "Courier New", 0, "Bold", 'M' }, - { "Courier New", 0, "Bold", 'X' }, - { "Courier New", 0, "Bold", 'K' }, - { "Courier New", 0, "Bold", 'x' }, - { "Courier New", 0, "Bold", 'z' }, - { "Courier New", 0, "Bold", 'v' }, - }; - - - /* Embolden these glyphs slightly. */ -#define EMBOLDEN_RULES_SIZE 2 - - static const SPH_TweakRule EMBOLDEN_Rules - [EMBOLDEN_RULES_SIZE] = - { - { "Courier New", 0, "Regular", 0 }, - { "Courier New", 0, "Italic", 0 }, - }; - - - /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */ - /* similar to Windows XP. */ -#define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12 - - static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules - [TIMES_NEW_ROMAN_HACK_RULES_SIZE] = - { - { "Times New Roman", 16, "Italic", '2' }, - { "Times New Roman", 16, "Italic", '5' }, - { "Times New Roman", 16, "Italic", '7' }, - { "Times New Roman", 16, "Regular", '2' }, - { "Times New Roman", 16, "Regular", '5' }, - { "Times New Roman", 16, "Regular", '7' }, - { "Times New Roman", 17, "Italic", '2' }, - { "Times New Roman", 17, "Italic", '5' }, - { "Times New Roman", 17, "Italic", '7' }, - { "Times New Roman", 17, "Regular", '2' }, - { "Times New Roman", 17, "Regular", '5' }, - { "Times New Roman", 17, "Regular", '7' }, - }; - - - /* This fudges distance on 2 to get rid of the vanishing stem issue. */ - /* A real solution to this is certainly welcome. */ -#define COURIER_NEW_2_HACK_RULES_SIZE 15 - - static const SPH_TweakRule COURIER_NEW_2_HACK_Rules - [COURIER_NEW_2_HACK_RULES_SIZE] = - { - { "Courier New", 10, "Regular", '2' }, - { "Courier New", 11, "Regular", '2' }, - { "Courier New", 12, "Regular", '2' }, - { "Courier New", 13, "Regular", '2' }, - { "Courier New", 14, "Regular", '2' }, - { "Courier New", 15, "Regular", '2' }, - { "Courier New", 16, "Regular", '2' }, - { "Courier New", 17, "Regular", '2' }, - { "Courier New", 18, "Regular", '2' }, - { "Courier New", 19, "Regular", '2' }, - { "Courier New", 20, "Regular", '2' }, - { "Courier New", 21, "Regular", '2' }, - { "Courier New", 22, "Regular", '2' }, - { "Courier New", 23, "Regular", '2' }, - { "Courier New", 24, "Regular", '2' }, - }; - - -#ifndef FORCE_NATURAL_WIDTHS - - /* Use compatible widths with these glyphs. Compatible widths is always */ - /* on when doing B/W TrueType instructing, but is used selectively here, */ - /* typically on glyphs with 3 or more vertical stems. */ -#define COMPATIBLE_WIDTHS_RULES_SIZE 38 - - static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules - [COMPATIBLE_WIDTHS_RULES_SIZE] = - { - { "Arial Unicode MS", 12, "Regular Class", 'm' }, - { "Arial Unicode MS", 14, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 10, "Regular Class", 0x448 }, - { "Arial", 11, "Regular Class", 'm' }, - { "Arial", 12, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 12, "Regular Class", 0x448 }, - { "Arial", 13, "Regular Class", 0x448 }, - { "Arial", 14, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Arial", 14, "Regular Class", 0x448 }, - { "Arial", 15, "Regular Class", 0x448 }, - { "Arial", 17, "Regular Class", 'm' }, - { "DejaVu Sans", 15, "Regular Class", 0 }, - { "Microsoft Sans Serif", 11, "Regular Class", 0 }, - { "Microsoft Sans Serif", 12, "Regular Class", 0 }, - { "Segoe UI", 11, "Regular Class", 0 }, - { "Monaco", 0, "Regular Class", 0 }, - { "Segoe UI", 12, "Regular Class", 'm' }, - { "Segoe UI", 14, "Regular Class", 'm' }, - { "Tahoma", 11, "Regular Class", 0 }, - { "Times New Roman", 16, "Regular Class", 'c' }, - { "Times New Roman", 16, "Regular Class", 'm' }, - { "Times New Roman", 16, "Regular Class", 'o' }, - { "Times New Roman", 16, "Regular Class", 'w' }, - { "Trebuchet MS", 11, "Regular Class", 0 }, - { "Trebuchet MS", 12, "Regular Class", 0 }, - { "Trebuchet MS", 14, "Regular Class", 0 }, - { "Trebuchet MS", 15, "Regular Class", 0 }, - { "Ubuntu", 12, "Regular Class", 'm' }, - /* Cyrillic small letter sha */ - { "Verdana", 10, "Regular Class", 0x448 }, - { "Verdana", 11, "Regular Class", 0x448 }, - { "Verdana and Clones", 12, "Regular Class", 'i' }, - { "Verdana and Clones", 12, "Regular Class", 'j' }, - { "Verdana and Clones", 12, "Regular Class", 'l' }, - { "Verdana and Clones", 12, "Regular Class", 'm' }, - { "Verdana and Clones", 13, "Regular Class", 'i' }, - { "Verdana and Clones", 13, "Regular Class", 'j' }, - { "Verdana and Clones", 13, "Regular Class", 'l' }, - { "Verdana and Clones", 14, "Regular Class", 'm' }, - }; - - - /* Scaling slightly in the x-direction prior to hinting results in */ - /* more visually pleasing glyphs in certain cases. */ - /* This sometimes needs to be coordinated with compatible width rules. */ - /* A value of 1000 corresponds to a scaled value of 1.0. */ - -#define X_SCALING_RULES_SIZE 50 - - static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] = - { - { "DejaVu Sans", 12, "Regular Class", 'm', 950 }, - { "Verdana and Clones", 12, "Regular Class", 'a', 1100 }, - { "Verdana and Clones", 13, "Regular Class", 'a', 1050 }, - { "Arial", 11, "Regular Class", 'm', 975 }, - { "Arial", 12, "Regular Class", 'm', 1050 }, - /* Cyrillic small letter el */ - { "Arial", 13, "Regular Class", 0x43B, 950 }, - { "Arial", 13, "Regular Class", 'o', 950 }, - { "Arial", 13, "Regular Class", 'e', 950 }, - { "Arial", 14, "Regular Class", 'm', 950 }, - /* Cyrillic small letter el */ - { "Arial", 15, "Regular Class", 0x43B, 925 }, - { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 }, - { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 }, - { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 }, - { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 }, - { "DejaVu Sans", 12, "Regular Class", 'l', 975 }, - { "DejaVu Sans", 12, "Regular Class", 'i', 975 }, - { "DejaVu Sans", 12, "Regular Class", 'j', 975 }, - { "DejaVu Sans", 13, "Regular Class", 'l', 950 }, - { "DejaVu Sans", 13, "Regular Class", 'i', 950 }, - { "DejaVu Sans", 13, "Regular Class", 'j', 950 }, - { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 }, - { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 }, - { "Georgia", 10, "", 0, 1050 }, - { "Georgia", 11, "", 0, 1100 }, - { "Georgia", 12, "", 0, 1025 }, - { "Georgia", 13, "", 0, 1050 }, - { "Georgia", 16, "", 0, 1050 }, - { "Georgia", 17, "", 0, 1030 }, - { "Liberation Sans", 12, "Regular Class", 'm', 1100 }, - { "Lucida Grande", 11, "Regular Class", 'm', 1100 }, - { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 }, - { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 }, - { "Segoe UI", 12, "Regular Class", 'H', 1050 }, - { "Segoe UI", 12, "Regular Class", 'm', 1050 }, - { "Segoe UI", 14, "Regular Class", 'm', 1050 }, - { "Tahoma", 11, "Regular Class", 'i', 975 }, - { "Tahoma", 11, "Regular Class", 'l', 975 }, - { "Tahoma", 11, "Regular Class", 'j', 900 }, - { "Tahoma", 11, "Regular Class", 'm', 918 }, - { "Verdana", 10, "Regular/Italic Class", 0, 1100 }, - { "Verdana", 12, "Regular Class", 'm', 975 }, - { "Verdana", 12, "Regular/Italic Class", 0, 1050 }, - { "Verdana", 13, "Regular/Italic Class", 'i', 950 }, - { "Verdana", 13, "Regular/Italic Class", 'j', 950 }, - { "Verdana", 13, "Regular/Italic Class", 'l', 950 }, - { "Verdana", 16, "Regular Class", 0, 1050 }, - { "Verdana", 9, "Regular/Italic Class", 0, 1050 }, - { "Times New Roman", 16, "Regular Class", 'm', 918 }, - { "Trebuchet MS", 11, "Regular Class", 'm', 800 }, - { "Trebuchet MS", 12, "Regular Class", 'm', 800 }, - }; - -#else - -#define COMPATIBLE_WIDTHS_RULES_SIZE 1 - - static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules - [COMPATIBLE_WIDTHS_RULES_SIZE] = - { - { "-", 0, "", 0 }, - }; - - -#define X_SCALING_RULES_SIZE 1 - - static const SPH_ScaleRule X_SCALING_Rules - [X_SCALING_RULES_SIZE] = - { - { "-", 0, "", 0, 1000 }, - }; - -#endif /* FORCE_NATURAL_WIDTHS */ - - - static FT_Bool - is_member_of_family_class( const FT_String* detected_font_name, - const FT_String* rule_font_name ) - { - FT_UInt i, j; - - - /* Does font name match rule family? */ - if ( ft_strcmp( detected_font_name, rule_font_name ) == 0 ) - return TRUE; - - /* Is font name a wildcard ""? */ - if ( ft_strcmp( rule_font_name, "" ) == 0 ) - return TRUE; - - /* Is font name contained in a class list? */ - for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ ) - { - if ( ft_strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) - { - for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) - { - if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) - continue; - if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], - detected_font_name ) == 0 ) - return TRUE; - } - } - } - - return FALSE; - } - - - static FT_Bool - is_member_of_style_class( const FT_String* detected_font_style, - const FT_String* rule_font_style ) - { - FT_UInt i, j; - - - /* Does font style match rule style? */ - if ( ft_strcmp( detected_font_style, rule_font_style ) == 0 ) - return TRUE; - - /* Is font style a wildcard ""? */ - if ( ft_strcmp( rule_font_style, "" ) == 0 ) - return TRUE; - - /* Is font style contained in a class list? */ - for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ ) - { - if ( ft_strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) - { - for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ ) - { - if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) - continue; - if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], - detected_font_style ) == 0 ) - return TRUE; - } - } - } - - return FALSE; - } - - - FT_LOCAL_DEF( FT_Bool ) - sph_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_TweakRule* rule, - FT_UInt num_rules ) - { - FT_UInt i; - - - /* rule checks may be able to be optimized further */ - for ( i = 0; i < num_rules; i++ ) - { - if ( family && - ( is_member_of_family_class ( family, rule[i].family ) ) ) - if ( rule[i].ppem == 0 || - rule[i].ppem == ppem ) - if ( style && - is_member_of_style_class ( style, rule[i].style ) ) - if ( rule[i].glyph == 0 || - FT_Get_Char_Index( (FT_Face)face, - rule[i].glyph ) == glyph_index ) - return TRUE; - } - - return FALSE; - } - - - static FT_UInt - scale_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_ScaleRule* rule, - FT_UInt num_rules ) - { - FT_UInt i; - - - /* rule checks may be able to be optimized further */ - for ( i = 0; i < num_rules; i++ ) - { - if ( family && - ( is_member_of_family_class ( family, rule[i].family ) ) ) - if ( rule[i].ppem == 0 || - rule[i].ppem == ppem ) - if ( style && - is_member_of_style_class( style, rule[i].style ) ) - if ( rule[i].glyph == 0 || - FT_Get_Char_Index( (FT_Face)face, - rule[i].glyph ) == glyph_index ) - return rule[i].scale; - } - - return 1000; - } - - - FT_LOCAL_DEF( FT_UInt ) - sph_test_tweak_x_scaling( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index ) - { - return scale_test_tweak( face, family, ppem, style, glyph_index, - X_SCALING_Rules, X_SCALING_RULES_SIZE ); - } - - -#define TWEAK_RULES( x ) \ - if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ - x##_Rules, x##_RULES_SIZE ) ) \ - loader->exec->sph_tweak_flags |= SPH_TWEAK_##x; - -#define TWEAK_RULES_EXCEPTIONS( x ) \ - if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ - x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \ - loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x; - - - FT_LOCAL_DEF( void ) - sph_set_tweaks( TT_Loader loader, - FT_UInt glyph_index ) - { - TT_Face face = loader->face; - FT_String* family = face->root.family_name; - FT_UInt ppem = loader->size->metrics->x_ppem; - FT_String* style = face->root.style_name; - - - /* don't apply rules if style isn't set */ - if ( !face->root.style_name ) - return; - -#ifdef SPH_DEBUG_MORE_VERBOSE - printf( "%s,%d,%s,%c=%d ", - family, ppem, style, glyph_index, glyph_index ); -#endif - - TWEAK_RULES( PIXEL_HINTING ); - - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING ) - { - loader->exec->ignore_x_mode = FALSE; - return; - } - - TWEAK_RULES( ALLOW_X_DMOVE ); - TWEAK_RULES( ALWAYS_DO_DELTAP ); - TWEAK_RULES( ALWAYS_SKIP_DELTAP ); - TWEAK_RULES( DEEMBOLDEN ); - TWEAK_RULES( DO_SHPIX ); - TWEAK_RULES( EMBOLDEN ); - TWEAK_RULES( MIAP_HACK ); - TWEAK_RULES( NORMAL_ROUND ); - TWEAK_RULES( NO_ALIGNRP_AFTER_IUP ); - TWEAK_RULES( NO_CALL_AFTER_IUP ); - TWEAK_RULES( NO_DELTAP_AFTER_IUP ); - TWEAK_RULES( RASTERIZER_35 ); - TWEAK_RULES( SKIP_IUP ); - - TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES ); - - TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP ); - - TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES ); - - TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES ); - TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES ); - - if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) - { - if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 ) - { - loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; - loader->exec->size->cvt_ready = -1; - - tt_size_ready_bytecode( - loader->exec->size, - FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); - } - else - loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35; - } - else - { - if ( loader->exec->rasterizer_version != - SPH_OPTION_SET_RASTERIZER_VERSION ) - { - loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - loader->exec->size->cvt_ready = -1; - - tt_size_ready_bytecode( - loader->exec->size, - FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); - } - else - loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; - } - - if ( IS_HINTED( loader->load_flags ) ) - { - TWEAK_RULES( TIMES_NEW_ROMAN_HACK ); - TWEAK_RULES( COURIER_NEW_2_HACK ); - } - - if ( sph_test_tweak( face, family, ppem, style, glyph_index, - COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) ) - loader->exec->face->sph_compatibility_mode = TRUE; - - - if ( IS_HINTED( loader->load_flags ) ) - { - if ( sph_test_tweak( face, family, ppem, style, glyph_index, - COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) ) - loader->exec->compatible_widths |= TRUE; - } - } - -#else /* !(TT_USE_BYTECODE_INTERPRETER && */ - /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ - - /* ANSI C doesn't like empty source files */ - typedef int _tt_subpix_dummy; - -#endif /* !(TT_USE_BYTECODE_INTERPRETER && */ - /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */ - - -/* END */ diff --git a/src/thirdparty/freetype2/src/truetype/ttsubpix.h b/src/thirdparty/freetype2/src/truetype/ttsubpix.h deleted file mode 100644 index 4966800c2..000000000 --- a/src/thirdparty/freetype2/src/truetype/ttsubpix.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * - * ttsubpix.h - * - * TrueType Subpixel Hinting. - * - * Copyright (C) 2010-2019 by - * David Turner, Robert Wilhelm, and Werner Lemberg. - * - * This file is part of the FreeType project, and may only be used, - * modified, and distributed under the terms of the FreeType project - * license, LICENSE.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 TTSUBPIX_H_ -#define TTSUBPIX_H_ - -#include -#include "ttobjs.h" -#include "ttinterp.h" - - -FT_BEGIN_HEADER - - -#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY - - /************************************************************************** - * - * ID flags to identify special functions at FDEF and runtime. - * - */ -#define SPH_FDEF_INLINE_DELTA_1 0x0000001 -#define SPH_FDEF_INLINE_DELTA_2 0x0000002 -#define SPH_FDEF_DIAGONAL_STROKE 0x0000004 -#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008 -#define SPH_FDEF_TTFAUTOHINT_1 0x0000010 -#define SPH_FDEF_SPACING_1 0x0000020 -#define SPH_FDEF_SPACING_2 0x0000040 -#define SPH_FDEF_TYPEMAN_STROKES 0x0000080 -#define SPH_FDEF_TYPEMAN_DIAGENDCTRL 0x0000100 - - - /************************************************************************** - * - * Tweak flags that are set for each glyph by the below rules. - * - */ -#define SPH_TWEAK_ALLOW_X_DMOVE 0x0000001UL -#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000002UL -#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000004UL -#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000008UL -#define SPH_TWEAK_DEEMBOLDEN 0x0000010UL -#define SPH_TWEAK_DO_SHPIX 0x0000020UL -#define SPH_TWEAK_EMBOLDEN 0x0000040UL -#define SPH_TWEAK_MIAP_HACK 0x0000080UL -#define SPH_TWEAK_NORMAL_ROUND 0x0000100UL -#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0000200UL -#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0000400UL -#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0000800UL -#define SPH_TWEAK_PIXEL_HINTING 0x0001000UL -#define SPH_TWEAK_RASTERIZER_35 0x0002000UL -#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0004000UL -#define SPH_TWEAK_SKIP_IUP 0x0008000UL -#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0010000UL -#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0020000UL -#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0040000UL -#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP 0x0080000UL - - - FT_LOCAL( FT_Bool ) - sph_test_tweak( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index, - const SPH_TweakRule* rule, - FT_UInt num_rules ); - - FT_LOCAL( FT_UInt ) - sph_test_tweak_x_scaling( TT_Face face, - const FT_String* family, - FT_UInt ppem, - const FT_String* style, - FT_UInt glyph_index ); - - FT_LOCAL( void ) - sph_set_tweaks( TT_Loader loader, - FT_UInt glyph_index ); - - - /* These macros are defined absent a method for setting them */ -#define SPH_OPTION_BITMAP_WIDTHS FALSE -#define SPH_OPTION_SET_SUBPIXEL TRUE -#define SPH_OPTION_SET_GRAYSCALE FALSE -#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE -#define SPH_OPTION_SET_RASTERIZER_VERSION 38 - -#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */ - - -FT_END_HEADER - -#endif /* TTSUBPIX_H_ */ - - -/* END */ diff --git a/src/thirdparty/freetype2/src/type1/t1afm.c b/src/thirdparty/freetype2/src/type1/t1afm.c index 684118453..b1a0d23be 100644 --- a/src/thirdparty/freetype2/src/type1/t1afm.c +++ b/src/thirdparty/freetype2/src/type1/t1afm.c @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,11 +16,10 @@ */ -#include #include "t1afm.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include #include "t1errors.h" @@ -84,7 +83,7 @@ /* compare two kerning pairs */ - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_kern_pairs( const void* a, const void* b ) { @@ -179,7 +178,6 @@ /* 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++ ) { @@ -187,9 +185,7 @@ /* check against PostScript pseudo platform */ if ( charmap->platform_id == 7 ) { - error = FT_Set_Charmap( t1_face, charmap ); - if ( error ) - goto Exit; + t1_face->charmap = charmap; break; } } @@ -204,16 +200,13 @@ 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->x = (FT_Int)FT_PEEK_SHORT_LE( p + 2 ); kp->y = 0; kp++; } - if ( oldcharmap ) - error = FT_Set_Charmap( t1_face, oldcharmap ); - if ( error ) - goto Exit; + t1_face->charmap = oldcharmap; /* now, sort the kern pairs according to their glyph indices */ ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), @@ -303,9 +296,14 @@ t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; - /* no `U' suffix here to 0x8000! */ - t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); - t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); + /* ascender and descender are optional and could both be zero */ + /* check if values are meaningful before overriding defaults */ + if ( fi->Ascender > fi->Descender ) + { + /* no `U' suffix here to 0x8000! */ + t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); + t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); + } if ( fi->NumKernPair ) { @@ -407,7 +405,7 @@ #else /* T1_CONFIG_OPTION_NO_AFM */ /* ANSI C doesn't like empty source files */ - typedef int _t1_afm_dummy; + typedef int t1_afm_dummy_; #endif /* T1_CONFIG_OPTION_NO_AFM */ diff --git a/src/thirdparty/freetype2/src/type1/t1afm.h b/src/thirdparty/freetype2/src/type1/t1afm.h index a8e6a5495..92ff627dd 100644 --- a/src/thirdparty/freetype2/src/type1/t1afm.h +++ b/src/thirdparty/freetype2/src/type1/t1afm.h @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,8 @@ #ifndef T1AFM_H_ #define T1AFM_H_ -#include #include "t1objs.h" -#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type1/t1driver.c b/src/thirdparty/freetype2/src/type1/t1driver.c index 557733da3..5ded77140 100644 --- a/src/thirdparty/freetype2/src/type1/t1driver.c +++ b/src/thirdparty/freetype2/src/type1/t1driver.c @@ -4,7 +4,7 @@ * * Type 1 driver interface (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,7 +16,6 @@ */ -#include #include "t1driver.h" #include "t1gload.h" #include "t1load.h" @@ -27,20 +26,20 @@ #include "t1afm.h" #endif -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_HASH_H -#include FT_INTERNAL_POSTSCRIPT_PROPS_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include -#include FT_SERVICE_MULTIPLE_MASTERS_H -#include FT_SERVICE_GLYPH_DICT_H -#include FT_SERVICE_FONT_FORMAT_H -#include FT_SERVICE_POSTSCRIPT_NAME_H -#include FT_SERVICE_POSTSCRIPT_CMAPS_H -#include FT_SERVICE_POSTSCRIPT_INFO_H -#include FT_SERVICE_PROPERTIES_H -#include FT_SERVICE_KERNING_H +#include +#include +#include +#include +#include +#include +#include +#include /************************************************************************** @@ -57,28 +56,32 @@ * */ - static FT_Error - t1_get_glyph_name( T1_Face face, + FT_CALLBACK_DEF( FT_Error ) + t1_get_glyph_name( FT_Face face, /* T1_Face */ FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max ) { - FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + T1_Face t1face = (T1_Face)face; + + + FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max ); return FT_Err_Ok; } - static FT_UInt - t1_get_name_index( T1_Face face, + FT_CALLBACK_DEF( FT_UInt ) + t1_get_name_index( FT_Face face, /* T1_Face */ const FT_String* glyph_name ) { - FT_Int i; + T1_Face t1face = (T1_Face)face; + FT_Int i; - for ( i = 0; i < face->type1.num_glyphs; i++ ) + for ( i = 0; i < t1face->type1.num_glyphs; i++ ) { - FT_String* gname = face->type1.glyph_names[i]; + FT_String* gname = t1face->type1.glyph_names[i]; if ( !ft_strcmp( glyph_name, gname ) ) @@ -91,8 +94,8 @@ static const FT_Service_GlyphDictRec t1_service_glyph_dict = { - (FT_GlyphDict_GetNameFunc) t1_get_glyph_name, /* get_name */ - (FT_GlyphDict_NameIndexFunc)t1_get_name_index /* name_index */ + t1_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + t1_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ }; @@ -102,9 +105,12 @@ */ static const char* - t1_get_ps_name( T1_Face face ) + t1_get_ps_name( FT_Face face ) /* T1_Face */ { - return (const char*) face->type1.font_name; + T1_Face t1face = (T1_Face)face; + + + return (const char*) t1face->type1.font_name; } @@ -122,19 +128,28 @@ #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT static const FT_Service_MultiMastersRec t1_service_multi_masters = { - (FT_Get_MM_Func) T1_Get_Multi_Master, /* get_mm */ - (FT_Set_MM_Design_Func) T1_Set_MM_Design, /* set_mm_design */ - (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) T1_Get_MM_Blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) T1_Get_MM_Var, /* get_mm_var */ - (FT_Set_Var_Design_Func) T1_Set_Var_Design, /* set_var_design */ - (FT_Get_Var_Design_Func) T1_Get_Var_Design, /* get_var_design */ - (FT_Set_Instance_Func) T1_Reset_MM_Blend, /* set_instance */ - (FT_Set_MM_WeightVector_Func)T1_Set_MM_WeightVector, /* set_mm_weightvector */ - (FT_Get_MM_WeightVector_Func)T1_Get_MM_WeightVector, /* get_mm_weightvector */ + T1_Get_Multi_Master, /* FT_Get_MM_Func get_mm */ + T1_Set_MM_Design, /* FT_Set_MM_Design_Func set_mm_design */ + T1_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */ + T1_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */ + T1_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */ + T1_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */ + T1_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */ + T1_Reset_MM_Blend, /* FT_Set_Named_Instance_Func set_named_instance */ + NULL, /* FT_Get_Default_Named_Instance_Func get_default_named_instance */ + T1_Set_MM_WeightVector, + /* FT_Set_MM_WeightVector_Func set_mm_weightvector */ + T1_Get_MM_WeightVector, + /* FT_Get_MM_WeightVector_Func get_mm_weightvector */ - (FT_Get_Var_Blend_Func) NULL, /* get_var_blend */ - (FT_Done_Blend_Func) T1_Done_Blend /* done_blend */ + NULL, /* FT_Construct_PS_Name_Func construct_ps_name */ + NULL, /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */ + NULL, /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */ + NULL, /* FT_Var_Get_Item_Delta_Func get_item_delta */ + NULL, /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */ + NULL, /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */ + NULL, /* FT_Get_Var_Blend_Func get_var_blend */ + T1_Done_Blend /* FT_Done_Blend_Func done_blend */ }; #endif @@ -297,10 +312,7 @@ { retval = ft_strlen( type1->glyph_names[idx] ) + 1; if ( value && value_len >= retval ) - { ft_memcpy( value, (void *)( type1->glyph_names[idx] ), retval ); - ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; - } } break; @@ -329,11 +341,8 @@ { retval = ft_strlen( type1->encoding.char_name[idx] ) + 1; if ( value && value_len >= retval ) - { ft_memcpy( value, (void *)( type1->encoding.char_name[idx] ), - retval - 1 ); - ((FT_Char *)value)[retval - 1] = (FT_Char)'\0'; - } + retval ); } break; @@ -622,11 +631,11 @@ static const FT_Service_PsInfoRec t1_service_ps_info = { - (PS_GetFontInfoFunc) t1_ps_get_font_info, /* ps_get_font_info */ - (PS_GetFontExtraFunc) t1_ps_get_font_extra, /* ps_get_font_extra */ - (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names, /* ps_has_glyph_names */ - (PS_GetFontPrivateFunc)t1_ps_get_font_private, /* ps_get_font_private */ - (PS_GetFontValueFunc) t1_ps_get_font_value, /* ps_get_font_value */ + t1_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */ + t1_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */ + t1_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */ + t1_ps_get_font_private, /* PS_GetFontPrivateFunc ps_get_font_private */ + t1_ps_get_font_value, /* PS_GetFontValueFunc ps_get_font_value */ }; @@ -646,9 +655,9 @@ FT_DEFINE_SERVICE_PROPERTIESREC( t1_service_properties, - (FT_Properties_SetFunc)ps_property_set, /* set_property */ - (FT_Properties_GetFunc)ps_property_get ) /* get_property */ - + ps_property_set, /* FT_Properties_SetFunc set_property */ + ps_property_get /* FT_Properties_GetFunc get_property */ + ) /* * SERVICE LIST diff --git a/src/thirdparty/freetype2/src/type1/t1driver.h b/src/thirdparty/freetype2/src/type1/t1driver.h index 206f64a0b..1cc3d24e7 100644 --- a/src/thirdparty/freetype2/src/type1/t1driver.h +++ b/src/thirdparty/freetype2/src/type1/t1driver.h @@ -4,7 +4,7 @@ * * High-level Type 1 driver interface (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define T1DRIVER_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type1/t1errors.h b/src/thirdparty/freetype2/src/type1/t1errors.h index b35f67a24..46bddbc30 100644 --- a/src/thirdparty/freetype2/src/type1/t1errors.h +++ b/src/thirdparty/freetype2/src/type1/t1errors.h @@ -4,7 +4,7 @@ * * Type 1 error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef T1ERRORS_H_ #define T1ERRORS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX T1_Err_ #define FT_ERR_BASE FT_Mod_Err_Type1 -#include FT_ERRORS_H +#include #endif /* T1ERRORS_H_ */ diff --git a/src/thirdparty/freetype2/src/type1/t1gload.c b/src/thirdparty/freetype2/src/type1/t1gload.c index f9b115b18..b9bc0b56c 100644 --- a/src/thirdparty/freetype2/src/type1/t1gload.c +++ b/src/thirdparty/freetype2/src/type1/t1gload.c @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,15 +16,14 @@ */ -#include #include "t1gload.h" -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_OUTLINE_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_INTERNAL_CFF_TYPES_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include +#include +#include #include "t1errors.h" @@ -71,8 +70,13 @@ /* For incremental fonts get the character data using the */ /* callback function. */ if ( inc ) + { + /* So `free_glyph_data` knows whether to free it. */ + char_string->pointer = NULL; + error = inc->funcs->get_glyph_data( inc->object, glyph_index, char_string ); + } else #endif /* FT_CONFIG_OPTION_INCREMENTAL */ @@ -80,7 +84,7 @@ /* 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]; + char_string->length = type1->charstrings_len[glyph_index]; } if ( !error ) @@ -156,6 +160,9 @@ decoder->builder.advance.y = INT_TO_FIXED( metrics.advance_v ); } + if ( error && inc ) + inc->funcs->free_glyph_data( inc->object, char_string ); + #endif /* FT_CONFIG_OPTION_INCREMENTAL */ return error; @@ -265,7 +272,7 @@ } FT_TRACE6(( "T1_Compute_Max_Advance: max advance: %f\n", - *max_advance / 65536.0 )); + (double)*max_advance / 65536 )); psaux->t1_decoder_funcs->done( &decoder ); @@ -296,7 +303,7 @@ { advances[nn] = 0; - FT_TRACE5(( " idx %d: advance height 0 font units\n", + FT_TRACE5(( " idx %u: advance height 0 font units\n", first + nn )); } @@ -334,7 +341,7 @@ else advances[nn] = 0; - FT_TRACE5(( " idx %d: advance width %d font unit%s\n", + FT_TRACE5(( " idx %u: advance width %ld font unit%s\n", first + nn, advances[nn], advances[nn] == 1 ? "" : "s" )); @@ -381,7 +388,7 @@ goto Exit; } - FT_TRACE1(( "T1_Load_Glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "T1_Load_Glyph: glyph index %u\n", glyph_index )); FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); @@ -399,16 +406,12 @@ glyph->y_scale = 0x10000L; } - t1glyph->outline.n_points = 0; - t1glyph->outline.n_contours = 0; - hinting = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) && !( load_flags & FT_LOAD_NO_HINTING ) ); scaled = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); glyph->hint = hinting; glyph->scaled = scaled; - t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; error = decoder_funcs->init( &decoder, t1glyph->face, @@ -453,16 +456,12 @@ 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 ) { - t1glyph->outline.flags &= FT_OUTLINE_OWNER; - t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; - - /* for composite glyphs, return only left side bearing and */ - /* advance width */ + /* 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 = t1glyph->internal; @@ -483,6 +482,13 @@ FT_Glyph_Metrics* metrics = &t1glyph->metrics; + t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; + + t1glyph->outline.flags &= FT_OUTLINE_OWNER; + t1glyph->outline.flags |= FT_OUTLINE_REVERSE_FILL; + if ( t1size && t1size->metrics.y_ppem < 24 ) + t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; + /* copy the _unscaled_ advance width */ metrics->horiAdvance = FIXED_TO_INT( decoder.builder.advance.x ); @@ -505,11 +511,6 @@ FIXED_TO_INT( decoder.builder.advance.y ); } - t1glyph->format = FT_GLYPH_FORMAT_OUTLINE; - - if ( t1size && t1size->metrics.y_ppem < 24 ) - t1glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION; - #if 1 /* apply the font matrix, if any */ if ( font_matrix.xx != 0x10000L || font_matrix.yy != 0x10000L || diff --git a/src/thirdparty/freetype2/src/type1/t1gload.h b/src/thirdparty/freetype2/src/type1/t1gload.h index 80440369d..6bedd132c 100644 --- a/src/thirdparty/freetype2/src/type1/t1gload.h +++ b/src/thirdparty/freetype2/src/type1/t1gload.h @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,7 +20,6 @@ #define T1GLOAD_H_ -#include #include "t1objs.h" diff --git a/src/thirdparty/freetype2/src/type1/t1load.c b/src/thirdparty/freetype2/src/type1/t1load.c index 5cffdfaac..0f11445be 100644 --- a/src/thirdparty/freetype2/src/type1/t1load.c +++ b/src/thirdparty/freetype2/src/type1/t1load.c @@ -4,7 +4,7 @@ * * Type 1 font loader (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -61,19 +61,20 @@ #include -#include FT_INTERNAL_DEBUG_H +#include #include FT_CONFIG_CONFIG_H -#include FT_MULTIPLE_MASTERS_H -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_HASH_H +#include +#include +#include +#include #include "t1load.h" #include "t1errors.h" #ifdef FT_CONFIG_OPTION_INCREMENTAL -#define IS_INCREMENTAL FT_BOOL( face->root.internal->incremental_interface ) +#define IS_INCREMENTAL \ + FT_BOOL( FT_FACE( face )->internal->incremental_interface ) #else #define IS_INCREMENTAL 0 #endif @@ -117,6 +118,9 @@ goto Exit; blend->num_default_design_vector = 0; + blend->weight_vector = NULL; + blend->default_weight_vector = NULL; + blend->design_pos[0] = NULL; face->blend = blend; } @@ -130,14 +134,11 @@ /* 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 ) ) + 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 ) ) 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; @@ -164,21 +165,6 @@ 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; @@ -189,10 +175,11 @@ FT_LOCAL_DEF( FT_Error ) - T1_Get_Multi_Master( T1_Face face, + T1_Get_Multi_Master( FT_Face face, /* T1_Face */ FT_Multi_Master* master ) { - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; FT_UInt n; FT_Error error; @@ -240,11 +227,12 @@ for ( j = 1; j < axismap->num_points; j++ ) { if ( ncv <= axismap->blend_points[j] ) - return INT_TO_FIXED( axismap->design_points[j - 1] ) + - ( axismap->design_points[j] - axismap->design_points[j - 1] ) * - FT_DivFix( ncv - axismap->blend_points[j - 1], - axismap->blend_points[j] - - axismap->blend_points[j - 1] ); + return INT_TO_FIXED( axismap->design_points[j - 1] + + FT_MulDiv( ncv - axismap->blend_points[j - 1], + axismap->design_points[j] - + axismap->design_points[j - 1], + axismap->blend_points[j] - + axismap->blend_points[j - 1] ) ); } return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] ); @@ -299,41 +287,65 @@ * arguments needed by the GX var distortable fonts. */ FT_LOCAL_DEF( FT_Error ) - T1_Get_MM_Var( T1_Face face, + T1_Get_MM_Var( FT_Face face, /* T1_Face */ FT_MM_Var* *master ) { - FT_Memory memory = face->root.memory; - FT_MM_Var *mmvar = NULL; + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_MM_Var *mmvar = NULL; FT_Multi_Master mmaster; FT_Error error; FT_UInt i; FT_Fixed axiscoords[T1_MAX_MM_AXIS]; - PS_Blend blend = face->blend; + PS_Blend blend = t1face->blend; + FT_UShort* axis_flags; + + FT_Offset mmvar_size; + FT_Offset axis_flags_size; + FT_Offset axis_size; 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 ) ) ) + + /* the various `*_size' variables, which we also use as */ + /* offsets into the `mmvar' array, must be multiples of the */ + /* pointer size (except the last one); without such an */ + /* alignment there might be runtime errors due to */ + /* misaligned addresses */ +#undef ALIGN_SIZE +#define ALIGN_SIZE( n ) \ + ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) ) + + mmvar_size = ALIGN_SIZE( sizeof ( FT_MM_Var ) ); + axis_flags_size = ALIGN_SIZE( mmaster.num_axis * + sizeof ( FT_UShort ) ); + axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis ); + + if ( FT_QALLOC( mmvar, mmvar_size + + axis_flags_size + + axis_size ) ) goto Exit; mmvar->num_axis = mmaster.num_axis; mmvar->num_designs = mmaster.num_designs; mmvar->num_namedstyles = 0; /* Not supported */ - mmvar->axis = (FT_Var_Axis*)&mmvar[1]; - /* Point to axes after MM_Var struct */ - mmvar->namedstyle = NULL; + + /* while axis flags are meaningless here, we have to provide the array */ + /* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */ + /* values directly follow the data of `FT_MM_Var' */ + axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size ); + FT_ARRAY_ZERO( axis_flags, mmaster.num_axis ); + + mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size ); + mmvar->namedstyle = NULL; for ( i = 0; i < mmaster.num_axis; i++ ) { mmvar->axis[i].name = mmaster.axis[i].name; mmvar->axis[i].minimum = INT_TO_FIXED( mmaster.axis[i].minimum ); mmvar->axis[i].maximum = 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 = ~0U; /* Does not apply */ mmvar->axis[i].tag = ~0U; /* Does not apply */ @@ -346,6 +358,10 @@ 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' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Slant" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 's', 'l', 'n', 't' ); + else if ( ft_strcmp( mmvar->axis[i].name, "Italic" ) == 0 ) + mmvar->axis[i].tag = FT_MAKE_TAG( 'i', 't', 'a', 'l' ); } mm_weights_unmap( blend->default_weight_vector, @@ -425,32 +441,21 @@ FT_LOCAL_DEF( FT_Error ) - T1_Set_MM_Blend( T1_Face face, + T1_Set_MM_Blend( FT_Face face, /* T1_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - FT_Error error; - - - error = t1_set_mm_blend( face, num_coords, coords ); - if ( error ) - return error; - - if ( num_coords ) - face->root.face_flags |= FT_FACE_FLAG_VARIATION; - else - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; - - return FT_Err_Ok; + return t1_set_mm_blend( (T1_Face)face, num_coords, coords ); } FT_LOCAL_DEF( FT_Error ) - T1_Get_MM_Blend( T1_Face face, + T1_Get_MM_Blend( FT_Face face, /* T1_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; FT_Fixed axiscoords[4]; FT_UInt i, nc; @@ -466,7 +471,7 @@ nc = num_coords; if ( num_coords > blend->num_axis ) { - FT_TRACE2(( "T1_Get_MM_Blend: only using first %d of %d coordinates\n", + FT_TRACE2(( "T1_Get_MM_Blend: only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -481,11 +486,12 @@ FT_LOCAL_DEF( FT_Error ) - T1_Set_MM_WeightVector( T1_Face face, + T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */ FT_UInt len, FT_Fixed* weightvector ) { - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; FT_UInt i, n; @@ -509,11 +515,6 @@ for ( ; i < blend->num_designs; i++ ) blend->weight_vector[i] = (FT_Fixed)0; - - if ( len ) - face->root.face_flags |= FT_FACE_FLAG_VARIATION; - else - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; } return FT_Err_Ok; @@ -521,11 +522,12 @@ FT_LOCAL_DEF( FT_Error ) - T1_Get_MM_WeightVector( T1_Face face, + T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */ FT_UInt* len, FT_Fixed* weightvector ) { - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; FT_UInt i; @@ -550,13 +552,14 @@ FT_LOCAL_DEF( FT_Error ) - T1_Set_MM_Design( T1_Face face, + T1_Set_MM_Design( FT_Face face, /* T1_Face */ FT_UInt num_coords, FT_Long* coords ) { + T1_Face t1face = (T1_Face)face; FT_Error error; - PS_Blend blend = face->blend; - FT_UInt n, p; + PS_Blend blend = t1face->blend; + FT_UInt n; FT_Fixed final_blends[T1_MAX_MM_DESIGNS]; @@ -575,7 +578,7 @@ 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; + FT_Int p, before = -1, after = -1; /* use a default value if we don't have a coordinate */ @@ -584,7 +587,7 @@ else design = ( designs[map->num_points - 1] - designs[0] ) / 2; - for ( p = 0; p < (FT_UInt)map->num_points; p++ ) + for ( p = 0; p < (FT_Int)map->num_points; p++ ) { FT_Long p_design = designs[p]; @@ -598,11 +601,11 @@ if ( design < p_design ) { - after = (FT_Int)p; + after = p; break; } - before = (FT_Int)p; + before = p; } /* now interpolate if necessary */ @@ -621,15 +624,10 @@ final_blends[n] = the_blend; } - error = t1_set_mm_blend( face, blend->num_axis, final_blends ); + error = t1_set_mm_blend( t1face, blend->num_axis, final_blends ); if ( error ) return error; - if ( num_coords ) - face->root.face_flags |= FT_FACE_FLAG_VARIATION; - else - face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; - return FT_Err_Ok; } @@ -637,12 +635,12 @@ /* MM fonts don't have named instances, so only the design is reset */ FT_LOCAL_DEF( FT_Error ) - T1_Reset_MM_Blend( T1_Face face, + T1_Reset_MM_Blend( FT_Face face, FT_UInt instance_index ) { FT_UNUSED( instance_index ); - return T1_Set_MM_Blend( face, 0, NULL ); + return T1_Set_MM_WeightVector( face, 0, NULL ); } @@ -652,7 +650,7 @@ * arguments needed by the GX var distortable fonts. */ FT_LOCAL_DEF( FT_Error ) - T1_Set_Var_Design( T1_Face face, + T1_Set_Var_Design( FT_Face face, /* T1_Face */ FT_UInt num_coords, FT_Fixed* coords ) { @@ -671,11 +669,12 @@ FT_LOCAL_DEF( FT_Error ) - T1_Get_Var_Design( T1_Face face, + T1_Get_Var_Design( FT_Face face, /* T1_Face */ FT_UInt num_coords, FT_Fixed* coords ) { - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + PS_Blend blend = t1face->blend; FT_Fixed axiscoords[4]; FT_UInt i, nc; @@ -692,7 +691,7 @@ if ( num_coords > blend->num_axis ) { FT_TRACE2(( "T1_Get_Var_Design:" - " only using first %d of %d coordinates\n", + " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); nc = blend->num_axis; } @@ -707,10 +706,11 @@ FT_LOCAL_DEF( void ) - T1_Done_Blend( T1_Face face ) + T1_Done_Blend( FT_Face face ) /* T1_Face */ { - FT_Memory memory = face->root.memory; - PS_Blend blend = face->blend; + T1_Face t1face = (T1_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Blend blend = t1face->blend; if ( blend ) @@ -751,24 +751,27 @@ PS_DesignMap dmap = blend->design_map + n; + FT_FREE( dmap->blend_points ); FT_FREE( dmap->design_points ); dmap->num_points = 0; } - FT_FREE( face->blend ); + FT_FREE( t1face->blend ); } } static void - parse_blend_axis_types( T1_Face face, - T1_Loader loader ) + parse_blend_axis_types( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; T1_TokenRec axis_tokens[T1_MAX_MM_AXIS]; FT_Int n, num_axis; - FT_Error error = FT_Err_Ok; + FT_Error error = FT_Err_Ok; PS_Blend blend; - FT_Memory memory; + FT_Memory memory = FT_FACE_MEMORY( face ); /* take an array of objects */ @@ -788,14 +791,13 @@ } /* allocate blend if necessary */ - error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); if ( error ) goto Exit; FT_TRACE4(( " [" )); - blend = face->blend; - memory = face->root.memory; + blend = t1face->blend; /* each token is an immediate containing the name of the axis */ for ( n = 0; n < num_axis; n++ ) @@ -827,7 +829,7 @@ FT_FREE( name ); } - if ( FT_ALLOC( blend->axis_names[n], len + 1 ) ) + if ( FT_QALLOC( blend->axis_names[n], len + 1 ) ) goto Exit; name = (FT_Byte*)blend->axis_names[n]; @@ -843,17 +845,21 @@ static void - parse_blend_design_positions( T1_Face face, - T1_Loader loader ) + parse_blend_design_positions( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (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_Int num_axis = 0; /* make compiler happy */ + T1_Parser parser = &loader->parser; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + FT_Fixed* design_pos[T1_MAX_MM_DESIGNS]; - FT_Error error = FT_Err_Ok; - PS_Blend blend; + design_pos[0] = NULL; /* get the array of design tokens -- compute number of designs */ T1_ToTokenArray( parser, design_tokens, @@ -875,12 +881,10 @@ { FT_Byte* old_cursor = parser->root.cursor; FT_Byte* old_limit = parser->root.limit; - FT_Int n; + FT_Int n, nn; + PS_Blend blend; - blend = face->blend; - num_axis = 0; /* make compiler happy */ - FT_TRACE4(( " [" )); for ( n = 0; n < num_designs; n++ ) @@ -908,12 +912,18 @@ } num_axis = n_axis; - error = t1_allocate_blend( face, + error = t1_allocate_blend( t1face, (FT_UInt)num_designs, (FT_UInt)num_axis ); if ( error ) goto Exit; - blend = face->blend; + + /* allocate a blend design pos table */ + if ( FT_QNEW_ARRAY( design_pos[0], num_designs * num_axis ) ) + goto Exit; + + for ( nn = 1; nn < num_designs; nn++ ) + design_pos[nn] = design_pos[0] + num_axis * nn; } else if ( n_axis != num_axis ) { @@ -931,8 +941,8 @@ parser->root.cursor = token2->start; parser->root.limit = token2->limit; - blend->design_pos[n][axis] = T1_ToFixed( parser, 0 ); - FT_TRACE4(( " %f", (double)blend->design_pos[n][axis] / 65536 )); + design_pos[n][axis] = T1_ToFixed( parser, 0 ); + FT_TRACE4(( " %f", (double)design_pos[n][axis] / 65536 )); } FT_TRACE4(( "]" )) ; } @@ -941,17 +951,31 @@ loader->parser.root.cursor = old_cursor; loader->parser.root.limit = old_limit; + + /* a valid BlendDesignPosition has been parsed */ + blend = t1face->blend; + if ( blend->design_pos[0] ) + FT_FREE( blend->design_pos[0] ); + + for ( n = 0; n < num_designs; n++ ) + { + blend->design_pos[n] = design_pos[n]; + design_pos[n] = NULL; + } } Exit: + FT_FREE( design_pos[0] ); loader->parser.root.error = error; } static void - parse_blend_design_map( T1_Face face, - T1_Loader loader ) + parse_blend_design_map( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; FT_Error error = FT_Err_Ok; T1_Parser parser = &loader->parser; PS_Blend blend; @@ -959,7 +983,7 @@ FT_Int n, num_axis; FT_Byte* old_cursor; FT_Byte* old_limit; - FT_Memory memory = face->root.memory; + FT_Memory memory = FT_FACE_MEMORY( face ); T1_ToTokenArray( parser, axis_tokens, @@ -980,10 +1004,10 @@ old_cursor = parser->root.cursor; old_limit = parser->root.limit; - error = t1_allocate_blend( face, 0, (FT_UInt)num_axis ); + error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis ); if ( error ) goto Exit; - blend = face->blend; + blend = t1face->blend; FT_TRACE4(( " [" )); @@ -1020,9 +1044,9 @@ } /* allocate design map data */ - if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) ) + if ( FT_QNEW_ARRAY( map->design_points, num_points ) || + FT_QNEW_ARRAY( map->blend_points, num_points ) ) goto Exit; - map->blend_points = map->design_points + num_points; map->num_points = (FT_Byte)num_points; for ( p = 0; p < num_points; p++ ) @@ -1039,7 +1063,7 @@ map->design_points[p] = T1_ToInt( parser ); map->blend_points [p] = T1_ToFixed( parser, 0 ); - FT_TRACE4(( " [%d %f]", + FT_TRACE4(( " [%ld %f]", map->design_points[p], (double)map->blend_points[p] / 65536 )); } @@ -1058,14 +1082,17 @@ static void - parse_weight_vector( T1_Face face, - T1_Loader loader ) + parse_weight_vector( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS]; FT_Int num_designs; FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_FACE_MEMORY( face ); T1_Parser parser = &loader->parser; - PS_Blend blend = face->blend; + PS_Blend blend = t1face->blend; T1_Token token; FT_Int n; FT_Byte* old_cursor; @@ -1090,21 +1117,27 @@ if ( !blend || !blend->num_designs ) { - error = t1_allocate_blend( face, (FT_UInt)num_designs, 0 ); + error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 ); if ( error ) goto Exit; - blend = face->blend; + blend = t1face->blend; } else if ( blend->num_designs != (FT_UInt)num_designs ) { FT_ERROR(( "parse_weight_vector:" - " /BlendDesignPosition and /WeightVector have\n" - " " + " /BlendDesignPosition and /WeightVector have\n" )); + FT_ERROR(( " " " different number of elements\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } + if ( !blend->weight_vector ) + if ( FT_QNEW_ARRAY( blend->weight_vector, num_designs * 2 ) ) + goto Exit; + + blend->default_weight_vector = blend->weight_vector + num_designs; + old_cursor = parser->root.cursor; old_limit = parser->root.limit; @@ -1135,11 +1168,15 @@ /* 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 ) + parse_buildchar( FT_Face face, /* T1_Face */ + void* loader_ ) { - face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser, - 0, NULL, 0 ); + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; + + + t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser, + 0, NULL, 0 ); #ifdef FT_DEBUG_LEVEL_TRACE { @@ -1147,7 +1184,7 @@ FT_TRACE4(( " [" )); - for ( i = 0; i < face->len_buildchar; i++ ) + for ( i = 0; i < t1face->len_buildchar; i++ ) FT_TRACE4(( " 0" )); FT_TRACE4(( "]\n" )); @@ -1283,9 +1320,9 @@ else { FT_TRACE1(( "t1_load_keyword: ignoring keyword `%s'" - " which is not valid at this point\n" - " (probably due to missing keywords)\n", + " which is not valid at this point\n", field->ident )); + FT_TRACE1(( " (probably due to missing keywords)\n" )); error = FT_Err_Ok; } @@ -1297,9 +1334,10 @@ static void - parse_private( T1_Face face, - T1_Loader loader ) + parse_private( FT_Face face, + void* loader_ ) { + T1_Loader loader = (T1_Loader)loader_; FT_UNUSED( face ); loader->keywords_encountered |= T1_PRIVATE; @@ -1363,13 +1401,14 @@ /* and `/CharStrings' dictionaries. */ static void - t1_parse_font_matrix( T1_Face face, - T1_Loader loader ) + t1_parse_font_matrix( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (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_Matrix* matrix = &t1face->type1.font_matrix; + FT_Vector* offset = &t1face->type1.font_offset; FT_Fixed temp[6]; FT_Fixed temp_scale; FT_Int result; @@ -1405,7 +1444,7 @@ if ( temp_scale != 0x10000L ) { /* set units per EM based on FontMatrix values */ - root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); + face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); temp[0] = FT_DivFix( temp[0], temp_scale ); temp[1] = FT_DivFix( temp[1], temp_scale ); @@ -1433,14 +1472,16 @@ static void - parse_encoding( T1_Face face, - T1_Loader loader ) + parse_encoding( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; T1_Parser parser = &loader->parser; FT_Byte* cur; FT_Byte* limit = parser->root.limit; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)t1face->psaux; T1_Skip_Spaces( parser ); @@ -1456,7 +1497,7 @@ /* and we must load it now */ if ( ft_isdigit( *cur ) || *cur == '[' ) { - T1_Encoding encode = &face->type1.encoding; + T1_Encoding encode = &t1face->type1.encoding; FT_Int count, array_size, n; PS_Table char_table = &loader->encoding_table; FT_Memory memory = parser->root.memory; @@ -1496,8 +1537,8 @@ /* we use a T1_Table to store our charnames */ loader->num_chars = encode->num_chars = array_size; - if ( FT_NEW_ARRAY( encode->char_index, array_size ) || - FT_NEW_ARRAY( encode->char_name, array_size ) || + if ( FT_QNEW_ARRAY( encode->char_index, array_size ) || + FT_QNEW_ARRAY( encode->char_name, array_size ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, array_size, memory ) ) ) { @@ -1638,7 +1679,7 @@ FT_TRACE4(( "]\n" )); #endif - face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; parser->root.cursor = cur; } @@ -1649,21 +1690,21 @@ if ( cur + 17 < limit && ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) { - face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; FT_TRACE4(( " StandardEncoding\n" )); } else if ( cur + 15 < limit && ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) { - face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; + t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; FT_TRACE4(( " ExpertEncoding\n" )); } else if ( cur + 18 < limit && ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) { - face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; + t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; FT_TRACE4(( " ISOLatin1Encoding\n" )); } @@ -1677,9 +1718,11 @@ static void - parse_subrs( T1_Face face, - T1_Loader loader ) + parse_subrs( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; T1_Parser parser = &loader->parser; PS_Table table = &loader->subrs; FT_Memory memory = parser->root.memory; @@ -1687,7 +1730,7 @@ FT_Int num_subrs; FT_UInt count; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)t1face->psaux; T1_Skip_Spaces( parser ); @@ -1731,14 +1774,14 @@ */ FT_TRACE0(( "parse_subrs: adjusting number of subroutines" - " (from %d to %d)\n", + " (from %d to %zu)\n", num_subrs, ( parser->root.limit - parser->root.cursor ) >> 3 )); num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3; if ( !loader->subrs_hash ) { - if ( FT_NEW( loader->subrs_hash ) ) + if ( FT_QNEW( loader->subrs_hash ) ) goto Fail; error = ft_hash_num_init( loader->subrs_hash, memory ); @@ -1819,7 +1862,7 @@ /* */ /* thanks to Tom Kacvinsky for pointing this out */ /* */ - if ( face->type1.private_dict.lenIV >= 0 ) + if ( t1face->type1.private_dict.lenIV >= 0 ) { FT_Byte* temp = NULL; @@ -1827,20 +1870,21 @@ /* some fonts define empty subr records -- this is not totally */ /* compliant to the specification (which says they should at */ /* least contain a `return'), but we support them anyway */ - if ( size < (FT_ULong)face->type1.private_dict.lenIV ) + if ( size < (FT_ULong)t1face->type1.private_dict.lenIV ) { error = FT_THROW( Invalid_File_Format ); goto Fail; } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_ALLOC( temp, size ) ) + if ( FT_DUP( temp, base, size ) ) goto Fail; - FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); - size -= (FT_ULong)face->type1.private_dict.lenIV; - error = T1_Add_Table( table, (FT_Int)idx, - temp + face->type1.private_dict.lenIV, size ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( table, + (FT_Int)idx, + temp + t1face->type1.private_dict.lenIV, + size ); FT_FREE( temp ); } else @@ -1872,9 +1916,11 @@ static void - parse_charstrings( T1_Face face, - T1_Loader loader ) + parse_charstrings( FT_Face face, /* T1_Face */ + void* loader_ ) { + T1_Face t1face = (T1_Face)face; + T1_Loader loader = (T1_Loader)loader_; T1_Parser parser = &loader->parser; PS_Table code_table = &loader->charstrings; PS_Table name_table = &loader->glyph_names; @@ -1882,7 +1928,7 @@ FT_Memory memory = parser->root.memory; FT_Error error; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)t1face->psaux; FT_Byte* cur = parser->root.cursor; FT_Byte* limit = parser->root.limit; @@ -1902,7 +1948,7 @@ if ( num_glyphs > ( limit - cur ) >> 3 ) { FT_TRACE0(( "parse_charstrings: adjusting number of glyphs" - " (from %d to %d)\n", + " (from %d to %zu)\n", num_glyphs, ( limit - cur ) >> 3 )); num_glyphs = ( limit - cur ) >> 3; } @@ -2023,34 +2069,35 @@ name_table->elements[n][len] = '\0'; /* record index of /.notdef */ - if ( *cur == '.' && + if ( *cur == '.' && ft_strcmp( ".notdef", - (const char*)(name_table->elements[n]) ) == 0 ) + (const char*)( name_table->elements[n] ) ) == 0 ) { notdef_index = n; notdef_found = 1; } - if ( face->type1.private_dict.lenIV >= 0 && + if ( t1face->type1.private_dict.lenIV >= 0 && n < num_glyphs + TABLE_EXTEND ) { FT_Byte* temp = NULL; - if ( size <= (FT_ULong)face->type1.private_dict.lenIV ) + if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV ) { error = FT_THROW( Invalid_File_Format ); goto Fail; } /* t1_decrypt() shouldn't write to base -- make temporary copy */ - if ( FT_ALLOC( temp, size ) ) + if ( FT_DUP( temp, base, size ) ) goto Fail; - FT_MEM_COPY( temp, base, size ); psaux->t1_decrypt( temp, size, 4330 ); - size -= (FT_ULong)face->type1.private_dict.lenIV; - error = T1_Add_Table( code_table, n, - temp + face->type1.private_dict.lenIV, size ); + size -= (FT_ULong)t1face->type1.private_dict.lenIV; + error = T1_Add_Table( code_table, + n, + temp + t1face->type1.private_dict.lenIV, + size ); FT_FREE( temp ); } else @@ -2236,7 +2283,7 @@ T1_FIELD_DICT_PRIVATE ) #endif - { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } + T1_FIELD_ZERO }; @@ -2297,8 +2344,8 @@ /* 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 ) + else if ( *cur == 'R' && cur + 6 < limit && *( cur + 1 ) == 'D' && + have_integer ) { FT_ULong s; FT_Byte* b; @@ -2310,8 +2357,8 @@ have_integer = 0; } - else if ( *cur == '-' && cur + 6 < limit && *(cur + 1) == '|' && - have_integer ) + else if ( *cur == '-' && cur + 6 < limit && *( cur + 1 ) == '|' && + have_integer ) { FT_ULong s; FT_Byte* b; @@ -2344,18 +2391,13 @@ T1_Field keyword = (T1_Field)t1_keywords; - for (;;) + while ( keyword->len ) { - FT_Byte* name; + FT_Byte* name = (FT_Byte*)keyword->ident; - name = (FT_Byte*)keyword->ident; - if ( !name ) - break; - - if ( cur[0] == name[0] && - len == ft_strlen( (const char *)name ) && - ft_memcmp( cur, name, len ) == 0 ) + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) { /* We found it -- run the parsing callback! */ /* We record every instance of every field */ @@ -2532,7 +2574,7 @@ { FT_ERROR(( "T1_Open_Face:" " number-of-designs != 2 ^^ number-of-axes\n" )); - T1_Done_Blend( face ); + T1_Done_Blend( FT_FACE( face ) ); } if ( face->blend && @@ -2552,9 +2594,17 @@ /* font as a normal PS font */ if ( face->blend && ( !face->blend->num_designs || !face->blend->num_axis ) ) - T1_Done_Blend( face ); + T1_Done_Blend( FT_FACE( face ) ); - /* another safety check */ + /* the font may have no valid WeightVector */ + if ( face->blend && !face->blend->weight_vector ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignPositions */ + if ( face->blend && !face->blend->design_pos[0] ) + T1_Done_Blend( FT_FACE( face ) ); + + /* the font may have no valid BlendDesignMap */ if ( face->blend ) { FT_UInt i; @@ -2563,7 +2613,7 @@ for ( i = 0; i < face->blend->num_axis; i++ ) if ( !face->blend->design_map[i].num_points ) { - T1_Done_Blend( face ); + T1_Done_Blend( FT_FACE( face ) ); break; } } diff --git a/src/thirdparty/freetype2/src/type1/t1load.h b/src/thirdparty/freetype2/src/type1/t1load.h index 44f835bde..2cd824196 100644 --- a/src/thirdparty/freetype2/src/type1/t1load.h +++ b/src/thirdparty/freetype2/src/type1/t1load.h @@ -4,7 +4,7 @@ * * Type 1 font loader (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,10 +20,9 @@ #define T1LOAD_H_ -#include -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H -#include FT_MULTIPLE_MASTERS_H +#include +#include +#include #include "t1parse.h" @@ -67,52 +66,52 @@ FT_BEGIN_HEADER #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT FT_LOCAL( FT_Error ) - T1_Get_Multi_Master( T1_Face face, + T1_Get_Multi_Master( FT_Face face, FT_Multi_Master* master ); FT_LOCAL( FT_Error ) - T1_Get_MM_Var( T1_Face face, + T1_Get_MM_Var( FT_Face face, FT_MM_Var* *master ); FT_LOCAL( FT_Error ) - T1_Set_MM_Blend( T1_Face face, + T1_Set_MM_Blend( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - T1_Get_MM_Blend( T1_Face face, + T1_Get_MM_Blend( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - T1_Set_MM_Design( T1_Face face, + T1_Set_MM_Design( FT_Face face, FT_UInt num_coords, FT_Long* coords ); FT_LOCAL( FT_Error ) - T1_Reset_MM_Blend( T1_Face face, + T1_Reset_MM_Blend( FT_Face face, FT_UInt instance_index ); FT_LOCAL( FT_Error ) - T1_Get_Var_Design( T1_Face face, + T1_Get_Var_Design( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( FT_Error ) - T1_Set_Var_Design( T1_Face face, + T1_Set_Var_Design( FT_Face face, FT_UInt num_coords, FT_Fixed* coords ); FT_LOCAL( void ) - T1_Done_Blend( T1_Face face ); + T1_Done_Blend( FT_Face face ); FT_LOCAL( FT_Error ) - T1_Set_MM_WeightVector( T1_Face face, + T1_Set_MM_WeightVector( FT_Face face, FT_UInt len, FT_Fixed* weightvector ); FT_LOCAL( FT_Error ) - T1_Get_MM_WeightVector( T1_Face face, + T1_Get_MM_WeightVector( FT_Face face, FT_UInt* len, FT_Fixed* weightvector ); diff --git a/src/thirdparty/freetype2/src/type1/t1objs.c b/src/thirdparty/freetype2/src/type1/t1objs.c index 741388a64..7f25208f8 100644 --- a/src/thirdparty/freetype2/src/type1/t1objs.c +++ b/src/thirdparty/freetype2/src/type1/t1objs.c @@ -4,7 +4,7 @@ * * Type 1 objects manager (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,12 +16,11 @@ */ -#include -#include FT_INTERNAL_CALC_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_IDS_H -#include FT_DRIVER_H +#include +#include +#include +#include +#include #include "t1gload.h" #include "t1load.h" @@ -32,8 +31,8 @@ #include "t1afm.h" #endif -#include FT_SERVICE_POSTSCRIPT_CMAPS_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include /************************************************************************** @@ -117,11 +116,15 @@ T1_Size_Request( FT_Size t1size, /* T1_Size */ FT_Size_Request req ) { + FT_Error error; + T1_Size size = (T1_Size)t1size; PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size ); - FT_Request_Metrics( size->root.face, req ); + error = FT_Request_Metrics( size->root.face, req ); + if ( error ) + goto Exit; if ( funcs ) funcs->set_scale( (PSH_Globals)t1size->internal->module_data, @@ -129,7 +132,8 @@ size->root.metrics.y_scale, 0, 0 ); - return FT_Err_Ok; + Exit: + return error; } @@ -142,7 +146,9 @@ FT_LOCAL_DEF( void ) T1_GlyphSlot_Done( FT_GlyphSlot slot ) { - slot->internal->glyph_hints = NULL; + /* `slot->internal` might be NULL in out-of-memory situations. */ + if ( slot->internal ) + slot->internal->glyph_hints = NULL; } @@ -161,8 +167,7 @@ FT_Module module; - module = FT_Get_Module( slot->face->driver->root.library, - "pshinter" ); + module = FT_Get_Module( slot->library, "pshinter" ); if ( module ) { T1_Hints_Funcs funcs; @@ -218,11 +223,10 @@ { FT_FREE( face->buildchar ); - face->buildchar = NULL; face->len_buildchar = 0; } - T1_Done_Blend( face ); + T1_Done_Blend( t1face ); face->blend = NULL; #endif @@ -285,7 +289,8 @@ * * @Input: * stream :: - * input stream where to load font data. + * Dummy argument for compatibility with the `FT_Face_InitFunc` API. + * Ignored. The stream should be passed through `face->root.stream`. * * face_index :: * The index of the font face in the resource. @@ -347,8 +352,8 @@ if ( error ) goto Exit; - FT_TRACE2(( "T1_Face_Init: %08p (index %d)\n", - face, + FT_TRACE2(( "T1_Face_Init: %p (index %d)\n", + (void *)face, face_index )); /* if we just wanted to check the format, leave successfully now */ @@ -599,11 +604,7 @@ /* set default property values, cf. `ftt1drv.h' */ -#ifdef T1_CONFIG_OPTION_OLD_ENGINE - driver->hinting_engine = FT_HINTING_FREETYPE; -#else driver->hinting_engine = FT_HINTING_ADOBE; -#endif driver->no_stem_darkening = TRUE; diff --git a/src/thirdparty/freetype2/src/type1/t1objs.h b/src/thirdparty/freetype2/src/type1/t1objs.h index 2161091f7..6c71977c1 100644 --- a/src/thirdparty/freetype2/src/type1/t1objs.h +++ b/src/thirdparty/freetype2/src/type1/t1objs.h @@ -4,7 +4,7 @@ * * Type 1 objects manager (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -21,9 +21,9 @@ #include -#include FT_INTERNAL_OBJECTS_H +#include #include FT_CONFIG_CONFIG_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type1/t1parse.c b/src/thirdparty/freetype2/src/type1/t1parse.c index 56caeb9e4..ef643e298 100644 --- a/src/thirdparty/freetype2/src/type1/t1parse.c +++ b/src/thirdparty/freetype2/src/type1/t1parse.c @@ -4,7 +4,7 @@ * * Type 1 parser (body). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -33,10 +33,9 @@ */ -#include -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include #include "t1parse.h" @@ -222,7 +221,7 @@ else { /* read segment in memory -- this is clumsy, but so does the format */ - if ( FT_ALLOC( parser->base_dict, size ) || + if ( FT_QALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; parser->base_len = size; @@ -303,8 +302,8 @@ goto Fail; } - if ( FT_STREAM_SEEK( start_pos ) || - FT_ALLOC( parser->private_dict, parser->private_len ) ) + if ( FT_STREAM_SEEK( start_pos ) || + FT_QALLOC( parser->private_dict, parser->private_len ) ) goto Fail; parser->private_len = 0; @@ -331,50 +330,25 @@ /* the private dict. Otherwise, simply overwrite into the base */ /* dictionary block in the heap. */ - /* first of all, look at the `eexec' keyword */ + /* First look for the `eexec' keyword. Ensure `eexec' is real -- */ + /* it could be in a comment or string (as e.g. in u003043t.gsf */ + /* from ghostscript). */ FT_Byte* cur = parser->base_dict; FT_Byte* limit = cur + parser->base_len; FT_Pointer pos_lf; FT_Bool test_cr; - Again: - for (;;) - { - if ( cur[0] == 'e' && - cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */ - /* whitespace + 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:" - " could not find `eexec' keyword\n" )); - error = FT_THROW( 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; - /* set limit to `eexec' + whitespace + 4 characters */ - parser->root.limit = cur + 10; + parser->root.limit = parser->base_dict + parser->base_len; cur = parser->root.cursor; limit = parser->root.limit; while ( cur < limit ) { - if ( cur[0] == 'e' && - cur + 5 < limit ) + /* 9 = 5 letters for `eexec' + whitespace + 4 chars */ + if ( cur[0] == 'e' && cur + 9 < limit ) { if ( cur[1] == 'e' && cur[2] == 'x' && @@ -390,21 +364,9 @@ 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; - - if ( cur >= limit ) - { - FT_ERROR(( "T1_Get_Private_Dict:" - " premature end in private dictionary\n" )); - error = FT_THROW( Invalid_File_Format ); - goto Exit; - } - - goto Again; + FT_ERROR(( "T1_Get_Private_Dict: could not find `eexec' keyword\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Exit; /* now determine where to write the _encrypted_ binary private */ /* dictionary. We overwrite the base dictionary for disk-based */ @@ -451,7 +413,7 @@ if ( parser->in_memory ) { /* note that we allocate one more byte to put a terminating `0' */ - if ( FT_ALLOC( parser->private_dict, size + 1 ) ) + if ( FT_QALLOC( parser->private_dict, size + 1 ) ) goto Fail; parser->private_len = size; } diff --git a/src/thirdparty/freetype2/src/type1/t1parse.h b/src/thirdparty/freetype2/src/type1/t1parse.h index dab8fddc8..f4ad426e9 100644 --- a/src/thirdparty/freetype2/src/type1/t1parse.h +++ b/src/thirdparty/freetype2/src/type1/t1parse.h @@ -4,7 +4,7 @@ * * Type 1 parser (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,9 +20,8 @@ #define T1PARSE_H_ -#include -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_STREAM_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type1/t1tokens.h b/src/thirdparty/freetype2/src/type1/t1tokens.h index 97f2dbe0c..c3736cd42 100644 --- a/src/thirdparty/freetype2/src/type1/t1tokens.h +++ b/src/thirdparty/freetype2/src/type1/t1tokens.h @@ -4,7 +4,7 @@ * * Type 1 tokenizer (specification). * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/thirdparty/freetype2/src/type42/t42drivr.c b/src/thirdparty/freetype2/src/type42/t42drivr.c index 09ad632e9..234fb16f9 100644 --- a/src/thirdparty/freetype2/src/type42/t42drivr.c +++ b/src/thirdparty/freetype2/src/type42/t42drivr.c @@ -4,7 +4,7 @@ * * High-level Type 42 driver interface (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -39,12 +39,12 @@ #include "t42drivr.h" #include "t42objs.h" #include "t42error.h" -#include FT_INTERNAL_DEBUG_H +#include -#include FT_SERVICE_FONT_FORMAT_H -#include FT_SERVICE_GLYPH_DICT_H -#include FT_SERVICE_POSTSCRIPT_NAME_H -#include FT_SERVICE_POSTSCRIPT_INFO_H +#include +#include +#include +#include #undef FT_COMPONENT #define FT_COMPONENT t42 @@ -56,33 +56,41 @@ * */ - static FT_Error - t42_get_glyph_name( T42_Face face, + FT_CALLBACK_DEF( FT_Error ) + t42_get_glyph_name( FT_Face face, /* T42_Face */ FT_UInt glyph_index, FT_Pointer buffer, FT_UInt buffer_max ) { - FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max ); + T42_Face t42face = (T42_Face)face; + + + FT_STRCPYN( buffer, + t42face->type1.glyph_names[glyph_index], + buffer_max ); return FT_Err_Ok; } - static FT_UInt - t42_get_name_index( T42_Face face, + FT_CALLBACK_DEF( FT_UInt ) + t42_get_name_index( FT_Face face, /* T42_Face */ const FT_String* glyph_name ) { - FT_Int i; + T42_Face t42face = (T42_Face)face; + FT_Int i; - for ( i = 0; i < face->type1.num_glyphs; i++ ) + for ( i = 0; i < t42face->type1.num_glyphs; i++ ) { - FT_String* gname = face->type1.glyph_names[i]; + FT_String* gname = t42face->type1.glyph_names[i]; if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) ) - return (FT_UInt)ft_strtol( (const char *)face->type1.charstrings[i], - NULL, 10 ); + return (FT_UInt)ft_strtol( + (const char *)t42face->type1.charstrings[i], + NULL, + 10 ); } return 0; @@ -102,10 +110,13 @@ * */ - static const char* - t42_get_ps_font_name( T42_Face face ) + FT_CALLBACK_DEF( const char* ) + t42_get_ps_font_name( FT_Face face ) /* T42_Face */ { - return (const char*)face->type1.font_name; + T42_Face t42face = (T42_Face)face; + + + return (const char*)t42face->type1.font_name; } @@ -121,7 +132,7 @@ * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) t42_ps_get_font_info( FT_Face face, PS_FontInfoRec* afont_info ) { @@ -131,7 +142,7 @@ } - static FT_Error + FT_CALLBACK_DEF( FT_Error ) t42_ps_get_font_extra( FT_Face face, PS_FontExtraRec* afont_extra ) { @@ -141,7 +152,7 @@ } - static FT_Int + FT_CALLBACK_DEF( FT_Int ) t42_ps_has_glyph_names( FT_Face face ) { FT_UNUSED( face ); @@ -150,22 +161,13 @@ } - static FT_Error - t42_ps_get_font_private( FT_Face face, - PS_PrivateRec* afont_private ) - { - *afont_private = ((T42_Face)face)->type1.private_dict; - - return FT_Err_Ok; - } - - static const FT_Service_PsInfoRec t42_service_ps_info = { (PS_GetFontInfoFunc) t42_ps_get_font_info, /* ps_get_font_info */ (PS_GetFontExtraFunc) t42_ps_get_font_extra, /* ps_get_font_extra */ (PS_HasGlyphNamesFunc) t42_ps_has_glyph_names, /* ps_has_glyph_names */ - (PS_GetFontPrivateFunc)t42_ps_get_font_private, /* ps_get_font_private */ + /* Type42 fonts don't have a Private dict */ + (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */ /* not implemented */ (PS_GetFontValueFunc) NULL /* ps_get_font_value */ }; diff --git a/src/thirdparty/freetype2/src/type42/t42drivr.h b/src/thirdparty/freetype2/src/type42/t42drivr.h index a35ca28f8..d286da02a 100644 --- a/src/thirdparty/freetype2/src/type42/t42drivr.h +++ b/src/thirdparty/freetype2/src/type42/t42drivr.h @@ -4,7 +4,7 @@ * * High-level Type 42 driver interface (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,7 @@ #define T42DRIVR_H_ -#include -#include FT_INTERNAL_DRIVER_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type42/t42error.h b/src/thirdparty/freetype2/src/type42/t42error.h index 5fb214394..f7c9a9403 100644 --- a/src/thirdparty/freetype2/src/type42/t42error.h +++ b/src/thirdparty/freetype2/src/type42/t42error.h @@ -4,7 +4,7 @@ * * Type 42 error codes (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -25,7 +25,7 @@ #ifndef T42ERROR_H_ #define T42ERROR_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -33,7 +33,7 @@ #define FT_ERR_PREFIX T42_Err_ #define FT_ERR_BASE FT_Mod_Err_Type42 -#include FT_ERRORS_H +#include #endif /* T42ERROR_H_ */ diff --git a/src/thirdparty/freetype2/src/type42/t42objs.c b/src/thirdparty/freetype2/src/type42/t42objs.c index d31bace45..d20917aea 100644 --- a/src/thirdparty/freetype2/src/type42/t42objs.c +++ b/src/thirdparty/freetype2/src/type42/t42objs.c @@ -4,7 +4,7 @@ * * Type 42 objects manager (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -19,9 +19,9 @@ #include "t42objs.h" #include "t42parse.h" #include "t42error.h" -#include FT_INTERNAL_DEBUG_H -#include FT_LIST_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include #undef FT_COMPONENT @@ -44,14 +44,8 @@ parser = &loader.parser; - if ( FT_ALLOC( face->ttf_data, 12 ) ) - goto Exit; - - /* while parsing the font we always update `face->ttf_size' so that */ - /* even in case of buggy data (which might lead to premature end of */ - /* scanning without causing an error) the call to `FT_Open_Face' in */ - /* `T42_Face_Init' passes the correct size */ - face->ttf_size = 12; + face->ttf_data = NULL; + face->ttf_size = 0; error = t42_parser_init( parser, face->root.stream, @@ -152,6 +146,11 @@ Exit: t42_loader_done( &loader ); + if ( error ) + { + FT_FREE( face->ttf_data ); + face->ttf_size = 0; + } return error; } @@ -510,9 +509,11 @@ error = FT_New_Size( t42face->ttf_face, &ttsize ); - t42size->ttsize = ttsize; - - FT_Activate_Size( ttsize ); + if ( !error ) + { + t42size->ttsize = ttsize; + FT_Activate_Size( ttsize ); + } return error; } @@ -582,6 +583,7 @@ FT_Face face = t42slot->face; T42_Face t42face = (T42_Face)face; FT_GlyphSlot ttslot; + FT_Memory memory = face->memory; FT_Error error = FT_Err_Ok; @@ -593,9 +595,15 @@ else { error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot ); - slot->ttslot = ttslot; + if ( !error ) + slot->ttslot = ttslot; } + /* share the loader so that the autohinter can see it */ + FT_GlyphLoader_Done( slot->ttslot->internal->loader ); + FT_FREE( slot->ttslot->internal ); + slot->ttslot->internal = t42slot->internal; + return error; } @@ -606,6 +614,8 @@ T42_GlyphSlot slot = (T42_GlyphSlot)t42slot; + /* do not destroy the inherited internal structure just yet */ + slot->ttslot->internal = NULL; FT_Done_GlyphSlot( slot->ttslot ); } @@ -648,7 +658,7 @@ FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz; - FT_TRACE1(( "T42_GlyphSlot_Load: glyph index %d\n", glyph_index )); + FT_TRACE1(( "T42_GlyphSlot_Load: glyph index %u\n", glyph_index )); /* map T42 glyph index to embedded TTF's glyph index */ glyph_index = (FT_UInt)ft_strtol( diff --git a/src/thirdparty/freetype2/src/type42/t42objs.h b/src/thirdparty/freetype2/src/type42/t42objs.h index 98300cf34..69a0fcd2f 100644 --- a/src/thirdparty/freetype2/src/type42/t42objs.h +++ b/src/thirdparty/freetype2/src/type42/t42objs.h @@ -4,7 +4,7 @@ * * Type 42 objects manager (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -19,15 +19,14 @@ #ifndef T42OBJS_H_ #define T42OBJS_H_ -#include -#include FT_FREETYPE_H -#include FT_TYPE1_TABLES_H -#include FT_INTERNAL_TYPE1_TYPES_H +#include +#include +#include #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 +#include +#include +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type42/t42parse.c b/src/thirdparty/freetype2/src/type42/t42parse.c index c47a77786..5beab0b5a 100644 --- a/src/thirdparty/freetype2/src/type42/t42parse.c +++ b/src/thirdparty/freetype2/src/type42/t42parse.c @@ -4,7 +4,7 @@ * * Type 42 font parser (body). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -18,9 +18,9 @@ #include "t42parse.h" #include "t42error.h" -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include +#include +#include /************************************************************************** @@ -34,19 +34,19 @@ static void - t42_parse_font_matrix( T42_Face face, - T42_Loader loader ); + t42_parse_font_matrix( FT_Face face, + void* loader_ ); static void - t42_parse_encoding( T42_Face face, - T42_Loader loader ); + t42_parse_encoding( FT_Face face, + void* loader_ ); static void - t42_parse_charstrings( T42_Face face, - T42_Loader loader ); + t42_parse_charstrings( FT_Face face, + void* loader_ ); static void - t42_parse_sfnts( T42_Face face, - T42_Loader loader ); + t42_parse_sfnts( FT_Face face, + void* loader_ ); /* as Type42 fonts have no Private dict, */ @@ -92,14 +92,14 @@ #undef T1CODE #define T1CODE T1_FIELD_LOCATION_BBOX - T1_FIELD_BBOX("FontBBox", xMin, 0 ) + 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 } + T1_FIELD_ZERO }; @@ -197,7 +197,7 @@ else { /* read segment in memory */ - if ( FT_ALLOC( parser->base_dict, size ) || + if ( FT_QALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; @@ -241,12 +241,14 @@ static void - t42_parse_font_matrix( T42_Face face, - T42_Loader loader ) + t42_parse_font_matrix( FT_Face face, /* T42_Face */ + void* loader_ ) { - T42_Parser parser = &loader->parser; - FT_Matrix* matrix = &face->type1.font_matrix; - FT_Vector* offset = &face->type1.font_offset; + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; + FT_Matrix* matrix = &t42face->type1.font_matrix; + FT_Vector* offset = &t42face->type1.font_offset; FT_Fixed temp[6]; FT_Fixed temp_scale; FT_Int result; @@ -299,14 +301,16 @@ static void - t42_parse_encoding( T42_Face face, - T42_Loader loader ) + t42_parse_encoding( FT_Face face, + void* loader_ ) { - T42_Parser parser = &loader->parser; + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; + T42_Parser parser = &loader->parser; FT_Byte* cur; - FT_Byte* limit = parser->root.limit; + FT_Byte* limit = parser->root.limit; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)t42face->psaux; T1_Skip_Spaces( parser ); @@ -322,7 +326,7 @@ /* and we must load it now */ if ( ft_isdigit( *cur ) || *cur == '[' ) { - T1_Encoding encode = &face->type1.encoding; + T1_Encoding encode = &t42face->type1.encoding; FT_Int count, n; PS_Table char_table = &loader->encoding_table; FT_Memory memory = parser->root.memory; @@ -363,8 +367,8 @@ /* 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 ) || + if ( FT_QNEW_ARRAY( encode->char_index, count ) || + FT_QNEW_ARRAY( encode->char_name, count ) || FT_SET_ERROR( psaux->ps_table_funcs->init( char_table, count, memory ) ) ) { @@ -493,8 +497,8 @@ T1_Skip_Spaces( parser ); } - face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; - parser->root.cursor = cur; + t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; + parser->root.cursor = cur; } /* Otherwise, we should have either `StandardEncoding', */ @@ -503,15 +507,15 @@ { if ( cur + 17 < limit && ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) - face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; + t42face->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; + t42face->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; + t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; else parser->root.error = FT_ERR( Ignore ); @@ -529,16 +533,19 @@ static void - t42_parse_sfnts( T42_Face face, - T42_Loader loader ) + t42_parse_sfnts( FT_Face face, + void* loader_ ) { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (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_Long count; + FT_Long ttf_count; + FT_Long ttf_reserved; FT_ULong n, string_size, old_string_size, real_size; FT_Byte* string_buf = NULL; @@ -546,6 +553,9 @@ T42_Load_Status status; + /** There should only be one sfnts array, but free any previous. */ + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; /* The format is */ /* */ @@ -574,7 +584,13 @@ status = BEFORE_START; string_size = 0; old_string_size = 0; - count = 0; + ttf_count = 0; + ttf_reserved = 12; + if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) ) + goto Fail; + + FT_TRACE2(( "\n" )); + FT_TRACE2(( "t42_parse_sfnts:\n" )); while ( parser->root.cursor < limit ) { @@ -586,6 +602,7 @@ if ( *cur == ']' ) { parser->root.cursor++; + t42face->ttf_size = ttf_count; goto Exit; } @@ -611,7 +628,7 @@ error = FT_THROW( Invalid_File_Format ); goto Fail; } - if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) + if ( FT_QREALLOC( string_buf, old_string_size, string_size ) ) goto Fail; allocated = 1; @@ -680,6 +697,9 @@ goto Fail; } + FT_TRACE2(( " PS string size %5lu bytes, offset 0x%08lx (%ld)\n", + string_size, ttf_count, ttf_count )); + /* The whole TTF is now loaded into `string_buf'. We are */ /* checking its contents while copying it to `ttf_data'. */ @@ -691,50 +711,64 @@ { case BEFORE_START: /* load offset table, 12 bytes */ - if ( count < 12 ) + if ( ttf_count < 12 ) { - face->ttf_data[count++] = string_buf[n]; + t42face->ttf_data[ttf_count++] = string_buf[n]; continue; } else { - num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; - status = BEFORE_TABLE_DIR; - face->ttf_size = 12 + 16 * num_tables; + FT_Long ttf_reserved_prev = ttf_reserved; - if ( (FT_Long)size < face->ttf_size ) + + num_tables = 16 * t42face->ttf_data[4] + t42face->ttf_data[5]; + status = BEFORE_TABLE_DIR; + ttf_reserved = 12 + 16 * num_tables; + + FT_TRACE2(( " SFNT directory contains %d tables\n", + num_tables )); + + if ( (FT_Long)size < ttf_reserved ) { FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); error = FT_THROW( Invalid_File_Format ); goto Fail; } - if ( FT_REALLOC( face->ttf_data, 12, face->ttf_size ) ) + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) goto Fail; } - /* fall through */ + FALL_THROUGH; case BEFORE_TABLE_DIR: /* the offset table is read; read the table directory */ - if ( count < face->ttf_size ) + if ( ttf_count < ttf_reserved ) { - face->ttf_data[count++] = string_buf[n]; + t42face->ttf_data[ttf_count++] = string_buf[n]; continue; } else { int i; FT_ULong len; + FT_Long ttf_reserved_prev = ttf_reserved; + FT_TRACE2(( "\n" )); + FT_TRACE2(( " table length\n" )); + FT_TRACE2(( " ------------------------------\n" )); + for ( i = 0; i < num_tables; i++ ) { - FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; + FT_Byte* p = t42face->ttf_data + 12 + 16 * i + 12; len = FT_PEEK_ULONG( p ); + FT_TRACE2(( " %4i 0x%08lx (%lu)\n", i, len, len )); + if ( len > size || - face->ttf_size > (FT_Long)( size - len ) ) + ttf_reserved > (FT_Long)( size - len ) ) { FT_ERROR(( "t42_parse_sfnts:" " invalid data in sfnts array\n" )); @@ -743,26 +777,31 @@ } /* Pad to a 4-byte boundary length */ - face->ttf_size += (FT_Long)( ( len + 3 ) & ~3U ); + ttf_reserved += (FT_Long)( ( len + 3 ) & ~3U ); } + ttf_reserved += 1; status = OTHER_TABLES; - if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, - face->ttf_size + 1 ) ) + FT_TRACE2(( "\n" )); + FT_TRACE2(( " allocating %ld bytes\n", ttf_reserved )); + FT_TRACE2(( "\n" )); + + if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev, + ttf_reserved ) ) goto Fail; } - /* fall through */ + FALL_THROUGH; case OTHER_TABLES: /* all other tables are just copied */ - if ( count >= face->ttf_size ) + if ( ttf_count >= ttf_reserved ) { FT_ERROR(( "t42_parse_sfnts: too much binary data\n" )); error = FT_THROW( Invalid_File_Format ); goto Fail; } - face->ttf_data[count++] = string_buf[n]; + t42face->ttf_data[ttf_count++] = string_buf[n]; } } @@ -776,15 +815,22 @@ parser->root.error = error; Exit: + if ( parser->root.error ) + { + FT_FREE( t42face->ttf_data ); + t42face->ttf_size = 0; + } if ( allocated ) FT_FREE( string_buf ); } static void - t42_parse_charstrings( T42_Face face, - T42_Loader loader ) + t42_parse_charstrings( FT_Face face, /* T42_Face */ + void* loader_ ) { + T42_Face t42face = (T42_Face)face; + T42_Loader loader = (T42_Loader)loader_; T42_Parser parser = &loader->parser; PS_Table code_table = &loader->charstrings; PS_Table name_table = &loader->glyph_names; @@ -792,7 +838,7 @@ FT_Memory memory = parser->root.memory; FT_Error error; - PSAux_Service psaux = (PSAux_Service)face->psaux; + PSAux_Service psaux = (PSAux_Service)t42face->psaux; FT_Byte* cur; FT_Byte* limit = parser->root.limit; @@ -826,7 +872,7 @@ if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 ) { FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs" - " (from %d to %d)\n", + " (from %d to %zu)\n", loader->num_glyphs, ( limit - parser->root.cursor ) >> 2 )); loader->num_glyphs = ( limit - parser->root.cursor ) >> 2; @@ -970,9 +1016,9 @@ name_table->elements[n][len] = '\0'; /* record index of /.notdef */ - if ( *cur == '.' && + if ( *cur == '.' && ft_strcmp( ".notdef", - (const char*)(name_table->elements[n]) ) == 0 ) + (const char*)( name_table->elements[n] ) ) == 0 ) { notdef_index = n; notdef_found = 1; @@ -1149,8 +1195,6 @@ { 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; @@ -1227,24 +1271,20 @@ if ( len > 0 && len < 22 && parser->root.cursor < limit ) { - int i; + T1_Field keyword = (T1_Field)t42_keywords; /* now compare the immediate name to the keyword table */ - - /* loop through all known keywords */ - for ( i = 0; i < n_keywords; i++ ) + while ( keyword->len ) { - T1_Field keyword = (T1_Field)&t42_keywords[i]; - FT_Byte *name = (FT_Byte*)keyword->ident; + FT_Byte* name = (FT_Byte*)keyword->ident; if ( !name ) continue; - if ( cur[0] == name[0] && - len == ft_strlen( (const char *)name ) && - ft_memcmp( cur, name, len ) == 0 ) + if ( keyword->len == len && + ft_memcmp( cur, name, len ) == 0 ) { /* we found it -- run the parsing callback! */ parser->root.error = t42_load_keyword( face, @@ -1254,6 +1294,8 @@ return parser->root.error; break; } + + keyword++; } } } diff --git a/src/thirdparty/freetype2/src/type42/t42parse.h b/src/thirdparty/freetype2/src/type42/t42parse.h index 0c7bb4849..f8d0a8b26 100644 --- a/src/thirdparty/freetype2/src/type42/t42parse.h +++ b/src/thirdparty/freetype2/src/type42/t42parse.h @@ -4,7 +4,7 @@ * * Type 42 font parser (specification). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -21,7 +21,7 @@ #include "t42objs.h" -#include FT_INTERNAL_POSTSCRIPT_AUX_H +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/type42/t42types.h b/src/thirdparty/freetype2/src/type42/t42types.h index a258144ec..72614b179 100644 --- a/src/thirdparty/freetype2/src/type42/t42types.h +++ b/src/thirdparty/freetype2/src/type42/t42types.h @@ -4,7 +4,7 @@ * * Type 42 font data types (specification only). * - * Copyright (C) 2002-2019 by + * Copyright (C) 2002-2025 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, @@ -20,11 +20,10 @@ #define T42TYPES_H_ -#include -#include FT_FREETYPE_H -#include FT_TYPE1_TABLES_H -#include FT_INTERNAL_TYPE1_TYPES_H -#include FT_INTERNAL_POSTSCRIPT_HINTS_H +#include +#include +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/freetype2/src/winfonts/fnterrs.h b/src/thirdparty/freetype2/src/winfonts/fnterrs.h index af29307c7..9eae20aae 100644 --- a/src/thirdparty/freetype2/src/winfonts/fnterrs.h +++ b/src/thirdparty/freetype2/src/winfonts/fnterrs.h @@ -4,7 +4,7 @@ * * Win FNT/FON error codes (specification only). * - * Copyright (C) 2001-2019 by + * Copyright (C) 2001-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,7 +26,7 @@ #ifndef FNTERRS_H_ #define FNTERRS_H_ -#include FT_MODULE_ERRORS_H +#include #undef FTERRORS_H_ @@ -34,7 +34,7 @@ #define FT_ERR_PREFIX FNT_Err_ #define FT_ERR_BASE FT_Mod_Err_Winfonts -#include FT_ERRORS_H +#include #endif /* FNTERRS_H_ */ diff --git a/src/thirdparty/freetype2/src/winfonts/winfnt.c b/src/thirdparty/freetype2/src/winfonts/winfnt.c index 2d771be2c..2653a2ecc 100644 --- a/src/thirdparty/freetype2/src/winfonts/winfnt.c +++ b/src/thirdparty/freetype2/src/winfonts/winfnt.c @@ -4,7 +4,7 @@ * * FreeType font driver for Windows FNT/FON files * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * Copyright 2003 Huw D M Davies for Codeweavers * Copyright 2007 Dmitry Timoshkov for Codeweavers @@ -18,17 +18,16 @@ */ -#include -#include FT_WINFONTS_H -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_OBJECTS_H -#include FT_TRUETYPE_IDS_H +#include +#include +#include +#include +#include #include "winfnt.h" #include "fnterrs.h" -#include FT_SERVICE_WINFNT_H -#include FT_SERVICE_FONT_FORMAT_H +#include +#include /************************************************************************** * @@ -218,7 +217,11 @@ /* first of all, read the FNT header */ if ( FT_STREAM_SEEK( font->offset ) || FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) ) + { + FT_TRACE2(( " not a Windows FNT file\n" )); + error = FT_THROW( Unknown_File_Format ); goto Exit; + } /* check header */ if ( header->version != 0x200 && @@ -285,7 +288,10 @@ /* does it begin with an MZ header? */ if ( FT_STREAM_SEEK( 0 ) || FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) ) + { + error = FT_ERR( Unknown_File_Format ); goto Exit; + } error = FT_ERR( Unknown_File_Format ); if ( mz_header.magic == WINFNT_MZ_MAGIC ) @@ -331,7 +337,7 @@ { FT_TRACE2(( "invalid alignment shift count for resource data\n" )); error = FT_THROW( Invalid_File_Format ); - goto Exit; + goto Exit1; } @@ -346,11 +352,15 @@ count = FT_GET_USHORT_LE(); + FT_TRACE2(( type_id == 0x8007U ? "RT_FONTDIR count %hu\n" : + type_id == 0x8008U ? "RT_FONT count %hu\n" : "", + count )); + if ( type_id == 0x8008U ) { font_count = count; - font_offset = FT_STREAM_POS() + 4 + - (FT_ULong)( stream->cursor - stream->limit ); + font_offset = FT_STREAM_POS() + 4 - + (FT_ULong)( stream->limit - stream->cursor ); break; } @@ -421,12 +431,12 @@ 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", + "size_of_optional_header %02x\n", pe32_header.magic, pe32_header.machine, pe32_header.number_of_sections, - pe32_header.size_of_optional_header, + pe32_header.size_of_optional_header )); + FT_TRACE2(( "magic32 %02x, rsrc_virtual_address %04lx, " + "rsrc_size %04lx\n", pe32_header.magic32, pe32_header.rsrc_virtual_address, pe32_header.rsrc_size )); @@ -479,7 +489,7 @@ &dir_entry1 ) ) goto Exit; - if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) + if ( !( dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) { error = FT_THROW( Invalid_File_Format ); goto Exit; @@ -503,7 +513,7 @@ &dir_entry2 ) ) goto Exit; - if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) + if ( !( dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) { error = FT_THROW( Invalid_File_Format ); goto Exit; @@ -597,6 +607,10 @@ Exit: return error; + + Exit1: + FT_FRAME_EXIT(); + goto Exit; } @@ -610,31 +624,34 @@ static FT_Error - fnt_cmap_init( FNT_CMap cmap, + fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */ FT_Pointer pointer ) { - FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); - FNT_Font font = face->font; + FNT_CMap fntcmap = (FNT_CMap)cmap; + FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap ); + FNT_Font font = face->font; FT_UNUSED( pointer ); - cmap->first = (FT_UInt32) font->header.first_char; - cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 ); + fntcmap->first = (FT_UInt32)font->header.first_char; + fntcmap->count = (FT_UInt32)( font->header.last_char - + fntcmap->first + 1 ); return 0; } static FT_UInt - fnt_cmap_char_index( FNT_CMap cmap, + fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */ FT_UInt32 char_code ) { - FT_UInt gindex = 0; + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; - char_code -= cmap->first; - if ( char_code < cmap->count ) + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) /* we artificially increase the glyph index; */ /* FNT_Load_Glyph reverts to the right one */ gindex = (FT_UInt)( char_code + 1 ); @@ -642,26 +659,27 @@ } - static FT_UInt32 - fnt_cmap_char_next( FNT_CMap cmap, + static FT_UInt + fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */ FT_UInt32 *pchar_code ) { - FT_UInt gindex = 0; - FT_UInt32 result = 0; + FNT_CMap fntcmap = (FNT_CMap)cmap; + FT_UInt gindex = 0; + FT_UInt32 result = 0; FT_UInt32 char_code = *pchar_code + 1; - if ( char_code <= cmap->first ) + if ( char_code <= fntcmap->first ) { - result = cmap->first; + result = fntcmap->first; gindex = 1; } else { - char_code -= cmap->first; - if ( char_code < cmap->count ) + char_code -= fntcmap->first; + if ( char_code < fntcmap->count ) { - result = cmap->first + char_code; + result = fntcmap->first + char_code; gindex = (FT_UInt)( char_code + 1 ); } } @@ -790,7 +808,7 @@ root->style_flags |= FT_STYLE_FLAG_BOLD; /* set up the `fixed_sizes' array */ - if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) + if ( FT_QNEW( root->available_sizes ) ) goto Fail; root->num_fixed_sizes = 1; @@ -882,10 +900,10 @@ } 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. */ + /* 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 ) ) + if ( FT_QALLOC( font->family_name, family_size + 1 ) ) goto Fail; FT_MEM_COPY( font->family_name, @@ -894,9 +912,10 @@ font->family_name[family_size] = '\0'; - if ( FT_REALLOC( font->family_name, - family_size, - ft_strlen( font->family_name ) + 1 ) ) + /* shrink it to the actual length */ + if ( FT_QREALLOC( font->family_name, + family_size + 1, + ft_strlen( font->family_name ) + 1 ) ) goto Fail; root->family_name = font->family_name; @@ -987,7 +1006,7 @@ FT_UInt glyph_index, FT_Int32 load_flags ) { - FNT_Face face = (FNT_Face)FT_SIZE_FACE( size ); + FNT_Face face = (FNT_Face)size->face; FNT_Font font; FT_Error error = FT_Err_Ok; FT_Byte* p; @@ -1012,7 +1031,7 @@ goto Exit; } - FT_TRACE1(( "FNT_Load_Glyph: glyph index %d\n", glyph_index )); + FT_TRACE1(( "FNT_Load_Glyph: glyph index %u\n", glyph_index )); if ( glyph_index > 0 ) glyph_index--; /* revert to real index */ @@ -1091,7 +1110,7 @@ /* 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, bitmap->rows, pitch ) ) + if ( FT_QALLOC_MULT( bitmap->buffer, bitmap->rows, pitch ) ) goto Exit; column = (FT_Byte*)bitmap->buffer; diff --git a/src/thirdparty/freetype2/src/winfonts/winfnt.h b/src/thirdparty/freetype2/src/winfonts/winfnt.h index b628ad4c4..56706450f 100644 --- a/src/thirdparty/freetype2/src/winfonts/winfnt.h +++ b/src/thirdparty/freetype2/src/winfonts/winfnt.h @@ -4,7 +4,7 @@ * * FreeType font driver for Windows FNT/FON files * - * Copyright (C) 1996-2019 by + * Copyright (C) 1996-2025 by * David Turner, Robert Wilhelm, and Werner Lemberg. * Copyright 2007 Dmitry Timoshkov for Codeweavers * @@ -21,9 +21,8 @@ #define WINFNT_H_ -#include -#include FT_WINFONTS_H -#include FT_INTERNAL_DRIVER_H +#include +#include FT_BEGIN_HEADER diff --git a/src/thirdparty/harfbuzz/config.h b/src/thirdparty/harfbuzz/config.h index b6871c856..82ce2c4c3 100644 --- a/src/thirdparty/harfbuzz/config.h +++ b/src/thirdparty/harfbuzz/config.h @@ -10,4 +10,5 @@ #undef HB_NO_FACE_COLLECT_UNICODES #undef HB_NO_METRICS #undef HB_NO_LAYOUT_COLLECT_GLYPHS +#undef HB_NO_PAINT #define HAVE_FREETYPE