├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── check.py ├── fonts ├── AdobeVFPrototype-Subset.otf ├── FDArrayTest257.otf ├── FDArrayTest65535.otf ├── NotoSansBalinese-Regular.ttf ├── NotoSansKannada-Regular.ttf ├── NotoSerifKannada-Regular.ttf ├── Selawik-README.md ├── Selawik-variable.ttf ├── TestAVAR.ttf ├── TestCFFThree.otf ├── TestCMAP13.ttf ├── TestCMAP14.otf ├── TestCMAPMacTurkish.ttf ├── TestCVARGVAROne.ttf ├── TestCVARGVARTwo.ttf ├── TestGLYFOne.ttf ├── TestGPOSFour.ttf ├── TestGPOSOne.ttf ├── TestGPOSThree.ttf ├── TestGPOSTwo.otf ├── TestGSUBOne.otf ├── TestGSUBThree.ttf ├── TestGVAR-Composite-0.ttf ├── TestGVAR-Composite-Missing.ttf ├── TestGVAREight.ttf ├── TestGVARFour.ttf ├── TestGVARNine.ttf ├── TestGVAROne.ttf ├── TestGVARThree.ttf ├── TestGVARTwo.ttf ├── TestHVAROne.otf ├── TestHVARTwo.ttf ├── TestKERNOne.otf ├── TestMORXEight.ttf ├── TestMORXEighteen.ttf ├── TestMORXEleven.ttf ├── TestMORXForty.ttf ├── TestMORXFour.ttf ├── TestMORXFourteen.ttf ├── TestMORXFourtyone.ttf ├── TestMORXNine.ttf ├── TestMORXOne.ttf ├── TestMORXSeventeen.ttf ├── TestMORXSixteen.ttf ├── TestMORXTen.ttf ├── TestMORXThirteen.ttf ├── TestMORXThirtyeight.ttf ├── TestMORXThirtyfive.ttf ├── TestMORXThirtyfour.ttf ├── TestMORXThirtynine.ttf ├── TestMORXThirtyone.ttf ├── TestMORXThirtyseven.ttf ├── TestMORXThirtysix.ttf ├── TestMORXThirtythree.ttf ├── TestMORXThirtytwo.ttf ├── TestMORXThree.ttf ├── TestMORXTwelve.ttf ├── TestMORXTwenty.ttf ├── TestMORXTwentyeight.ttf ├── TestMORXTwentyfive.ttf ├── TestMORXTwentyfour.ttf ├── TestMORXTwentynine.ttf ├── TestMORXTwentyone.ttf ├── TestMORXTwentyseven.ttf ├── TestMORXTwentysix.ttf ├── TestMORXTwentythree.ttf ├── TestMORXTwentytwo.ttf ├── TestMORXTwo.ttf ├── TestRVRN-CFF2.otf ├── TestRVRN.ttf ├── TestSFNTOne.otf ├── TestSFNTTwo.ttf ├── TestSVGgradientTransform.otf ├── TestSVGgzip.otf ├── TestSVGmultiGlyphs.otf ├── TestShapeAran.ttf ├── TestShapeEthi.ttf ├── TestShapeKndaV3.ttf ├── TestShapeLana.ttf ├── TestTRAKOne.ttf ├── TestVRTR-CID-Regular.otf ├── TestVRTR-Regular.otf ├── TestVRTR-TTF-Regular.ttf └── Zycon.ttf ├── package.json ├── reports ├── Allsorts.html ├── CoreText.html ├── FreeStack.html ├── OpenType.js.html ├── TehreerStack.html └── fontkit.html ├── src ├── CMakeLists.txt ├── fonttest │ ├── CMakeLists.txt │ ├── coretext_engine.h │ ├── coretext_engine.mm │ ├── coretext_font.h │ ├── coretext_font.mm │ ├── coretext_line.h │ ├── coretext_line.mm │ ├── coretext_path.h │ ├── coretext_path.mm │ ├── font.h │ ├── font_engine.cpp │ ├── font_engine.h │ ├── freestack_engine.cpp │ ├── freestack_engine.h │ ├── freestack_font.cpp │ ├── freestack_font.h │ ├── freestack_line.cpp │ ├── freestack_line.h │ ├── freestack_path.cpp │ ├── freestack_path.h │ ├── main.cpp │ ├── tehreerstack_engine.cpp │ ├── tehreerstack_engine.h │ ├── tehreerstack_line.cpp │ ├── tehreerstack_line.h │ ├── test_harness.cpp │ └── test_harness.h └── third_party │ ├── fontkit │ └── render │ ├── freetype │ └── CMakeLists.txt │ ├── fribidi │ ├── CMakeLists.txt │ ├── LICENSE.txt │ ├── generated │ │ ├── arabic-shaping.tab.i │ │ ├── bidi-type.tab.i │ │ ├── brackets-type.tab.i │ │ ├── brackets.tab.i │ │ ├── fribidi-unicode-version.h │ │ ├── joining-type.tab.i │ │ └── mirroring.tab.i │ ├── include │ │ └── fribidi-config.h │ └── update_generated.sh │ ├── harfbuzz │ ├── CMakeLists.txt │ ├── LICENSE.txt │ └── autoconf_generated │ │ └── hb-version.h │ ├── raqm │ ├── CMakeLists.txt │ ├── LICENSE.txt │ └── generated │ │ └── raqm-version.h │ ├── sheenbidi │ └── CMakeLists.txt │ └── sheenfigure │ └── CMakeLists.txt ├── svgutil.py ├── svgutil_test.py └── testcases ├── AVAR-1.html ├── CFF-1.html ├── CFF-2.html ├── CFF-3.html ├── CFF2-1.html ├── CMAP-1.html ├── CMAP-2.html ├── CMAP-3.html ├── CMAP-4.html ├── CVAR-1.html ├── CVAR-2.html ├── GLYF-1.html ├── GPOS-1.html ├── GPOS-2.html ├── GPOS-3.html ├── GPOS-4.html ├── GPOS-5.html ├── GSUB-1.html ├── GSUB-2.html ├── GSUB-3.html ├── GVAR-1.html ├── GVAR-2.html ├── GVAR-3.html ├── GVAR-4.html ├── GVAR-5.html ├── GVAR-6.html ├── GVAR-7.html ├── GVAR-8.html ├── GVAR-9.html ├── HVAR-1.html ├── HVAR-2.html ├── KERN-1.html ├── KERN-2.html ├── MORX-1.html ├── MORX-10.html ├── MORX-11.html ├── MORX-12.html ├── MORX-13.html ├── MORX-14.html ├── MORX-16.html ├── MORX-17.html ├── MORX-18.html ├── MORX-19.html ├── MORX-2.html ├── MORX-20.html ├── MORX-21.html ├── MORX-22.html ├── MORX-23.html ├── MORX-24.html ├── MORX-25.html ├── MORX-26.html ├── MORX-27.html ├── MORX-28.html ├── MORX-29.html ├── MORX-3.html ├── MORX-30.html ├── MORX-31.html ├── MORX-32.html ├── MORX-33.html ├── MORX-34.html ├── MORX-35.html ├── MORX-36.html ├── MORX-37.html ├── MORX-38.html ├── MORX-39.html ├── MORX-4.html ├── MORX-40.html ├── MORX-41.html ├── MORX-5.html ├── MORX-6.html ├── MORX-7.html ├── MORX-8.html ├── MORX-9.html ├── SFNT-1.html ├── SFNT-2.html ├── SHARAN-1.html ├── SHBALI-1.html ├── SHBALI-2.html ├── SHBALI-3.html ├── SHKNDA-1.html ├── SHKNDA-2.html ├── SHKNDA-3.html ├── SHLANA-1.html ├── SHLANA-10.html ├── SHLANA-2.html ├── SHLANA-3.html ├── SHLANA-4.html ├── SHLANA-5.html ├── SHLANA-6.html ├── SHLANA-7.html ├── SHLANA-8.html ├── SHLANA-9.html ├── index.html └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.a 4 | *.pyc 5 | node_modules/ 6 | build/ 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/third_party/freetype/freetype2"] 2 | path = src/third_party/freetype/freetype2 3 | url = git://git.sv.nongnu.org/freetype/freetype2.git 4 | [submodule "src/third_party/harfbuzz/harfbuzz"] 5 | path = src/third_party/harfbuzz/harfbuzz 6 | url = https://github.com/behdad/harfbuzz.git 7 | [submodule "src/third_party/fribidi/fribidi"] 8 | path = src/third_party/fribidi/fribidi 9 | url = https://github.com/fribidi/fribidi.git 10 | [submodule "src/third_party/raqm/libraqm"] 11 | path = src/third_party/raqm/libraqm 12 | url = https://github.com/HOST-Oman/libraqm.git 13 | [submodule "src/third_party/sheenbidi/sheenbidi"] 14 | path = src/third_party/sheenbidi/sheenbidi 15 | url = https://github.com/Tehreer/SheenBidi.git 16 | [submodule "src/third_party/sheenfigure/sheenfigure"] 17 | path = src/third_party/sheenfigure/sheenfigure 18 | url = https://github.com/Tehreer/SheenFigure.git 19 | [submodule "src/third_party/allsorts/allsorts-tools"] 20 | path = src/third_party/allsorts/allsorts-tools 21 | url = https://github.com/yeslogic/allsorts-tools 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | UNICODE LICENSE V3 2 | 3 | COPYRIGHT AND PERMISSION NOTICE 4 | 5 | Copyright © 2016-2024 Unicode, Inc. 6 | 7 | NOTICE TO USER: Carefully read the following legal agreement. BY 8 | DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR 9 | SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE 10 | TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT 11 | DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a 14 | copy of data files and any associated documentation (the "Data Files") or 15 | software and any associated documentation (the "Software") to deal in the 16 | Data Files or Software without restriction, including without limitation 17 | the rights to use, copy, modify, merge, publish, distribute, and/or sell 18 | copies of the Data Files or Software, and to permit persons to whom the 19 | Data Files or Software are furnished to do so, provided that either (a) 20 | this copyright and permission notice appear with all copies of the Data 21 | Files or Software, or (b) this copyright and permission notice appear in 22 | associated Documentation. 23 | 24 | THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 25 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 27 | THIRD PARTY RIGHTS. 28 | 29 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE 30 | BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, 31 | OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 32 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 33 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA 34 | FILES OR SOFTWARE. 35 | 36 | Except as contained in this notice, the name of a copyright holder shall 37 | not be used in advertising or otherwise to promote the sale, use or other 38 | dealings in these Data Files or Software without prior written 39 | authorization of the copyright holder. 40 | 41 | SPDX-License-Identifier: Unicode-3.0 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Text rendering tests 2 | 3 | This is a test suite for text rendering engines. It is not easy to correctly 4 | display text, so we founded this project to help implementations to 5 | get this right. 6 | 7 | ```bash 8 | $ brew install cmake ninja npm rust 9 | $ git clone --recursive https://github.com/unicode-org/text-rendering-tests.git 10 | $ cd text-rendering-tests 11 | $ for engine in CoreText FreeStack TehreerStack fontkit OpenType.js Allsorts ; do python3 check.py --engine=$engine --output=reports/$engine.html ; done 12 | ``` 13 | 14 | 15 | ## Supported Platforms 16 | 17 | Currently, the test suite supports six OpenType implementations: 18 | 19 | * With `--engine=FreeStack`, the tests are run on the free/libre 20 | open-source text rendering stack with [FreeType](https://www.freetype.org/), 21 | [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/), 22 | [FriBidi](https://www.fribidi.org/), 23 | and [Raqm](https://github.com/HOST-Oman/libraqm). These libraries 24 | are used by Linux, Android, ChromeOS, and many other systems. 25 | — [Test report for FreeStack](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/FreeStack.html). 26 | 27 | * With `--engine=CoreText`, the tests are run on Apple’s CoreText. 28 | This option will work only if you run the test suite on MacOS X. 29 | — [Test report for CoreText](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/CoreText.html). 30 | 31 | * With `--engine=TehreerStack`, the tests are run on an open-source 32 | text rendering stack consisting of [FreeType](https://www.freetype.org/), 33 | [SheenBidi](https://github.com/Tehreer/SheenBidi), and 34 | [SheenFigure](https://github.com/Tehreer/SheenFigure). 35 | — [Test report for TehreerStack](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/TehreerStack.html). 36 | 37 | * With `--engine=fontkit`, the tests are run on 38 | [fontkit](http://github.com/devongovett/fontkit), a JavaScript font engine. 39 | — [Test report for fontkit](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/fontkit.html). 40 | 41 | * With `--engine=OpenType.js`, the tests are run using [OpenType.js](https://github.com/nodebox/opentype.js), another JavaScript font engine. 42 | — [Test report for OpenType.js](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/OpenType.js.html). 43 | 44 | * With `--engine=Allsorts`, the tests are run using [Allsorts](https://github.com/yeslogic/allsorts), 45 | a parsing and shaping engine implemented in [Rust](https://www.rust-lang.org/). 46 | — [Test report for Allsorts](https://rawgit.com/unicode-org/text-rendering-tests/master/reports/Allsorts.html). 47 | 48 | It’s trivial to test other implementations; simply write a small 49 | wrapper tool. For the [Go font 50 | library](https://godoc.org/golang.org/x/image/font/sfnt), see 51 | [here](https://github.com/golang/go/issues/20208). For the [Rust font 52 | library](https://github.com/google/font-rs), see 53 | [here](https://github.com/google/font-rs/issues/17). 54 | 55 | 56 | ## Test Cases 57 | 58 | The test cases are defined in the [testcases](testcases/) directory. 59 | It contains HTML snippets which describe each test, and define the 60 | rendering parameters together with the expected result. 61 | 62 | For each test case, the `check.py` script parses the HTML snippet to 63 | extract the rendering parameters. Then, it runs a sub-process (written 64 | in C++, Objective C, Rust or JavaScript depending on the tested 65 | implementation) that writes the observed rendering in SVG format to 66 | Standard Output. Finally, the script checks whether the expected 67 | rendering matches the observed result. Currently, “matching” is 68 | implemented by iterating over SVG paths, allowing for maximally 1 font 69 | design unit of difference. 70 | 71 | ### Copyright & Licenses 72 | 73 | Copyright © 2016-2024 Unicode, Inc. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the United States and other countries. 74 | 75 | A CLA is required to contribute to this project - please refer to the [CONTRIBUTING.md](https://github.com/unicode-org/.github/blob/main/.github/CONTRIBUTING.md) file (or start a Pull Request) for more information. 76 | 77 | The contents of this repository are governed by the Unicode [Terms of Use](https://www.unicode.org/copyright.html) and are released under [LICENSE](./LICENSE). 78 | -------------------------------------------------------------------------------- /fonts/AdobeVFPrototype-Subset.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/AdobeVFPrototype-Subset.otf -------------------------------------------------------------------------------- /fonts/FDArrayTest257.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/FDArrayTest257.otf -------------------------------------------------------------------------------- /fonts/FDArrayTest65535.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/FDArrayTest65535.otf -------------------------------------------------------------------------------- /fonts/NotoSansBalinese-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/NotoSansBalinese-Regular.ttf -------------------------------------------------------------------------------- /fonts/NotoSansKannada-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/NotoSansKannada-Regular.ttf -------------------------------------------------------------------------------- /fonts/NotoSerifKannada-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/NotoSerifKannada-Regular.ttf -------------------------------------------------------------------------------- /fonts/Selawik-README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | This version of Selawik is a test case and demonstration of OpenType 1.8 Font Variations technology and tables. It also includes some handy debugging characters. 3 | 4 | This version of Selawik is intended for testing only, and is not recommended for shipping in applications, etc. For that, it is better to use the main branch of [Selawik](https://github.com/Microsoft/Selawik). 5 | 6 | # Features 7 | 8 | * Full TrueType hinting with VTT source tables included. See [Hinting](#hinting) for details. 9 | * All tables required for OpenType 1.8 are present (see [Table Status](#table-status), below). This includes cvar (varied CVTs), GPOS/GDEF (kerning varies), and avar (coordinate space warping to match Segoe UI). 10 | 11 | Note: This version of Selawik does not include an MVAR because its vertical metrics do not change anywhere in the design space, thus there is no need for MVAR. A future release will contain an axis that varies vertical metrics as an excuse to have an MVAR. 12 | 13 | * Numerous interesting debugging glyphs (requires liga to be enabled). For example, \axis1 will show the current normalized wght coordinate. See [Debugging Glyphs](#debugging-glyphs) for details. 14 | * 1 axis: weight 15 | 16 | ## Table status 17 | The following tables are currently supported: 18 | 19 | - [x] fvar 20 | - [x] gvar 21 | - [x] cvar 22 | - [x] avar (to match Segoe UI weights and metrics) 23 | - [x] STAT 24 | - [x] GPOS/GDEF - kerning 25 | - [x] HVAR 26 | 27 | Not yet complete: 28 | 29 | - [ ] GSUB/GDEF - to change dollar signs in the bold 30 | - [ ] MVAR (future release) 31 | 32 | ## To do 33 | * Add a second axis that varies vertical metrics so we need an MVAR table. This axis will not be one of the standard axes listed in the [OpenType 1.8 specification] (https://www.microsoft.com/typography/otspec/fvar.htm), so that it becomes an example of out to do a foundry-defined axis. 34 | * Add Feature Variations (GPOS/GDEF) to switch dollar sign glyphs across weights. 35 | 36 | 37 | # Debugging glyphs 38 | Thanks to Greg Hitchcock's TrueType coding wizardry, this font includes many glyphs that are helpful for debugging implementations of variable fonts. It has a number of substitutions implemented as liga features: 39 | 40 | Feature | Description 41 | -------- | ---------- 42 | \axis1 | Shows the normalized coordinate on the wght axis for the currently selected instance (e.g. 1.0 for bold, -1.0 for light, or something in between). 43 | \axis2 | Shows 0 because this font doesn't yet have a second axis. 44 | \axis1hex | Same as \axis1 but in hex. 45 | \axis2hex | Same as \axis2 but in hex. 46 | \pointsize | Shows the point size passed to the TrueType rasterizer. Note that depending on how the application calls the rasterizer, this may not be what you expect - e.g. on Safari on MacOS, this is always 1024. 47 | \ppem | Shows the pixels per em passed to the TrueType rastersize. Note that depending on how the application calls the rasterizer, this may not be what you expect - e.g. on Safari on MacOS, this is always 1024. 48 | \ttversion | Shows the version of the TrueType rasterizer. 49 | \ttmode | Shows the current TrueType rasterizer mode flags. 50 | \boldtest | A glyph to help you detect artificial emboldening. The glyph has a vertical bar and a circle. The vertical bar's weight varies with the weight of the rest of the font: it gets bolder at bolder weights, lighter at lighter weights. The circle changes weight (and size) in opposition to the rest of the font: lighter at bold weights and vice versa. Thus, if you use this character and see both the circle and bar look bold, you're not looking at a true bold instance, but an algorithmically emboldened one. 51 | \family | Shows the family name of the font. 52 | \version | Shows the version of this font 53 | 54 | 55 | 56 | 57 | # Hinting 58 | This version of Selawik is primarily hinted with the light Latin hinting style Microsoft recommends for variable Latin fonts. The VTT Light Latin autohinter was used to create the first round of hints, which were then reviewed and touched up. 59 | 60 | This hinting style only uses CVTs for vertical metrics anchors (ascender, descender, cap height, x-height, and baseline). While this makes for an easy job hinting a Latin font, it makes for a poor test case because Selawik doesn't vary vertical metrics with weight, thus doesn't vary CVTs, thus doesn't need a cvar. So, to make it more interesting, we added CVT-based stem hints to the lowercase only. This provided the need to vary CVTs and thus require a cvar. Note that this was only done for testing purposes. For variable fonts, Microsoft recommends the light hinting style using the `ResYDist()` command instead of a CVT-based stem hint. 61 | -------------------------------------------------------------------------------- /fonts/Selawik-variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/Selawik-variable.ttf -------------------------------------------------------------------------------- /fonts/TestAVAR.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestAVAR.ttf -------------------------------------------------------------------------------- /fonts/TestCFFThree.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCFFThree.otf -------------------------------------------------------------------------------- /fonts/TestCMAP13.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCMAP13.ttf -------------------------------------------------------------------------------- /fonts/TestCMAP14.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCMAP14.otf -------------------------------------------------------------------------------- /fonts/TestCMAPMacTurkish.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCMAPMacTurkish.ttf -------------------------------------------------------------------------------- /fonts/TestCVARGVAROne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCVARGVAROne.ttf -------------------------------------------------------------------------------- /fonts/TestCVARGVARTwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestCVARGVARTwo.ttf -------------------------------------------------------------------------------- /fonts/TestGLYFOne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGLYFOne.ttf -------------------------------------------------------------------------------- /fonts/TestGPOSFour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGPOSFour.ttf -------------------------------------------------------------------------------- /fonts/TestGPOSOne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGPOSOne.ttf -------------------------------------------------------------------------------- /fonts/TestGPOSThree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGPOSThree.ttf -------------------------------------------------------------------------------- /fonts/TestGPOSTwo.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGPOSTwo.otf -------------------------------------------------------------------------------- /fonts/TestGSUBOne.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGSUBOne.otf -------------------------------------------------------------------------------- /fonts/TestGSUBThree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGSUBThree.ttf -------------------------------------------------------------------------------- /fonts/TestGVAR-Composite-0.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVAR-Composite-0.ttf -------------------------------------------------------------------------------- /fonts/TestGVAR-Composite-Missing.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVAR-Composite-Missing.ttf -------------------------------------------------------------------------------- /fonts/TestGVAREight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVAREight.ttf -------------------------------------------------------------------------------- /fonts/TestGVARFour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVARFour.ttf -------------------------------------------------------------------------------- /fonts/TestGVARNine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVARNine.ttf -------------------------------------------------------------------------------- /fonts/TestGVAROne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVAROne.ttf -------------------------------------------------------------------------------- /fonts/TestGVARThree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVARThree.ttf -------------------------------------------------------------------------------- /fonts/TestGVARTwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestGVARTwo.ttf -------------------------------------------------------------------------------- /fonts/TestHVAROne.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestHVAROne.otf -------------------------------------------------------------------------------- /fonts/TestHVARTwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestHVARTwo.ttf -------------------------------------------------------------------------------- /fonts/TestKERNOne.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestKERNOne.otf -------------------------------------------------------------------------------- /fonts/TestMORXEight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXEight.ttf -------------------------------------------------------------------------------- /fonts/TestMORXEighteen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXEighteen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXEleven.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXEleven.ttf -------------------------------------------------------------------------------- /fonts/TestMORXForty.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXForty.ttf -------------------------------------------------------------------------------- /fonts/TestMORXFour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXFour.ttf -------------------------------------------------------------------------------- /fonts/TestMORXFourteen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXFourteen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXFourtyone.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXFourtyone.ttf -------------------------------------------------------------------------------- /fonts/TestMORXNine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXNine.ttf -------------------------------------------------------------------------------- /fonts/TestMORXOne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXOne.ttf -------------------------------------------------------------------------------- /fonts/TestMORXSeventeen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXSeventeen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXSixteen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXSixteen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirteen.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirteen.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtyeight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtyeight.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtyfive.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtyfive.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtyfour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtyfour.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtynine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtynine.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtyone.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtyone.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtyseven.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtyseven.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtysix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtysix.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtythree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtythree.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThirtytwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThirtytwo.ttf -------------------------------------------------------------------------------- /fonts/TestMORXThree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXThree.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwelve.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwelve.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwenty.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwenty.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentyeight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentyeight.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentyfive.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentyfive.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentyfour.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentyfour.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentynine.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentynine.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentyone.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentyone.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentyseven.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentyseven.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentysix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentysix.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentythree.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentythree.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwentytwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwentytwo.ttf -------------------------------------------------------------------------------- /fonts/TestMORXTwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestMORXTwo.ttf -------------------------------------------------------------------------------- /fonts/TestRVRN-CFF2.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestRVRN-CFF2.otf -------------------------------------------------------------------------------- /fonts/TestRVRN.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestRVRN.ttf -------------------------------------------------------------------------------- /fonts/TestSFNTOne.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestSFNTOne.otf -------------------------------------------------------------------------------- /fonts/TestSFNTTwo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestSFNTTwo.ttf -------------------------------------------------------------------------------- /fonts/TestSVGgradientTransform.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestSVGgradientTransform.otf -------------------------------------------------------------------------------- /fonts/TestSVGgzip.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestSVGgzip.otf -------------------------------------------------------------------------------- /fonts/TestSVGmultiGlyphs.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestSVGmultiGlyphs.otf -------------------------------------------------------------------------------- /fonts/TestShapeAran.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestShapeAran.ttf -------------------------------------------------------------------------------- /fonts/TestShapeEthi.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestShapeEthi.ttf -------------------------------------------------------------------------------- /fonts/TestShapeKndaV3.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestShapeKndaV3.ttf -------------------------------------------------------------------------------- /fonts/TestShapeLana.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestShapeLana.ttf -------------------------------------------------------------------------------- /fonts/TestTRAKOne.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestTRAKOne.ttf -------------------------------------------------------------------------------- /fonts/TestVRTR-CID-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestVRTR-CID-Regular.otf -------------------------------------------------------------------------------- /fonts/TestVRTR-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestVRTR-Regular.otf -------------------------------------------------------------------------------- /fonts/TestVRTR-TTF-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/TestVRTR-TTF-Regular.ttf -------------------------------------------------------------------------------- /fonts/Zycon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unicode-org/text-rendering-tests/6d6e1fe0a5249177ca87ad57f54d91109becc7ca/fonts/Zycon.ttf -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "text-rendering-tests", 3 | "version": "1.0.0", 4 | "description": "OpenType test suite", 5 | "dependencies": { 6 | "fontkit": "^1.7.1", 7 | "iconv-lite": "^0.4.17", 8 | "opentype.js": "^0.8.0" 9 | }, 10 | "license": "Apache-2.0", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/unicode-org/text-rendering-tests.git" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | add_subdirectory(third_party/freetype) 4 | add_subdirectory(third_party/fribidi) 5 | add_subdirectory(third_party/harfbuzz) 6 | add_subdirectory(third_party/sheenbidi) 7 | add_subdirectory(third_party/sheenfigure) 8 | add_subdirectory(third_party/raqm) 9 | add_subdirectory(fonttest) 10 | -------------------------------------------------------------------------------- /src/fonttest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(fonttest) 4 | 5 | add_executable(fonttest 6 | main.cpp 7 | font_engine.cpp 8 | freestack_engine.cpp 9 | freestack_font.cpp 10 | freestack_line.cpp 11 | freestack_path.cpp 12 | tehreerstack_engine.cpp 13 | tehreerstack_line.cpp 14 | test_harness.cpp 15 | $,coretext_engine.mm,> 16 | $,coretext_font.mm,> 17 | $,coretext_line.mm,> 18 | $,coretext_path.mm,> 19 | ) 20 | 21 | set_target_properties(fonttest PROPERTIES 22 | CXX_STANDARD 11 23 | CXX_STANDARD_REQUIRED YES 24 | CXX_EXTENSIONS NO 25 | ) 26 | 27 | target_include_directories(fonttest 28 | PRIVATE .. 29 | ) 30 | 31 | set(compile_definitions) 32 | if(APPLE) 33 | list(APPEND compile_definitions HAVE_CORETEXT) 34 | include(CheckCSourceCompiles) 35 | check_c_source_compiles(" 36 | #include 37 | int main(int a, char** b) { return (int) kCTVersionNumber10_14; } 38 | " HAVE_CORETEXT_10_14) 39 | if(DEFINED HAVE_CORETEXT_10_14 AND HAVE_CORETEXT_10_14) 40 | list(APPEND compile_definitions HAVE_CORETEXT_10_14) 41 | endif() 42 | endif() 43 | 44 | target_compile_definitions(fonttest 45 | PRIVATE ${compile_definitions} 46 | ) 47 | 48 | if(APPLE) 49 | find_library(Foundation Foundation) 50 | find_library(CoreGraphics CoreGraphics) 51 | find_library(CoreText CoreText) 52 | endif(APPLE) 53 | 54 | target_link_libraries(fonttest 55 | freetype harfbuzz raqm sheenbidi sheenfigure 56 | $,${Foundation},> 57 | $,${CoreGraphics},> 58 | $,${CoreText},> 59 | ) 60 | -------------------------------------------------------------------------------- /src/fonttest/coretext_engine.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_CORETEXT_ENGINE_H_ 17 | #define FONTTEST_CORETEXT_ENGINE_H_ 18 | 19 | #include "fonttest/font.h" 20 | 21 | namespace fonttest { 22 | 23 | class CoreTextEngine : public FontEngine { 24 | public: 25 | CoreTextEngine(); 26 | ~CoreTextEngine(); 27 | virtual std::string GetName() const; 28 | virtual std::string GetVersion() const; 29 | virtual Font* LoadFont(const std::string& path, int faceIndex); 30 | 31 | // Renders a line of text into an SVG document. 32 | virtual bool RenderSVG(const std::string& text, 33 | const std::string& textLanguage, 34 | Font* font, double fontSize, 35 | const FontVariation& fontVariation, 36 | const std::string& id_prefix, 37 | std::string* svg); 38 | }; 39 | 40 | } // namespace fonttest 41 | 42 | 43 | #endif // FONTTEST_CORETEXT_ENGINE_H_ 44 | -------------------------------------------------------------------------------- /src/fonttest/coretext_font.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_CORETEXT_FONT_H_ 17 | #define FONTTEST_CORETEXT_FONT_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "fonttest/font.h" 24 | 25 | namespace fonttest { 26 | 27 | class CoreTextFont : public Font { 28 | public: 29 | CoreTextFont(CTFontDescriptorRef fontDescriptor); 30 | CoreTextFont(CGFontRef cgFont); 31 | ~CoreTextFont(); 32 | 33 | CTFontRef CreateFont(double size, const FontVariation& variation); 34 | 35 | virtual void GetGlyphOutline(int glyphID, const FontVariation& variation, 36 | std::string* path, std::string* viewBox); 37 | 38 | private: 39 | CGFontRef cgFont_; 40 | CTFontDescriptorRef fontDescriptor_; 41 | }; 42 | 43 | } // namespace fonttest 44 | 45 | #endif // FONTTEST_CORETEXT_FONT_H_ 46 | -------------------------------------------------------------------------------- /src/fonttest/coretext_line.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_CORETEXT_LINE_H_ 17 | #define FONTTEST_CORETEXT_LINE_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "fonttest/font.h" 23 | 24 | namespace fonttest { 25 | 26 | class CoreTextLine { 27 | public: 28 | CoreTextLine(const std::string& text, const std::string& textLanguage, 29 | CTFontRef font, double fontSize); 30 | ~CoreTextLine(); 31 | bool RenderSVG(const std::string& idPrefix, std::string* svg); 32 | 33 | private: 34 | CTFontRef font_; 35 | CTLineRef line_; 36 | double fontSize_; 37 | }; 38 | 39 | } // namespace fonttest 40 | 41 | #endif // FONTTEST_CORETEXT_LINE_H_ 42 | -------------------------------------------------------------------------------- /src/fonttest/coretext_path.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_CORETEXT_PATH_H_ 17 | #define FONTTEST_CORETEXT_PATH_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace fonttest { 24 | 25 | class CoreTextPath { 26 | public: 27 | CoreTextPath(CGPathRef path); 28 | ~CoreTextPath(); 29 | const std::string& ToSVGPath(); 30 | 31 | private: 32 | std::string svgPath_; 33 | static void VisitPathElement(void* data, const CGPathElement* element); 34 | }; 35 | 36 | } // namespace fonttest 37 | 38 | #endif // FONTTEST_CORETEXT_PATH_H_ 39 | -------------------------------------------------------------------------------- /src/fonttest/coretext_path.mm: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | 18 | #include "fonttest/coretext_path.h" 19 | 20 | namespace fonttest { 21 | 22 | CoreTextPath::CoreTextPath(CGPathRef path) { 23 | CGPathApply(path, reinterpret_cast(this), 24 | &CoreTextPath::VisitPathElement); 25 | } 26 | 27 | CoreTextPath::~CoreTextPath() { 28 | } 29 | 30 | const std::string& CoreTextPath::ToSVGPath() { 31 | return svgPath_; 32 | } 33 | 34 | void CoreTextPath::VisitPathElement(void* data, const CGPathElement* element) { 35 | CoreTextPath* self = static_cast(data); 36 | std::string* svg = &self->svgPath_; 37 | 38 | if (!svg->empty()) { 39 | svg->append(" "); 40 | } 41 | 42 | char buffer[100]; 43 | long x, y, ax, ay, bx, by; 44 | switch (element->type) { 45 | case kCGPathElementMoveToPoint: 46 | x = static_cast(element->points[0].x); 47 | y = static_cast(element->points[0].y); 48 | snprintf(buffer, sizeof(buffer), "M%ld,%ld", x, y); 49 | svg->append(buffer); 50 | break; 51 | 52 | case kCGPathElementAddLineToPoint: 53 | x = static_cast(element->points[0].x); 54 | y = static_cast(element->points[0].y); 55 | snprintf(buffer, sizeof(buffer), "L%ld,%ld", x, y); 56 | svg->append(buffer); 57 | break; 58 | 59 | case kCGPathElementAddQuadCurveToPoint: 60 | ax = static_cast(element->points[0].x); 61 | ay = static_cast(element->points[0].y); 62 | x = static_cast(element->points[1].x); 63 | y = static_cast(element->points[1].y); 64 | snprintf(buffer, sizeof(buffer), "Q%ld,%ld %ld,%ld", ax, ay, x, y); 65 | svg->append(buffer); 66 | break; 67 | 68 | case kCGPathElementAddCurveToPoint: 69 | ax = static_cast(element->points[0].x); 70 | ay = static_cast(element->points[0].y); 71 | bx = static_cast(element->points[1].x); 72 | by = static_cast(element->points[1].y); 73 | x = static_cast(element->points[2].x); 74 | y = static_cast(element->points[2].y); 75 | snprintf(buffer, sizeof(buffer), "C%ld,%ld %ld,%ld %ld,%ld", 76 | ax, ay, bx, by, x, y); 77 | svg->append(buffer); 78 | break; 79 | 80 | case kCGPathElementCloseSubpath: 81 | svg->append("Z"); 82 | break; 83 | } 84 | } 85 | 86 | } // namespace fonttest 87 | -------------------------------------------------------------------------------- /src/fonttest/font.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FONT_H_ 17 | #define FONTTEST_FONT_H_ 18 | 19 | #include 20 | #include 21 | 22 | namespace fonttest { 23 | 24 | typedef std::map FontVariation; // "WGHT" -> 400.0 25 | 26 | class Font { 27 | public: 28 | virtual ~Font() {} 29 | 30 | // Returns the path of a glyph outline, in SVG path format. 31 | // For example, "M 100 100 L 300 100 L 200 300 Z", 32 | virtual void GetGlyphOutline(int glyphID, const FontVariation& variation, 33 | std::string* path, std::string* viewBox) = 0; 34 | }; 35 | 36 | } // namespace fonttest 37 | 38 | #endif // FONTTEST_FONT_H_ 39 | -------------------------------------------------------------------------------- /src/fonttest/font_engine.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "fonttest/font_engine.h" 17 | #include "fonttest/freestack_engine.h" 18 | #include "fonttest/tehreerstack_engine.h" 19 | 20 | #ifdef HAVE_CORETEXT 21 | # include "fonttest/coretext_engine.h" 22 | #endif 23 | 24 | namespace fonttest { 25 | 26 | FontEngine* FontEngine::Create(const std::string& engineName) { 27 | if (engineName == "FreeStack") { 28 | return new FreeStackEngine(); 29 | } 30 | 31 | if (engineName == "TehreerStack") { 32 | return new TehreerStackEngine(); 33 | } 34 | 35 | #ifdef HAVE_CORETEXT 36 | if (engineName == "CoreText") { 37 | return new CoreTextEngine(); 38 | } 39 | #endif // HAVE_CORETEXT 40 | 41 | #ifdef HAVE_DIRECTWRITE 42 | if (engineName == "DirectWrite") { 43 | return new DirectWriteEngine(); 44 | } 45 | #endif // HAVE_DIRECTWRITE 46 | 47 | return NULL; 48 | } 49 | 50 | FontEngine::~FontEngine() { 51 | } 52 | 53 | } // namespace fonttest 54 | -------------------------------------------------------------------------------- /src/fonttest/font_engine.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FONT_ENGINE_H_ 17 | #define FONTTEST_FONT_ENGINE_H_ 18 | 19 | #include 20 | #include 21 | 22 | namespace fonttest { 23 | class Font; 24 | typedef std::map FontVariation; // "WGHT" -> 400.0 25 | 26 | class FontEngine { 27 | public: 28 | virtual ~FontEngine(); 29 | static FontEngine* Create(const std::string& engineName); 30 | virtual std::string GetName() const = 0; 31 | virtual std::string GetVersion() const = 0; 32 | virtual Font* LoadFont(const std::string& path, int faceIndex) = 0; 33 | 34 | // Renders a line of text into an SVG document. 35 | virtual bool RenderSVG(const std::string& text, 36 | const std::string& textLanguage, 37 | Font* font, double fontSize, 38 | const FontVariation& fontVariation, 39 | const std::string& id_prefix, 40 | std::string* svg) = 0; 41 | }; 42 | 43 | } // namespace fonttest 44 | 45 | #endif // FONTTEST_FONT_ENGINE_H_ 46 | -------------------------------------------------------------------------------- /src/fonttest/freestack_engine.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include FT_FREETYPE_H 21 | 22 | #include "fonttest/font_engine.h" 23 | #include "fonttest/freestack_engine.h" 24 | #include "fonttest/freestack_font.h" 25 | #include "fonttest/freestack_line.h" 26 | 27 | #include 28 | #include FT_FREETYPE_H 29 | #include 30 | #include 31 | #include 32 | 33 | namespace fonttest { 34 | 35 | FreeStackEngine::FreeStackEngine() { 36 | FT_Init_FreeType(&freeTypeLibrary_); 37 | } 38 | 39 | FreeStackEngine::~FreeStackEngine() { 40 | FT_Done_FreeType(freeTypeLibrary_); 41 | } 42 | 43 | std::string FreeStackEngine::GetName() const { 44 | return "FreeStack"; 45 | } 46 | 47 | std::string FreeStackEngine::GetVersion() const { 48 | std::stringstream result; 49 | 50 | result << "HarfBuzz/" << hb_version_string() << ' '; 51 | 52 | FT_Int ftMajor, ftMinor, ftPatch; 53 | FT_Library_Version(freeTypeLibrary_, &ftMajor, &ftMinor, &ftPatch); 54 | result << "FreeType/" << ftMajor << '.' << ftMinor << '.' << ftPatch; 55 | 56 | result << " FriBidi/" << FRIBIDI_MAJOR_VERSION << '.' 57 | << FRIBIDI_MINOR_VERSION << '.' << FRIBIDI_MICRO_VERSION; 58 | 59 | result << " Raqm/" << RAQM_VERSION_MAJOR << '.' 60 | << RAQM_VERSION_MINOR << '.' << RAQM_VERSION_MICRO; 61 | 62 | return result.str(); 63 | } 64 | 65 | Font* FreeStackEngine::LoadFont( 66 | const std::string& path, int faceIndex) { 67 | FT_Face face = NULL; 68 | FT_Error error = FT_New_Face(freeTypeLibrary_, path.c_str(), 69 | static_cast(faceIndex), &face); 70 | if (error || !face) { 71 | return NULL; 72 | } 73 | 74 | return new FreeStackFont(face); 75 | } 76 | 77 | bool FreeStackEngine::RenderSVG(const std::string& text, 78 | const std::string& textLanguage, 79 | Font* font, double fontSize, 80 | const FontVariation& fontVariation, 81 | const std::string& idPrefix, 82 | std::string* svg) { 83 | FT_Face face = 84 | static_cast(font)->GetFace(fontSize, fontVariation); 85 | FreeStackLine line(text, textLanguage, face, fontSize); 86 | return line.RenderSVG(idPrefix, svg); 87 | } 88 | 89 | } // namespace fonttest 90 | -------------------------------------------------------------------------------- /src/fonttest/freestack_engine.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FREESTACK_ENGINE_H_ 17 | #define FONTTEST_FREESTACK_ENGINE_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include FT_FREETYPE_H 24 | #include FT_MULTIPLE_MASTERS_H 25 | #include FT_TRUETYPE_TABLES_H 26 | #include FT_TYPES_H 27 | 28 | #include "fonttest/font.h" 29 | 30 | namespace fonttest { 31 | 32 | class FreeStackEngine : public FontEngine { 33 | public: 34 | FreeStackEngine(); 35 | ~FreeStackEngine(); 36 | virtual std::string GetName() const; 37 | virtual std::string GetVersion() const; 38 | virtual Font* LoadFont(const std::string& path, int faceIndex); 39 | 40 | // Renders a line of text into an SVG document. 41 | virtual bool RenderSVG(const std::string& text, 42 | const std::string& textLanguage, 43 | Font* font, double fontSize, 44 | const FontVariation& fontVariation, 45 | const std::string& idPrefix, 46 | std::string* svg); 47 | 48 | private: 49 | FT_Library freeTypeLibrary_; 50 | }; 51 | 52 | } // namespace fonttest 53 | 54 | 55 | #endif // FONTTEST_FREESTACK_ENGINE_H_ 56 | -------------------------------------------------------------------------------- /src/fonttest/freestack_font.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include FT_MULTIPLE_MASTERS_H 24 | 25 | #include "fonttest/font.h" 26 | #include "fonttest/freestack_font.h" 27 | #include "fonttest/freestack_path.h" 28 | 29 | namespace fonttest { 30 | 31 | FreeStackFont::FreeStackFont(FT_Face face) 32 | : face_(face) { 33 | } 34 | 35 | FreeStackFont::~FreeStackFont() { 36 | FT_Done_Face(face_); 37 | } 38 | 39 | static std::string TagToString(FT_ULong tag) { 40 | char s[5]; 41 | s[0] = static_cast((tag & 0xff000000) >> 24); 42 | s[1] = static_cast((tag & 0x00ff0000) >> 16); 43 | s[2] = static_cast((tag & 0x0000ff00) >> 8); 44 | s[3] = static_cast((tag & 0x000000ff) >> 0); 45 | s[4] = 0; 46 | if (s[3] == 0x20) { 47 | s[3] = 0; 48 | if (s[2] == 0x20) { 49 | s[2] = 0; 50 | if (s[1] == 0x20) { 51 | s[1] = 0; 52 | } 53 | } 54 | } 55 | return std::string(s); 56 | } 57 | 58 | FT_Face FreeStackFont::GetFace(double size, const FontVariation& variation) { 59 | FT_Fixed fixedSize = static_cast(size * 64 + 0.5); 60 | FT_Error error = FT_Set_Char_Size(face_, fixedSize, fixedSize, 0, 0); 61 | if (error) { 62 | std::cerr << "FT_Set_Char_Size() failed; error: " << error << std::endl; 63 | exit(1); 64 | } 65 | 66 | FT_MM_Var* mmvar = NULL; 67 | FT_Get_MM_Var(face_, &mmvar); 68 | if (mmvar) { 69 | FT_Fixed coords[mmvar->num_axis]; 70 | for (FT_UInt axisIndex = 0; axisIndex < mmvar->num_axis; ++axisIndex) { 71 | const FT_Var_Axis& axis = mmvar->axis[axisIndex]; 72 | coords[axisIndex] = axis.def; 73 | FontVariation::const_iterator iter = 74 | variation.find(TagToString(axis.tag)); 75 | if (iter != variation.end()) { 76 | coords[axisIndex] = 77 | static_cast(iter->second * 65536.0 + 0.5); 78 | } 79 | } 80 | error = FT_Set_Var_Design_Coordinates(face_, mmvar->num_axis, coords); 81 | if (error) { 82 | std::cerr << "FT_Set_Var_Design_Coordinates() failed; error: " 83 | << error << std::endl; 84 | exit(1); 85 | } 86 | free(static_cast(mmvar)); 87 | } 88 | 89 | return face_; 90 | } 91 | 92 | void FreeStackFont::GetGlyphOutline(int glyphID, 93 | const FontVariation& variation, 94 | std::string* path, 95 | std::string* viewBox) { 96 | FT_Face face = GetFace(1000.0, variation); 97 | FT_Error error = 98 | FT_Load_Glyph(face, glyphID, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP); 99 | if (error) { 100 | std::cerr << "FT_Load_Glyph() failed; error: " << error << std::endl; 101 | exit(1); 102 | } 103 | 104 | if (!face->glyph) { 105 | std::cerr << "FT_Load_Glyph() did not load a glyph" << std::endl; 106 | exit(1); 107 | } 108 | 109 | FT_Vector transform; 110 | transform.x = transform.y = 0; 111 | FreeTypePathConverter converter(transform); 112 | path->assign(converter.Convert(&face->glyph->outline)); 113 | char buffer[200]; 114 | snprintf(buffer, sizeof(buffer), "%ld %ld %ld %ld", 115 | 0L, lround(face->descender), 116 | lround(face->glyph->metrics.horiAdvance / 64), 117 | lround(face->height)); 118 | viewBox->assign(buffer); 119 | } 120 | 121 | } // namespace fonttest 122 | -------------------------------------------------------------------------------- /src/fonttest/freestack_font.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FREESTACK_FONT_H_ 17 | #define FONTTEST_FREESTACK_FONT_H_ 18 | 19 | #include 20 | #include FT_FREETYPE_H 21 | #include FT_TYPES_H 22 | 23 | #include "fonttest/font.h" 24 | 25 | namespace fonttest { 26 | 27 | class FreeStackFont : public Font { 28 | public: 29 | FreeStackFont(FT_Face face); 30 | ~FreeStackFont(); 31 | FT_Face GetFace(double size, const FontVariation& variation); 32 | virtual void GetGlyphOutline(int glyphID, const FontVariation& variation, 33 | std::string* path, std::string* viewBox); 34 | 35 | private: 36 | FT_Face face_; 37 | }; 38 | 39 | } // namespace fonttest 40 | 41 | #endif // FONTTEST_FREESTACK_FONT_H_ 42 | -------------------------------------------------------------------------------- /src/fonttest/freestack_line.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FREESTACK_LINE_H_ 17 | #define FONTTEST_FREESTACK_LINE_H_ 18 | 19 | #include 20 | #include FT_FREETYPE_H 21 | 22 | #include "raqm.h" 23 | 24 | #include "fonttest/font.h" 25 | 26 | namespace fonttest { 27 | 28 | class FreeStackLine { 29 | public: 30 | FreeStackLine(const std::string& text, const std::string& textLanguage, 31 | FT_Face font, double fontSize); 32 | ~FreeStackLine(); 33 | bool RenderSVG(const std::string& idPrefix, std::string* svg); 34 | 35 | private: 36 | raqm_t* line_; 37 | FT_Face font_; 38 | double fontSize_; 39 | }; 40 | 41 | } // namespace fonttest 42 | 43 | #endif // FONTTEST_FREESTACK_LINE_H_ 44 | -------------------------------------------------------------------------------- /src/fonttest/freestack_path.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include FT_IMAGE_H 23 | #include FT_OUTLINE_H 24 | 25 | #include "fonttest/freestack_path.h" 26 | 27 | namespace fonttest { 28 | 29 | FreeTypePathConverter::FreeTypePathConverter(const FT_Vector& transform) 30 | : transform_(transform) { 31 | } 32 | 33 | FreeTypePathConverter::~FreeTypePathConverter() { 34 | } 35 | 36 | std::string FreeTypePathConverter::Convert(FT_Outline* outline) { 37 | path_.clear(); 38 | start_.x = start_.y = 0; 39 | closed_ = true; 40 | 41 | FT_Outline_Funcs callbacks; 42 | callbacks.move_to = &FreeTypePathConverter::MoveToCallback; 43 | callbacks.line_to = &FreeTypePathConverter::LineToCallback; 44 | callbacks.conic_to = &FreeTypePathConverter::QuadToCallback; 45 | callbacks.cubic_to = &FreeTypePathConverter::CurveToCallback; 46 | callbacks.shift = 0; 47 | callbacks.delta = 0; 48 | FT_Error error = 49 | FT_Outline_Decompose(outline, &callbacks, static_cast(this)); 50 | if (error) { 51 | std::cerr << "FT_Outline_Decompose() failed; error: " << error 52 | << std::endl; 53 | exit(1); 54 | } 55 | if (!closed_) { 56 | path_.append(" Z"); 57 | } 58 | return path_; 59 | } 60 | 61 | void FreeTypePathConverter::MoveTo(const FT_Vector& to) { 62 | start_.x = to.x + transform_.x; 63 | start_.y = to.y + transform_.y; 64 | if (!closed_) { 65 | path_.append(" Z"); 66 | } 67 | char buffer[200]; 68 | snprintf(buffer, sizeof(buffer), "%sM%ld,%ld", 69 | path_.empty() ? "" : " ", start_.x / 64, start_.y / 64); 70 | path_.append(buffer); 71 | closed_ = false; 72 | } 73 | 74 | void FreeTypePathConverter::LineTo(const FT_Vector& to) { 75 | FT_Vector p; 76 | p.x = to.x + transform_.x; 77 | p.y = to.y + transform_.y; 78 | if (p.x == start_.x && p.y == start_.y) { 79 | path_.append(" Z"); 80 | closed_ = true; 81 | return; 82 | } 83 | char buffer[200]; 84 | snprintf(buffer, sizeof(buffer), "%sL%ld,%ld", 85 | path_.empty() ? "" : " ", p.x / 64, p.y / 64); 86 | path_.append(buffer); 87 | closed_ = false; 88 | } 89 | 90 | void FreeTypePathConverter::QuadTo(const FT_Vector& control, 91 | const FT_Vector& to) { 92 | char buffer[200]; 93 | snprintf(buffer, sizeof(buffer), "%sQ%ld,%ld %ld,%ld", 94 | path_.empty() ? "" : " ", 95 | (control.x + transform_.x) / 64, (control.y + transform_.y) / 64, 96 | (to.x + transform_.x) / 64, (to.y + transform_.y) / 64); 97 | path_.append(buffer); 98 | closed_ = false; 99 | } 100 | 101 | void FreeTypePathConverter::CurveTo(const FT_Vector& control1, 102 | const FT_Vector& control2, 103 | const FT_Vector& to) { 104 | char buffer[200]; 105 | snprintf(buffer, sizeof(buffer), "%sC%ld,%ld %ld,%ld %ld,%ld", 106 | path_.empty() ? "" : " ", 107 | (control1.x + transform_.x) / 64, (control1.y + transform_.y) / 64, 108 | (control2.x + transform_.x) / 64, (control2.y + transform_.y) / 64, 109 | (to.x + transform_.x) / 64, (to.y + transform_.y) / 64); 110 | path_.append(buffer); 111 | closed_ = false; 112 | } 113 | 114 | 115 | int FreeTypePathConverter::MoveToCallback(const FT_Vector* to, void* data) { 116 | if (to && data) { 117 | reinterpret_cast(data)->MoveTo(*to); 118 | return 0; 119 | } else { 120 | return 1; 121 | } 122 | } 123 | 124 | int FreeTypePathConverter::LineToCallback(const FT_Vector* to, void* data) { 125 | if (to && data) { 126 | reinterpret_cast(data)->LineTo(*to); 127 | return 0; 128 | } else { 129 | return 1; 130 | } 131 | } 132 | 133 | int FreeTypePathConverter::QuadToCallback(const FT_Vector* control, 134 | const FT_Vector* to, 135 | void* data) { 136 | if (control && to && data) { 137 | reinterpret_cast(data)->QuadTo(*control, *to); 138 | return 0; 139 | } else { 140 | return 1; 141 | } 142 | } 143 | 144 | int FreeTypePathConverter::CurveToCallback(const FT_Vector* control1, 145 | const FT_Vector* control2, 146 | const FT_Vector* to, 147 | void* data) { 148 | if (control1 && control2 && to && data) { 149 | FreeTypePathConverter* c = reinterpret_cast(data); 150 | c->CurveTo(*control1, *control2, *to); 151 | return 0; 152 | } else { 153 | return 1; 154 | } 155 | } 156 | 157 | } // namespace fonttest 158 | -------------------------------------------------------------------------------- /src/fonttest/freestack_path.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_FREESTACK_PATH_H_ 17 | #define FONTTEST_FREESTACK_PATH_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include FT_IMAGE_H 23 | #include FT_TYPES_H 24 | 25 | namespace fonttest { 26 | 27 | class FreeTypePathConverter { 28 | public: 29 | FreeTypePathConverter(const FT_Vector& transform); 30 | ~FreeTypePathConverter(); 31 | std::string Convert(FT_Outline* outline); 32 | 33 | private: 34 | void MoveTo(const FT_Vector& to); 35 | void LineTo(const FT_Vector& to); 36 | void QuadTo(const FT_Vector& control, const FT_Vector& to); 37 | void CurveTo(const FT_Vector& control1, const FT_Vector& control2, 38 | const FT_Vector& to); 39 | 40 | static int MoveToCallback(const FT_Vector* to, void* data); 41 | static int LineToCallback(const FT_Vector* to, void* data); 42 | static int QuadToCallback(const FT_Vector* control, 43 | const FT_Vector* to, void* data); 44 | static int CurveToCallback(const FT_Vector* control1, 45 | const FT_Vector* control2, 46 | const FT_Vector* to, void* data); 47 | 48 | std::string path_; 49 | FT_Vector start_, transform_; 50 | bool closed_; 51 | }; 52 | 53 | } // namespace fonttest 54 | 55 | #endif // FONTTEST_FREESTACK_PATH_H_ 56 | -------------------------------------------------------------------------------- /src/fonttest/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include "fonttest/test_harness.h" 19 | 20 | int main(int argc, const char** argv) { 21 | std::vector args; 22 | for (int i = 0; i < argc; ++i) { 23 | args.push_back(argv[i]); 24 | } 25 | 26 | fonttest::TestHarness harness(args); 27 | harness.Run(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /src/fonttest/tehreerstack_engine.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | extern "C" { 20 | #include 21 | #include FT_FREETYPE_H 22 | } 23 | 24 | #include "fonttest/font_engine.h" 25 | #include "fonttest/freestack_font.h" 26 | #include "fonttest/tehreerstack_line.h" 27 | #include "fonttest/tehreerstack_engine.h" 28 | 29 | namespace fonttest { 30 | 31 | TehreerStackEngine::TehreerStackEngine() { 32 | FT_Init_FreeType(&freeTypeLibrary_); 33 | } 34 | 35 | TehreerStackEngine::~TehreerStackEngine() { 36 | FT_Done_FreeType(freeTypeLibrary_); 37 | } 38 | 39 | std::string TehreerStackEngine::GetName() const { 40 | return "TehreerStack"; 41 | } 42 | 43 | std::string TehreerStackEngine::GetVersion() const { 44 | std::stringstream result; 45 | 46 | FT_Int ftMajor, ftMinor, ftPatch; 47 | FT_Library_Version(freeTypeLibrary_, &ftMajor, &ftMinor, &ftPatch); 48 | result << "FreeType/" << ftMajor << '.' << ftMinor << '.' << ftPatch; 49 | 50 | result << " SheenBidi/2.0"; 51 | 52 | result << " SheenFigure/1.5"; 53 | 54 | return result.str(); 55 | } 56 | 57 | Font* TehreerStackEngine::LoadFont( 58 | const std::string& path, int faceIndex) { 59 | FT_Face face = NULL; 60 | FT_Error error = FT_New_Face(freeTypeLibrary_, path.c_str(), 61 | static_cast(faceIndex), &face); 62 | if (error || !face) { 63 | return NULL; 64 | } 65 | 66 | return new FreeStackFont(face); 67 | } 68 | 69 | bool TehreerStackEngine::RenderSVG(const std::string& text, 70 | const std::string& textLanguage, 71 | Font* font, double fontSize, 72 | const FontVariation& fontVariation, 73 | const std::string& idPrefix, 74 | std::string* svg) { 75 | FT_Face face = static_cast(font)->GetFace(fontSize, fontVariation); 76 | TehreerStackLine line(text, textLanguage, face, fontSize); 77 | return line.RenderSVG(idPrefix, svg); 78 | } 79 | 80 | } // namespace fonttest 81 | -------------------------------------------------------------------------------- /src/fonttest/tehreerstack_engine.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_TEHREERSTACK_ENGINE_H_ 17 | #define FONTTEST_TEHREERSTACK_ENGINE_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include FT_FREETYPE_H 24 | 25 | #include "fonttest/font.h" 26 | 27 | namespace fonttest { 28 | 29 | class TehreerStackEngine : public FontEngine { 30 | public: 31 | TehreerStackEngine(); 32 | ~TehreerStackEngine(); 33 | virtual std::string GetName() const; 34 | virtual std::string GetVersion() const; 35 | virtual Font* LoadFont(const std::string& path, int faceIndex); 36 | 37 | // Renders a line of text into an SVG document. 38 | virtual bool RenderSVG(const std::string& text, 39 | const std::string& textLanguage, 40 | Font* font, double fontSize, 41 | const FontVariation& fontVariation, 42 | const std::string& idPrefix, 43 | std::string* svg); 44 | 45 | private: 46 | FT_Library freeTypeLibrary_; 47 | }; 48 | 49 | } // namespace fonttest 50 | 51 | 52 | #endif // FONTTEST_TEHREERSTACK_ENGINE_H_ 53 | -------------------------------------------------------------------------------- /src/fonttest/tehreerstack_line.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2019 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_TEHREERSTACK_LINE_H_ 17 | #define FONTTEST_TEHREERSTACK_LINE_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | extern "C" { 24 | #include 25 | #include FT_FREETYPE_H 26 | 27 | #include 28 | } 29 | 30 | #include "fonttest/font.h" 31 | 32 | struct GlyphInfo { 33 | uint16_t glyphID; 34 | double xOffset; 35 | double yOffset; 36 | double advance; 37 | }; 38 | 39 | namespace fonttest { 40 | 41 | class TehreerStackLine { 42 | public: 43 | TehreerStackLine(const std::string& text, const std::string& textLanguage, 44 | FT_Face font, double fontSize); 45 | ~TehreerStackLine(); 46 | bool RenderSVG(const std::string& idPrefix, std::string* svg); 47 | 48 | private: 49 | SFFontRef sfFont_; 50 | FT_Face font_; 51 | double fontSize_; 52 | 53 | std::vector glyphInfos; 54 | }; 55 | 56 | } // namespace fonttest 57 | 58 | #endif // FONTTEST_TEHREERSTACK_LINE_H_ 59 | -------------------------------------------------------------------------------- /src/fonttest/test_harness.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "fonttest/font.h" 24 | #include "fonttest/font_engine.h" 25 | #include "fonttest/test_harness.h" 26 | 27 | namespace fonttest { 28 | 29 | // Helper methods for parsing command-line arguments. 30 | static void TrimWhitespace(std::string* str); 31 | static void SplitString(const std::string& text, char sep, 32 | std::vector* result); 33 | 34 | static void ParseVariationSpec(const std::string& spec, 35 | FontVariation* variation) { 36 | if (spec.empty()) { 37 | return; 38 | } 39 | 40 | std::vector v; 41 | SplitString(spec, ';', &v); 42 | for (const std::string& item : v) { 43 | std::vector keyValue; 44 | SplitString(item, ':', &keyValue); 45 | if (keyValue.size() != 2) { 46 | std::cerr << "malformed --variation=" << spec << std::endl; 47 | exit(1); 48 | } 49 | std::string key = keyValue[0]; 50 | std::string value = keyValue[1]; 51 | TrimWhitespace(&key); 52 | TrimWhitespace(&value); 53 | (*variation)[key] = std::atof(value.c_str()); 54 | } 55 | } 56 | 57 | TestHarness::TestHarness(const std::vector& options) 58 | : options_(options), 59 | engine_(FontEngine::Create(GetOption("--engine="))) { 60 | if (!engine_.get()) { 61 | PrintUsageAndExit(); 62 | } 63 | 64 | std::string fontPath = GetOption("--font="); 65 | int fontIndex = 0; 66 | if (!fontPath.empty()) { 67 | font_.reset(engine_->LoadFont(fontPath, fontIndex)); 68 | if (!font_.get()) { 69 | std::cerr << "failed to load font: " << fontPath << std::endl; 70 | exit(1); 71 | } 72 | } 73 | } 74 | 75 | TestHarness::~TestHarness() { 76 | } 77 | 78 | void TestHarness::Run() { 79 | if (HasOption("--version")) { 80 | std::cout << engine_->GetVersion() << std::endl; 81 | return; 82 | } 83 | 84 | FontVariation fontVariation; 85 | const std::string testcase = GetOption("--testcase="); 86 | const std::string variationSpec = GetOption("--variation="); 87 | ParseVariationSpec(variationSpec, &fontVariation); 88 | const std::string text = GetOption("--render="); 89 | const std::string textLanguage = GetOption("--textLanguage="); 90 | const double fontSize = 1000.0; 91 | std::string svg; 92 | engine_->RenderSVG(text, textLanguage, font_.get(), fontSize, fontVariation, 93 | testcase, &svg); 94 | std::cout << svg; 95 | } 96 | 97 | bool TestHarness::HasOption(const std::string& flag) const { 98 | for (auto iter = options_.begin(); iter != options_.end(); ++iter) { 99 | if (iter->find(flag) == 0) { 100 | return true; 101 | } 102 | } 103 | return false; 104 | } 105 | 106 | const std::string TestHarness::GetOption(const std::string& flag) const { 107 | for (auto iter = options_.begin(); iter != options_.end(); ++iter) { 108 | if (iter->find(flag) == 0) { 109 | return iter->substr(flag.length()); 110 | } 111 | } 112 | return ""; 113 | } 114 | 115 | void TestHarness::PrintUsageAndExit() { 116 | std::cerr 117 | << "Usage: fonttest" << std::endl 118 | << " --render=Text" << std::endl 119 | << " --variation=WGHT:700;WDTH:120" << std::endl 120 | << " --testcase=AVAR-1/789" << std::endl 121 | << " --engine={FreeStack, TehreerStack, DirectWrite, CoreText}" << std::endl 122 | << " --font=path/to/testfont.otf" << std::endl; 123 | exit(1); 124 | } 125 | 126 | void SplitString(const std::string& text, char sep, 127 | std::vector* result) { 128 | std::size_t start = 0, limit = 0; 129 | while ((limit = text.find(sep, start)) != std::string::npos) { 130 | result->push_back(text.substr(start, limit - start)); 131 | start = limit + 1; 132 | } 133 | result->push_back(text.substr(start)); 134 | } 135 | 136 | void TrimWhitespace(std::string* str) { 137 | static const char* whitespace = " \t\f\v\n\r"; 138 | const std::size_t start = str->find_first_not_of(whitespace); 139 | if (start == std::string::npos) { 140 | str->clear(); 141 | return; 142 | } 143 | str->substr(start).swap(*str); 144 | const std::size_t end = str->find_last_not_of(whitespace); 145 | if (end != std::string::npos) { 146 | str->erase(end + 1); 147 | } 148 | } 149 | 150 | } // namespace fonttest 151 | 152 | -------------------------------------------------------------------------------- /src/fonttest/test_harness.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Unicode Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef FONTTEST_TEST_HARNESS_H_ 17 | #define FONTTEST_TEST_HARNESS_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace fonttest { 25 | 26 | class Font; 27 | class FontEngine; 28 | 29 | typedef std::map FontVariation; // WGHT -> 400.0 30 | 31 | class TestHarness { 32 | public: 33 | TestHarness(const std::vector& options); 34 | ~TestHarness(); 35 | void Run(); 36 | 37 | private: 38 | bool HasOption(const std::string& flag) const; 39 | const std::string GetOption(const std::string& flag) const; 40 | void PrintUsageAndExit(); 41 | 42 | const std::vector options_; 43 | std::unique_ptr engine_; 44 | std::unique_ptr font_; 45 | }; 46 | 47 | } // namespace fonttest 48 | 49 | #endif // FONTTEST_TEST_HARNESS_H_ 50 | -------------------------------------------------------------------------------- /src/third_party/fontkit/render: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fontkit = require('fontkit'); 4 | 5 | // Poor man's argument parser 6 | var argv = {}; 7 | process.argv.forEach(function (arg) { 8 | var match = arg.match(/^--(.+)=(.+)$/); 9 | if (match) { 10 | argv[match[1]] = match[2]; 11 | } 12 | }); 13 | 14 | function render() { 15 | var font = fontkit.openSync(argv.font); 16 | 17 | if (argv.variation) { 18 | var settings = {}; 19 | argv.variation.split(';').forEach(function (setting) { 20 | var parts = setting.split(':'); 21 | settings[parts[0]] = parts[1]; 22 | }); 23 | 24 | font = font.getVariation(settings); 25 | } 26 | 27 | var run = font.layout(argv.render); 28 | var gids = {}; 29 | 30 | var glyphs = run.glyphs.map(function (glyph) { 31 | if (gids[glyph.id]) return; 32 | gids[glyph.id] = true; 33 | 34 | // Get path and normalize 35 | var path = glyph.getScaledPath(1000).mapPoints(function (x, y) { 36 | return [Math.floor(x), Math.floor(y)]; 37 | }); 38 | 39 | // Filter out lines back to the starting point of a contour 40 | var startX = 0, startY = 0; 41 | var closed = false; 42 | path.commands = path.commands.filter(function (c, i) { 43 | if (c.command === 'moveTo') { 44 | startX = c.args[0]; 45 | startY = c.args[1]; 46 | } else if (c.command === 'lineTo' && (!path.commands[i + 1] || path.commands[i + 1].command === 'closePath')) { 47 | return Math.abs(c.args[0] - startX) > 1 || Math.abs(c.args[1] - startY) > 1; 48 | } 49 | 50 | return true; 51 | }); 52 | 53 | var svgPath = path.toSVG() 54 | .replace(/(\d+) (-?\d+)/g, '$1,$2') 55 | .replace(/(\d)([A-Z])/g, '$1 $2') 56 | .replace(/Z([^\s])/g, 'Z $1'); 57 | 58 | return ( 59 | '' + 60 | '' + 61 | '' 62 | ); 63 | }); 64 | 65 | var scale = 1 / font.unitsPerEm * 1000; 66 | var x = 0, y = 0; 67 | var svg = run.glyphs.map(function (glyph, index) { 68 | var pos = run.positions[index]; 69 | var xPos = Math.round(x + pos.xOffset * scale); 70 | var yPos = Math.round(y + pos.yOffset * scale); 71 | var use = ''; 72 | x += Math.round(pos.xAdvance * scale); 73 | y += Math.round(pos.yAdvance * scale); 74 | return use; 75 | }); 76 | 77 | var bbox = [0, font.descent, run.advanceWidth, font.ascent - font.descent].map(function (x) { 78 | return Math.round(x * scale) 79 | }); 80 | 81 | console.log( 82 | '', 83 | '', 84 | glyphs.join('\n'), 85 | svg.join('\n'), 86 | '' 87 | ); 88 | } 89 | 90 | try { 91 | render(); 92 | } catch (e) { 93 | console.error(e.stack); 94 | process.exit(1); 95 | } 96 | -------------------------------------------------------------------------------- /src/third_party/freetype/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(freetype) 4 | 5 | add_library(freetype STATIC 6 | freetype2/src/autofit/autofit.c 7 | freetype2/src/base/ftbase.c 8 | freetype2/src/base/ftbbox.c 9 | freetype2/src/base/ftbitmap.c 10 | freetype2/src/base/ftdebug.c 11 | freetype2/src/base/ftfstype.c 12 | freetype2/src/base/ftgasp.c 13 | freetype2/src/base/ftglyph.c 14 | freetype2/src/base/ftinit.c 15 | freetype2/src/base/ftmm.c 16 | freetype2/src/base/ftpatent.c 17 | freetype2/src/base/ftstroke.c 18 | freetype2/src/base/ftsynth.c 19 | freetype2/src/base/ftsystem.c 20 | freetype2/src/base/fttype1.c 21 | freetype2/src/base/ftwinfnt.c 22 | freetype2/src/bdf/bdf.c 23 | freetype2/src/cff/cff.c 24 | freetype2/src/cid/type1cid.c 25 | freetype2/src/gzip/ftgzip.c 26 | freetype2/src/lzw/ftlzw.c 27 | freetype2/src/pcf/pcf.c 28 | freetype2/src/pfr/pfr.c 29 | freetype2/src/psaux/psaux.c 30 | freetype2/src/pshinter/pshinter.c 31 | freetype2/src/psnames/psnames.c 32 | freetype2/src/raster/raster.c 33 | freetype2/src/sdf/sdf.c 34 | freetype2/src/sfnt/sfnt.c 35 | freetype2/src/smooth/smooth.c 36 | freetype2/src/truetype/truetype.c 37 | freetype2/src/type1/type1.c 38 | freetype2/src/type42/type42.c 39 | freetype2/src/winfonts/winfnt.c 40 | ) 41 | 42 | target_include_directories(freetype 43 | PUBLIC freetype2/include 44 | PRIVATE freetype2/include/freetype/config 45 | ) 46 | 47 | target_compile_definitions(freetype 48 | PRIVATE -DFT_CONFIG_MODULES_H= 49 | PRIVATE -DFT2_BUILD_LIBRARY=1 50 | ) 51 | -------------------------------------------------------------------------------- /src/third_party/fribidi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(fribidi) 4 | 5 | add_library(fribidi STATIC 6 | fribidi/lib/fribidi-char-sets-cap-rtl.c 7 | fribidi/lib/fribidi-char-sets-cp1255.c 8 | fribidi/lib/fribidi-char-sets-cp1256.c 9 | fribidi/lib/fribidi-char-sets-iso8859-6.c 10 | fribidi/lib/fribidi-char-sets-iso8859-8.c 11 | fribidi/lib/fribidi-char-sets-utf8.c 12 | fribidi/lib/fribidi-char-sets.c 13 | fribidi/lib/fribidi-arabic.c 14 | fribidi/lib/fribidi-bidi-types.c 15 | fribidi/lib/fribidi-bidi.c 16 | fribidi/lib/fribidi-brackets.c 17 | fribidi/lib/fribidi-deprecated.c 18 | fribidi/lib/fribidi-joining-types.c 19 | fribidi/lib/fribidi-joining.c 20 | fribidi/lib/fribidi-mirroring.c 21 | fribidi/lib/fribidi-run.c 22 | fribidi/lib/fribidi-shape.c 23 | fribidi/lib/fribidi.c 24 | ) 25 | 26 | include(CheckIncludeFile) 27 | check_include_file(stdlib.h HAVE_STDLIB_H) 28 | check_include_file(string.h HAVE_STRING_H) 29 | check_include_file(strings.h HAVE_STRINGS_H) 30 | check_include_file(wchar.h HAVE_WCHAR_H) 31 | check_include_file(sys/times.h HAVE_SYS_TIMES_H) 32 | 33 | include(CheckTypeSize) 34 | check_type_size(int SIZEOF_INT) 35 | check_type_size(wchar_t SIZEOF_WCHAR_T) 36 | 37 | target_compile_definitions(fribidi 38 | PRIVATE HAVE_STRINGIZE 39 | $,HAVE_STDLIB_H,> 40 | $,HAVE_STRING_H,> 41 | $,HAVE_STRINGS_H,> 42 | $,HAVE_WCHAR_H,> 43 | $,HAVE_SYS_TIMES_H,> 44 | ) 45 | 46 | target_include_directories(fribidi SYSTEM 47 | PUBLIC fribidi/lib 48 | PUBLIC generated 49 | PUBLIC include 50 | PUBLIC fribidi/charset 51 | ) 52 | -------------------------------------------------------------------------------- /src/third_party/fribidi/generated/fribidi-unicode-version.h: -------------------------------------------------------------------------------- 1 | /* fribidi-unicode-version.h 2 | * generated by gen-unicode-version (fribidi 1.0.1) 3 | * from the file BidiMirroring.txt */ 4 | 5 | #define FRIBIDI_UNICODE_VERSION "10.0.0" 6 | #define FRIBIDI_UNICODE_MAJOR_VERSION 10 7 | #define FRIBIDI_UNICODE_MINOR_VERSION 0 8 | #define FRIBIDI_UNICODE_MICRO_VERSION 0 9 | #define FRIBIDI_UNICODE_NAMESPACE(SYMBOL) \ 10 | FRIBIDI_NAMESPACE(SYMBOL##_unicode_10_0_0) 11 | #define FRIBIDI_UNICODE_PRIVATESPACE(SYMBOL) \ 12 | FRIBIDI_PRIVATESPACE(SYMBOL##_unicode_10_0_0) 13 | 14 | /* End of generated fribidi-unicode-version.h */ 15 | -------------------------------------------------------------------------------- /src/third_party/fribidi/include/fribidi-config.h: -------------------------------------------------------------------------------- 1 | /* The contents of this file have been generated by expanding a macro 2 | * whose source is located at ../fribidi/lib/fribidi-config.h.in 3 | */ 4 | 5 | /* Not copyrighted, in public domain. */ 6 | #ifndef FRIBIDI_CONFIG_H 7 | #define FRIBIDI_CONFIG_H 8 | 9 | #define FRIBIDI "fribidi" 10 | #define FRIBIDI_NAME "fribidi" 11 | #define FRIBIDI_BUGREPORT "@PACKAGE_BUGREPORT@" 12 | 13 | #define FRIBIDI_VERSION "1.0.1" 14 | #define FRIBIDI_MAJOR_VERSION 1 15 | #define FRIBIDI_MINOR_VERSION 0 16 | #define FRIBIDI_MICRO_VERSION 1 17 | #define FRIBIDI_INTERFACE_VERSION 4 18 | #define FRIBIDI_INTERFACE_VERSION_STRING "4" 19 | 20 | /* Define to 1 if you want charset conversion codes in the library */ 21 | #define FRIBIDI_CHARSETS 1 22 | 23 | /* Define to 1 if you want to use glib */ 24 | #define FRIBIDI_USE_GLIB 0 25 | 26 | /* The size of a `int', as computed by sizeof. */ 27 | #define FRIBIDI_SIZEOF_INT 4 28 | 29 | #endif /* FRIBIDI_CONFIG_H */ 30 | -------------------------------------------------------------------------------- /src/third_party/fribidi/update_generated.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BUILD_DIR=build/out/Default 4 | GENERATED=src/third_party/fribidi/generated 5 | UNIDATA=src/third_party/fribidi/fribidi/gen.tab/unidata 6 | MAX_DEPTH=3 7 | 8 | rm -rf $GENERATED 9 | mkdir $GENERATED 10 | 11 | make -s --directory build gen-unicode-version 12 | $BUILD_DIR/gen-unicode-version \ 13 | $UNIDATA/*.txt >$GENERATED/fribidi-unicode-version.h 14 | 15 | make -s --directory build gen-arabic-shaping-tab 16 | $BUILD_DIR/gen-arabic-shaping-tab \ 17 | $MAX_DEPTH $UNIDATA/UnicodeData.txt >$GENERATED/arabic-shaping.tab.i 18 | 19 | make -s --directory build gen-bidi-type-tab 20 | $BUILD_DIR/gen-bidi-type-tab \ 21 | $MAX_DEPTH $UNIDATA/UnicodeData.txt >$GENERATED/bidi-type.tab.i 22 | 23 | make -s --directory build gen-mirroring-tab 24 | $BUILD_DIR/gen-mirroring-tab \ 25 | $MAX_DEPTH $UNIDATA/BidiMirroring.txt >$GENERATED/mirroring.tab.i 26 | 27 | make -s --directory build gen-joining-type-tab 28 | $BUILD_DIR/gen-joining-type-tab \ 29 | $MAX_DEPTH $UNIDATA/UnicodeData.txt $UNIDATA/ArabicShaping.txt \ 30 | >$GENERATED/joining-type.tab.i 31 | 32 | make -s --directory build gen-brackets-tab 33 | $BUILD_DIR/gen-brackets-tab \ 34 | $MAX_DEPTH $UNIDATA/BidiBrackets.txt $UNIDATA/UnicodeData.txt \ 35 | >$GENERATED/brackets.tab.i 36 | 37 | make -s --directory build gen-brackets-type-tab 38 | $BUILD_DIR/gen-brackets-type-tab \ 39 | $MAX_DEPTH $UNIDATA/BidiBrackets.txt \ 40 | >$GENERATED/brackets-type.tab.i 41 | -------------------------------------------------------------------------------- /src/third_party/harfbuzz/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(harfbuzz) 4 | 5 | include(CheckIncludeFile) 6 | include(CheckSymbolExists) 7 | 8 | add_library(harfbuzz STATIC 9 | harfbuzz/src/hb-aat-layout.cc 10 | harfbuzz/src/hb-aat-map.cc 11 | harfbuzz/src/hb-blob.cc 12 | harfbuzz/src/hb-buffer-serialize.cc 13 | harfbuzz/src/hb-buffer.cc 14 | harfbuzz/src/hb-common.cc 15 | # harfbuzz/src/hb-coretext.cc 16 | # harfbuzz/src/hb-directwrite.cc 17 | harfbuzz/src/hb-face.cc 18 | harfbuzz/src/hb-fallback-shape.cc 19 | harfbuzz/src/hb-font.cc 20 | harfbuzz/src/hb-ft.cc 21 | # harfbuzz/src/hb-glib.cc 22 | # harfbuzz/src/hb-gobject-structs.cc 23 | # harfbuzz/src/hb-graphite2.cc 24 | # harfbuzz/src/hb-icu.cc 25 | harfbuzz/src/hb-map.cc 26 | harfbuzz/src/hb-number.cc 27 | harfbuzz/src/hb-ot-cff1-table.cc 28 | harfbuzz/src/hb-ot-cff2-table.cc 29 | harfbuzz/src/hb-ot-color.cc 30 | harfbuzz/src/hb-ot-face.cc 31 | harfbuzz/src/hb-ot-font.cc 32 | harfbuzz/src/hb-ot-layout.cc 33 | harfbuzz/src/hb-ot-map.cc 34 | harfbuzz/src/hb-ot-math.cc 35 | harfbuzz/src/hb-ot-metrics.cc 36 | harfbuzz/src/hb-ot-name.cc 37 | harfbuzz/src/hb-ot-shape-complex-arabic.cc 38 | harfbuzz/src/hb-ot-shape-complex-default.cc 39 | harfbuzz/src/hb-ot-shape-complex-hangul.cc 40 | harfbuzz/src/hb-ot-shape-complex-hebrew.cc 41 | harfbuzz/src/hb-ot-shape-complex-indic-table.cc 42 | harfbuzz/src/hb-ot-shape-complex-indic.cc 43 | harfbuzz/src/hb-ot-shape-complex-khmer.cc 44 | harfbuzz/src/hb-ot-shape-complex-myanmar.cc 45 | harfbuzz/src/hb-ot-shape-complex-thai.cc 46 | harfbuzz/src/hb-ot-shape-complex-syllabic.cc 47 | harfbuzz/src/hb-ot-shape-complex-use.cc 48 | harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc 49 | harfbuzz/src/hb-ot-shape-fallback.cc 50 | harfbuzz/src/hb-ot-shape-normalize.cc 51 | harfbuzz/src/hb-ot-shape.cc 52 | harfbuzz/src/hb-ot-tag.cc 53 | harfbuzz/src/hb-ot-var.cc 54 | harfbuzz/src/hb-set.cc 55 | harfbuzz/src/hb-shape-plan.cc 56 | harfbuzz/src/hb-shape.cc 57 | harfbuzz/src/hb-shaper.cc 58 | harfbuzz/src/hb-static.cc 59 | harfbuzz/src/hb-ucd.cc 60 | harfbuzz/src/hb-unicode.cc 61 | # harfbuzz/src/hb-uniscribe.cc 62 | # harfbuzz/src/hb-warning.cc 63 | 64 | harfbuzz/src/hb-buffer-deserialize-json.rl 65 | harfbuzz/src/hb-buffer-deserialize-text.rl 66 | harfbuzz/src/hb-ot-shape-complex-indic-machine.rl 67 | harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl 68 | harfbuzz/src/hb-ot-shape-complex-myanmar-machine.rl 69 | harfbuzz/src/hb-ot-shape-complex-use-machine.rl 70 | ) 71 | 72 | set_target_properties(harfbuzz PROPERTIES 73 | CXX_STANDARD 11 74 | CXX_STANDARD_REQUIRED YES 75 | CXX_EXTENSIONS NO 76 | ) 77 | 78 | check_include_file(inttypes.h HAVE_INTTYPES_H) 79 | check_include_file(memory.h HAVE_MEMORY_H) 80 | check_include_file(stdint.h HAVE_STDINT_H) 81 | check_include_file(stdlib.h HAVE_STDLIB_H) 82 | check_include_file(string.h HAVE_STRING_H) 83 | check_include_file(strings.h HAVE_STRINGS_H) 84 | check_include_file(sys/mman.h HAVE_SYS_MMAN_H) 85 | check_include_file(sys/stat.h HAVE_SYS_STAT_H) 86 | check_include_file(sys/types.h HAVE_SYS_TYPES_H) 87 | check_include_file(unistd.h HAVE_UNISTD_H) 88 | check_include_file(pthread.h HAVE_PTHREAD) 89 | 90 | include(CheckSymbolExists) 91 | check_symbol_exists(atexit stdlib.h HAVE_ATEXIT) 92 | check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) 93 | check_symbol_exists(mmap sys/mman.h HAVE_MMAP) 94 | check_symbol_exists(mprotect sys/mman.h HAVE_MPROTECT) 95 | check_symbol_exists(round math.h HAVE_ROUND) 96 | check_symbol_exists(sysconf unistd.h HAVE_SYSCONF) 97 | 98 | target_include_directories(harfbuzz 99 | PUBLIC harfbuzz/src 100 | PRIVATE harfbuzz/src/hb-ucdn 101 | PRIVATE autoconf_generated 102 | ) 103 | 104 | target_link_libraries(harfbuzz freetype) 105 | 106 | target_compile_definitions(harfbuzz 107 | PRIVATE HAVE_FREETYPE HAVE_OT HAVE_UCDN 108 | HAVE_FT_GET_VAR_BLEND_COORDINATES 109 | HAVE_INTEL_ATOMIC_PRIMITIVES 110 | $,HAVE_ATEXIT,> 111 | $,HAVE_GETPAGESIZE,> 112 | $,HAVE_MMAP,> 113 | $,HAVE_MPROTECT,> 114 | $,HAVE_ROUND,> 115 | $,HAVE_SYSCONF,> 116 | $,HAVE_SYS_MMAN_H,> 117 | $,HAVE_SYS_STAT_H,> 118 | $,HAVE_SYS_TYPES_H,> 119 | $,HAVE_UNISTD_H,> 120 | $,HAVE_PTHREAD,> 121 | ) 122 | -------------------------------------------------------------------------------- /src/third_party/harfbuzz/LICENSE.txt: -------------------------------------------------------------------------------- 1 | HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. 2 | For parts of HarfBuzz that are licensed under different licenses see individual 3 | files names COPYING in subdirectories where applicable. 4 | 5 | Copyright © 2010,2011,2012 Google, Inc. 6 | Copyright © 2012 Mozilla Foundation 7 | Copyright © 2011 Codethink Limited 8 | Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) 9 | Copyright © 2009 Keith Stribley 10 | Copyright © 2009 Martin Hosken and SIL International 11 | Copyright © 2007 Chris Wilson 12 | Copyright © 2006 Behdad Esfahbod 13 | Copyright © 2005 David Turner 14 | Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. 15 | Copyright © 1998-2004 David Turner and Werner Lemberg 16 | 17 | For full copyright notices consult the individual files in the package. 18 | 19 | 20 | Permission is hereby granted, without written agreement and without 21 | license or royalty fees, to use, copy, modify, and distribute this 22 | software and its documentation for any purpose, provided that the 23 | above copyright notice and the following two paragraphs appear in 24 | all copies of this software. 25 | 26 | IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 27 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 28 | ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 29 | IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 30 | DAMAGE. 31 | 32 | THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 33 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 34 | FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 35 | ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 36 | PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 37 | -------------------------------------------------------------------------------- /src/third_party/harfbuzz/autoconf_generated/hb-version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2011 Google, Inc. 3 | * 4 | * This is part of HarfBuzz, a text shaping library. 5 | * 6 | * Permission is hereby granted, without written agreement and without 7 | * license or royalty fees, to use, copy, modify, and distribute this 8 | * software and its documentation for any purpose, provided that the 9 | * above copyright notice and the following two paragraphs appear in 10 | * all copies of this software. 11 | * 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 | * DAMAGE. 17 | * 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 | * 24 | * Google Author(s): Behdad Esfahbod 25 | */ 26 | 27 | #ifndef HB_H_IN 28 | #error "Include instead." 29 | #endif 30 | 31 | #ifndef HB_VERSION_H 32 | #define HB_VERSION_H 33 | 34 | #include "hb-common.h" 35 | 36 | HB_BEGIN_DECLS 37 | 38 | 39 | #define HB_VERSION_MAJOR 2 40 | #define HB_VERSION_MINOR 6 41 | #define HB_VERSION_MICRO 4 42 | 43 | #define HB_VERSION_STRING "2.6.4" 44 | 45 | #define HB_VERSION_ATLEAST(major,minor,micro) \ 46 | ((major)*10000+(minor)*100+(micro) <= \ 47 | HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) 48 | 49 | 50 | HB_EXTERN void 51 | hb_version (unsigned int *major, 52 | unsigned int *minor, 53 | unsigned int *micro); 54 | 55 | HB_EXTERN const char * 56 | hb_version_string (void); 57 | 58 | HB_EXTERN hb_bool_t 59 | hb_version_atleast (unsigned int major, 60 | unsigned int minor, 61 | unsigned int micro); 62 | 63 | 64 | HB_END_DECLS 65 | 66 | #endif /* HB_VERSION_H */ 67 | -------------------------------------------------------------------------------- /src/third_party/raqm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(raqm) 4 | 5 | include(CheckIncludeFile) 6 | check_include_file(inttypes.h HAVE_INTTYPES_H) 7 | check_include_file(memory.h HAVE_MEMORY_H) 8 | check_include_file(stdint.h HAVE_STDINT_H) 9 | check_include_file(stdlib.h HAVE_STDLIB_H) 10 | check_include_file(string.h HAVE_STRING_H) 11 | check_include_file(strings.h HAVE_STRINGS_H) 12 | check_include_file(sys/stat.h HAVE_SYS_STAT_H) 13 | check_include_file(sys/types.h HAVE_SYS_TYPES_H) 14 | check_include_file(unistd.h HAVE_UNISTD_H) 15 | 16 | add_library(raqm STATIC 17 | libraqm/src/raqm.c 18 | ) 19 | 20 | target_compile_definitions(raqm 21 | PRIVATE 22 | HAVE_HB_FT_FONT_CREATE_REFERENCED 23 | HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES 24 | HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH 25 | HAVE_HB_FT_FONT_SET_LOAD_FLAGS 26 | $,HAVE_INTTYPES_H,> 27 | $,HAVE_MEMORY_H,> 28 | $,HAVE_STDINT_H,> 29 | $,HAVE_STDLIB_H,> 30 | $,HAVE_STRING_H,> 31 | $,HAVE_STRINGS_H,> 32 | $,HAVE_SYS_STAT_H,> 33 | $,HAVE_SYS_TYPES_H,> 34 | $,HAVE_UNISTD_H,> 35 | ) 36 | 37 | target_include_directories(raqm SYSTEM 38 | PUBLIC libraqm/src 39 | PUBLIC generated 40 | ) 41 | 42 | target_link_libraries(raqm fribidi harfbuzz) 43 | -------------------------------------------------------------------------------- /src/third_party/raqm/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2015 Information Technology Authority (ITA) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/third_party/raqm/generated/raqm-version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2011 Google, Inc. 3 | * 4 | * This is part of HarfBuzz, a text shaping library. 5 | * 6 | * Permission is hereby granted, without written agreement and without 7 | * license or royalty fees, to use, copy, modify, and distribute this 8 | * software and its documentation for any purpose, provided that the 9 | * above copyright notice and the following two paragraphs appear in 10 | * all copies of this software. 11 | * 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 | * DAMAGE. 17 | * 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 | * 24 | * Google Author(s): Behdad Esfahbod 25 | */ 26 | 27 | #ifndef _RAQM_H_IN_ 28 | #error "Include instead." 29 | #endif 30 | 31 | #ifndef _RAQM_VERSION_H_ 32 | #define _RAQM_VERSION_H_ 33 | 34 | #define RAQM_VERSION_MAJOR 0 35 | #define RAQM_VERSION_MINOR 10 36 | #define RAQM_VERSION_MICRO 1 37 | 38 | #define RAQM_VERSION_STRING "0.10.1" 39 | 40 | #define RAQM_VERSION_ATLEAST(major,minor,micro) \ 41 | ((major)*10000+(minor)*100+(micro) <= \ 42 | RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO) 43 | 44 | #endif /* _RAQM_VERSION_H_ */ 45 | -------------------------------------------------------------------------------- /src/third_party/sheenbidi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(sheenbidi) 4 | 5 | add_library(sheenbidi STATIC 6 | sheenbidi/Source/SheenBidi.c 7 | ) 8 | 9 | target_include_directories(sheenbidi 10 | PUBLIC sheenbidi/Headers 11 | ) 12 | 13 | target_compile_definitions(sheenbidi 14 | PRIVATE -DSB_CONFIG_UNITY=1 15 | ) 16 | -------------------------------------------------------------------------------- /src/third_party/sheenfigure/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(sheenfigure) 4 | 5 | add_library(sheenfigure STATIC 6 | sheenfigure/Source/SheenFigure.c 7 | ) 8 | 9 | target_include_directories(sheenfigure 10 | PUBLIC sheenfigure/Headers 11 | ) 12 | 13 | target_compile_definitions(sheenfigure 14 | PRIVATE -DSF_CONFIG_UNITY=1 15 | ) 16 | 17 | target_link_libraries(sheenfigure sheenbidi) 18 | -------------------------------------------------------------------------------- /svgutil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 Unicode Inc. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | import itertools 19 | 20 | 21 | def is_similar(a, b, maxDelta): 22 | if (a is not b) and (a is None or b is None): 23 | return False 24 | if a.tag != b.tag: 25 | return False 26 | for name, valueA in a.attrib.items(): 27 | valueB = b.attrib.get(name) 28 | if name in ("d", "viewBox", "x", "y"): 29 | if not is_similar_path(valueA, valueB, maxDelta): 30 | return False 31 | else: 32 | if valueA != valueB: 33 | return False 34 | for childA, childB in itertools.zip_longest(a, b): 35 | if not is_similar(childA, childB, maxDelta): 36 | return False 37 | return True 38 | 39 | 40 | def is_similar_path(a, b, maxDelta): 41 | for itemA, itemB in itertools.zip_longest(simplified_path(a), simplified_path(b)): 42 | if itemA is None or itemB is None: 43 | return False 44 | try: 45 | if abs(float(itemA) - float(itemB)) > maxDelta: 46 | return False 47 | except ValueError: 48 | if itemA != itemB: 49 | return False 50 | return True 51 | 52 | 53 | # http://codereview.stackexchange.com/a/88051 54 | def parse_path(path_data): 55 | digit_exp = "0123456789eE" 56 | comma_wsp = ", \t\n\r\f\v" 57 | drawto_command = "MmZzLlHhVvCcSsQqTtAa" 58 | sign = "+-" 59 | exponent = "eE" 60 | float = False 61 | entity = "" 62 | for char in path_data: 63 | if char in digit_exp: 64 | entity += char 65 | elif char in comma_wsp and entity: 66 | yield entity 67 | float = False 68 | entity = "" 69 | elif char in drawto_command: 70 | if entity: 71 | yield entity 72 | float = False 73 | entity = "" 74 | yield char 75 | elif char == ".": 76 | if float: 77 | yield entity 78 | entity = "." 79 | else: 80 | entity += "." 81 | float = True 82 | elif char in sign: 83 | if entity and entity[-1] not in exponent: 84 | yield entity 85 | float = False 86 | entity = char 87 | else: 88 | entity += char 89 | if entity: 90 | yield entity 91 | 92 | 93 | # Iterate path entities, removing subpaths consisting of only "moveto" commands. 94 | class simplified_path: 95 | def __init__(self, path_data): 96 | self.path = parse_path(path_data) 97 | self.subpath = [] 98 | 99 | def __iter__(self): 100 | return self 101 | 102 | def __next__(self): 103 | # Exhaust the current subpath before proceeding. 104 | if len(self.subpath): 105 | return self.subpath.pop(0) 106 | 107 | # Buffer the current subpath. 108 | for entity in self.path: 109 | self.subpath.append(entity) 110 | if entity in "Zz": 111 | only_moves = True 112 | for subentity in iter(self.subpath): 113 | if subentity in "MmZz": 114 | pass 115 | elif subentity in "LlHhVvCcSsQqTtAa": 116 | only_moves = False 117 | break 118 | if only_moves: 119 | self.subpath = [] 120 | else: 121 | break 122 | 123 | if len(self.subpath): 124 | return self.subpath.pop(0) 125 | else: 126 | raise StopIteration 127 | -------------------------------------------------------------------------------- /svgutil_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 Unicode Inc. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | import unittest 19 | import xml.etree.ElementTree as etree 20 | 21 | import svgutil 22 | 23 | SVG_A = etree.fromstring( 24 | """ 25 | 26 | 27 | """ 28 | ) 29 | 30 | SVG_B = etree.fromstring( 31 | """ 32 | 33 | 34 | """ 35 | ) 36 | 37 | SVG_C = etree.fromstring( 38 | """ 39 | 40 | 41 | """ 42 | ) 43 | 44 | SVG_D = etree.fromstring( 45 | """ 46 | 47 | 48 | """ 49 | ) 50 | 51 | 52 | class TestSVGHandling(unittest.TestCase): 53 | def test_is_similar(self): 54 | self.assertTrue(svgutil.is_similar(SVG_A, SVG_A, maxDelta=0.0)) 55 | self.assertFalse(svgutil.is_similar(SVG_A, SVG_B, maxDelta=1.0)) 56 | self.assertTrue(svgutil.is_similar(SVG_A, SVG_B, maxDelta=5.0)) 57 | self.assertFalse(svgutil.is_similar(SVG_A, SVG_C, maxDelta=1.0)) 58 | self.assertTrue(svgutil.is_similar(SVG_A, SVG_C, maxDelta=5.0)) 59 | self.assertTrue(svgutil.is_similar(SVG_A, SVG_D, maxDelta=0.0)) 60 | self.assertTrue(svgutil.is_similar(SVG_D, SVG_A, maxDelta=0.0)) 61 | 62 | def test_is_similar_path(self): 63 | self.assertTrue(svgutil.is_similar_path("M1,2 L3,4", "M1,2 L4,4", 1)) 64 | self.assertFalse(svgutil.is_similar_path("M1,2 L3,4", "M1,2 L1,4", 1)) 65 | 66 | def test_parse_path(self): 67 | self.assertEqual( 68 | " ".join(svgutil.parse_path("M 83.7,424 Q56,458Z")), "M 83.7 424 Q 56 458 Z" 69 | ) 70 | 71 | 72 | if __name__ == "__main__": 73 | unittest.main() 74 | -------------------------------------------------------------------------------- /testcases/CFF-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

CFF–3: Endchar With Five Arguments

10 |
11 | In the font for this test case, 12 | the glyphs Agrave and Udieresis pass five arguments 13 | to the endchar command. 14 | For a description of this particular variant of the endchar 15 | operator, see 16 | Adobe PostScript Technical Note #5177, Appendix C, 17 | at the bottom of page 35. See also OpenType.js bug 117 and fontkit bug 322. 18 |
19 |
20 | If the implementation under test works correctly, you should see 21 | the glyphs À and Ü. 22 |
23 | 24 | 25 | 26 | 34 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 53 |
Expected 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
Observed 46 | 47 |
Conformance 51 | 52 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /testcases/CMAP-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

CMAP–1: Ideographic Variation Sequences

12 | 13 |
14 | The Unicode 15 | Ideographic Variation Database defines glyph variants for Han 16 | ideographs. For example, Unicode supports two slightly different 17 | variants when rendering U+82A6 in Japanese; the font for this test 19 | case contains a type 14 ‘cmap’ table that implements them. 20 | With a conforming implementation, you should see four 21 | glyphs below. In the third glyph (U+82A6 U+E0101), the top stroke 22 | below the radical should be attached and slanting up. 23 | But in the first, second, and fourth glyph, that stroke should be 24 | detached and horizontal. If all four glyphs look the 25 | same, or if you see any black boxes in the renderings, it’s a sign 26 | that your implementation is broken. 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 44 | 45 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 66 | 67 |
82A6
82A6
E0100
82A6
E0101
82A6
E0102
Expected
Observed 55 | 56 | 57 | 58 |
Conformance 62 | 63 | 64 | 65 |
68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /testcases/CMAP-2.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

CMAP–2: Unicode Variation Selectors

12 | 13 |
14 | Unicode defines Standardized Variants of certain characters, including some 17 | Mathematical 18 | Symbols. The font for 19 | this test case contains a type 14 ‘cmap’ table that 20 | implements both the regular symbol ≩ U+2269 GREATER-THAN BUT NOT 21 | EQUAL TO, and its variant U+2269 U+FE00 GREATER-THAN BUT NOT EQUAL 22 | TO WITH VERTICAL STROKE. With a correct implementation, the two 23 | glyphs should look different. If the two glyphs look the same, or if 24 | you see any black boxes in the renderings, it’s a sign that your 25 | implementation is broken. 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 54 |
2269
2269
FE00
Expected
Observed 47 | 48 |
Conformance 52 | 53 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /testcases/GLYF-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

GLYF–1: Composite Glyphs

12 | 13 |
14 | The font for this test case 15 | has a ‘glyf’ table whose entry for U+0123 LATIN SMALL 16 | LETTER G WITH CEDILLA is a composite glyph. It has two 17 | components: one for the base glyph, and another one for the 18 | accent. A correct implementation must place the accent on top of the 19 | g. 20 |
21 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 38 | 39 |
Expected
Observed 32 |
Conformance 37 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /testcases/GPOS-3.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

GPOS–3: Mark-to-Base Attachment for Ethiopic Diacritics

12 | 13 |
14 | The font for this test case 15 | defines 16 | a Mark Positioning feature in 18 | its Glyph 19 | Positioning table. The feature uses 20 | a MarkToBase Attachment Positioning Subtable for placing Ethiopic 22 | diacritics on top of a base glyph. If your text rendering engine is 23 | correct, the dots (which indicate “long vowel”, “long 24 | consonant”, and “long consonant plus long vowel”) 25 | should be placed on top of the base glyph (the 26 | syllable “la”). If the dots appear to the right of the base 27 | glyph, or if they are missing entirely, it’s a sign that your text 28 | rendering system is broken. 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 47 | 48 | 50 | 51 | 53 | 54 | 55 | 56 | 57 | 62 | 63 | 64 | 65 | 70 |
U+1308
U+1308
U+135E
U+1308
U+135F
U+1308
U+135D
Expected
Observed 58 | 59 | 60 | 61 |
Conformance 66 | 67 | 68 | 69 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /testcases/GSUB-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

GSUB–1: Space Isn’t Nothing

12 | 13 |
14 | The font for this test case 15 | has a contextual alternates feature in its GSUB table that 16 | substitutes a by a.alt if followed by a 17 | space. Some versions of Adobe InDesign had a bug where space was 18 | treated like an empty substitution context. If your implementation 19 | is correct, you should see two different glyphs in the rendering: 20 | the first letter should have an overbar, the second letter should 21 | not. 22 |
23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 40 | 41 |
Expected
Observed 34 |
Conformance 39 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /testcases/GSUB-3.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

GSUB-3: Substituting a Billion Laughs

6 | 7 |
8 | The font for this test case 9 | is an OpenType version of the Billion 11 | laughs attack. Its GSUB table contains a sequence of 12 | nine identical lookups. Each lookup replaces the glyph o by 13 | the string olololololololololo, provided that the 14 | o is surrounded (both preceded and followed) by an 15 | l. The first lookup thus expands one single laugh 16 | (lol) into ten. The second lookup gives 100 laughs; the 17 | third 1000; the fourth 10,000; the fifth 100,000; and so forth. 18 | After executing the ninth lookup, the final result would be a 19 | billion laughs, but this takes a very long time (and large amounts 20 | of memory) to compute. If your implementation is immune to this 21 | attack, it should neither crash nor hang when rendering lol 22 | with this font. Instead, your implementation should stop executing 23 | once its internal buffer has reached a size limit. See also fontkit 25 | bug 221. 26 |
27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 39 |
ExpectedShouldn’t crash
Conformance 38 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /testcases/KERN-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

KERN–1

12 | 13 |
14 | The font for this test case 15 | contains a ‘kern’ table of format 0, which in turns 16 | contains a single format 0 subtable. Without kerning, the glyphs 17 | for T, u and the dotless ı will look like 18 | normal letters. However, if your implementation correctly applies 19 | the font’s kerning data, the shapes will join to form a geometric 20 | pattern. If you can still discern the original 21 | letters ıTuTuTı in the rendering, it’s a sign that your 22 | implementation fails to correctly handle kerning. 23 | See also HarfBuzz 24 | bug 1255. 25 |
26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 41 | 42 |
Expected
Observed 36 |
Conformance 40 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /testcases/KERN-2.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

KERN–2

12 | 13 |
14 | Although kerning is typically reducing space between 15 | letter pairs, it’s entirely valid for a font to increase it. 16 | This test verifies that an implementation can handle 17 | such kerning tables. If your implementation works correctly, 18 | you should see four groups separated by whitespace. 19 |
20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 35 | 36 |
Expected
Observed 30 |
Conformance 34 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /testcases/MORX-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

MORX–1: Non-Contextual Glyph Substitution

12 | 13 |
14 | The font for this test case contains 15 | an AAT Extended Glyph Metamorphosis Table 17 | with a single Non-Contextual Glyph Substitution Subtable, 18 | replacing the glyphs A and C by alternate forms. 19 | If your renderer supports 20 | Apple 21 | Advanced Typography, 22 | the letters A and C should be white on black whereas the letter B 23 | should appear inside a stroked circle. 24 |
25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 41 | 42 |
Expected
Observed 36 |
Conformance 40 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /testcases/MORX-10.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

MORX–10: “End of Text” Rearrangement

12 | 13 |
14 | The font for this test case has 15 | an AAT Extended Glyph Metamorphosis Table 17 | with a single Rearrangement Subtable. Its finite-state machine 18 | contains one single state with the following transitions: 19 |
20 | 21 |
    22 |
  • For glyph A, the machine sets both start 23 | and end of the marked glyph sequence to the current 24 | glyph position.
  • 25 | 26 |
  • For glyph B, the machine changes the end of the 27 | marked glyph sequence to the current position.
  • 28 | 29 |
  • For “end of text”, the machine executes a rearrangement action.
  • 30 |
31 | 32 |
33 | If your rendering system correctly implements Apple Advanced 34 | Typography, it should swap the last two letters in ABABAB 35 | when taking the final end-of-text transition. See also 36 | fontkit 37 | bug 144. 38 |
39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 54 |
Expected
Observed 49 |
Conformance 53 |
55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /testcases/MORX-11.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX–11: “End of Text” Rearrangement with MarkLast Flag

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Rearrangement Subtable. Its finite-state machine 12 | contains one single state with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A, the machine sets both start 17 | and end of the marked glyph sequence to the current 18 | glyph position.
  • 19 | 20 |
  • For “end of text”, the machine changes the end of the 21 | marked glyph sequence to the current position and 22 | executes a rearrangement action of type 2, which moves the 23 | last marked glyph to the front of the marked sequence.
  • 24 | 25 |
  • For any other glyphs, the machine performs no action.
  • 26 |
27 | 28 |
29 | The input string for this test case is BABBAABX. If your 30 | rendering system correctly implements Apple Advanced 31 | Typography, the finite-state machine should have marked the 32 | last A (the third-last glyph in the input string) before 33 | taking the final end-of-text transition. When processing 34 | end-of-text, your implementation should first extend the marked 35 | glyph sequence to the trailing ABX, and then perform a 36 | rearrangement for moving X to the front of the marked 37 | sequence. See also fontkit bug 145. 38 |
39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 54 |
Expected
Observed 49 |
Conformance 53 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /testcases/MORX-13.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-13: Rearrangement with DontAdvance and MarkLast

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Rearrangement Subtable. Its finite-state machine 12 | contains two states (0 and 1) with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A, the machine stays in its current 17 | state. As a side effect, it sets both start 18 | and end of the marked glyph sequence to the 19 | current glyph position.
  • 20 | 21 |
  • For glyphs B, C, and D, the machine stays 22 | in its current state. As a side effect, it sets both start 23 | and end of the marked glyph sequence to the 24 | current glyph position.
  • 25 | 26 |
  • For glyph E,
  • 27 |
      28 |
    • from state 0, the machine makes a transition to state 1. 29 | This transition carries both the DontAdvance and 30 | MarkLast flags. No rearrangement action is performed.
    • 31 | 32 |
    • from state 1, the machine stays in state 1. The transition 33 | carries no flags. However, it peforms a rearrangement of type 1 34 | which moves the first marked glyph to the end of the marked 35 | glyph sequence.
    • 36 |
    37 | 38 |
  • For any other glyphs and “end of text”, the machine performs 39 | no action.
  • 40 |
41 | 42 |
43 | The input string for this test case is ABCDE. If your 44 | rendering system correctly implements Apple Advanced 45 | Typography, the finite-state machine should extend 46 | the marked glyph range to include E when the state 47 | changes from 0 to 1, even though the current position is not 48 | advancing. As a result, the final string after rearrangement should 49 | be BCDEA. If your implementation produces BCDAE 50 | or another order, it fails to handle state transitions that carry 51 | both the DontAdvance and MarkLast flags. 52 |
53 | 54 | 55 | 56 | 57 | 59 | 60 | 61 | 62 | 64 | 65 | 66 | 68 |
Expected
Observed 63 |
Conformance 67 |
69 | 70 | 71 | -------------------------------------------------------------------------------- /testcases/MORX-16.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-16: Rearrangement with DontAdvance and MarkFirst

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Rearrangement Subtable. Its finite-state machine 12 | contains two states (0 and 1) with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A:
  • 17 |
      18 |
    • in state 0, the machine moves to state 1. 19 | This transition carries both the DontAdvance and 20 | MarkFirst flags. No rearrangement action is performed.
    • 21 | 22 |
    • in state 1, the machine moves to state 0. 23 | This transition carries no flags. 24 | No rearrangement action is performed.
    • 25 |
    26 | 27 |
  • For glyphs B, C, and D, the machine stays 28 | in its current state. As a side effect, it sets the end 29 | of the marked glyph sequence to the current glyph position.
  • 30 | 31 |
  • For glyph E, the machine stays in its current state. 32 | As a side effect, it sets the end 33 | of the marked glyph sequence to the current glyph position, 34 | and executes a rearrangement action of type 1 (Ax ⇒ xA).
  • 35 | 36 |
  • For any other glyphs and “end of text”, the machine performs 37 | no action.
  • 38 |
39 | 40 |
41 | The input string for this test case is ABCDE. 42 | If your rendering system correctly implements Apple Advanced 43 | Typography, the A glyph should be rearranged to the 44 | end of the rendered string, resulting in BCDEA. 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 66 |
ABCDE
Expected
Observed 61 |
Conformance 65 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /testcases/MORX-17.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-17: Rearrangement with DontAdvance at End of Text

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Rearrangement Subtable. Its finite-state machine 12 | contains a single state with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A, the transition carries the 17 | MarkFirst flag. No rearrangement action is performed.
  • 18 | 19 |
  • For glyph B, the transition carries the 20 | MarkLast flag. No rearrangement action is performed.
  • 21 | 22 |
  • For End of text, the transition carries the 23 | DontAdvance flag and performs a rearrangement action 24 | of type 1 (Ax ⇒ xA).
  • 25 | 26 |
  • For any other glyphs, the machine performs no action.
  • 27 |
28 | 29 |
30 | The input string for this test case is AB. 31 | If your rendering system correctly implements Apple Advanced 32 | Typography, the A glyph should be rearranged to the 33 | end of the rendered string when your implementation executes the 34 | rearrangement for the End-of-text transition. Despite the presence 35 | of the DontAdvance flag, the result should be BA. 36 | See also fontkit 37 | bug 147. 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 58 |
AB
Expected
Observed 53 |
Conformance 57 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /testcases/MORX-19.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-19: Contextual Glyph Substitution without Marking

6 | 7 |
8 | The font for this test 9 | case is the same as with MORX–18. In this 10 | test, we do not render the B letter, so there are no marked 11 | glyphs. If your rendering system correctly implements Apple 12 | Advanced Typography, it should implicitly mark the first letter 13 | of the rendered string, so the output should look as expected. 14 | See also Fontkit bug 150. 16 |
17 | 18 | 19 | 20 | 21 | 23 | 24 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 37 |
Expected
Observed 30 | 31 |
Conformance 35 | 36 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /testcases/MORX-21.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-21: Contextual Glyph Substitution with SetMark

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Contextual Glyph Substitution Subtable. Its finite-state machine 12 | contains a single state with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph B, the transition carries the 17 | SetMark flag.
  • 18 | 19 |
  • For glyph D, the transition carries the 20 | SetMark flag. Also, it replaces the marked glyph 21 | with a circled form.
  • 22 |
23 | 24 |
25 | The input string for this test is ABCDE. If your rendering 26 | system correctly implements Apple Advanced Typography, it 27 | should do the following when processing the transition 28 | for D: first, it should replace the marked glyph B 29 | by a circled form. Second, it should reset the marked glyph index 30 | to D. Therefore, only the B letter should 31 | be encircled in the rendered result. If the D is encircled, 32 | your implementation should be fixed to reset the marked glyph index 33 | after performing the replacement. 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 54 |
ABCDE
Expected
Observed 49 |
Conformance 53 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /testcases/MORX-22.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-22: Contextual Glyph Substitution with MarkIndex and CurrentIndex

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Contextual Glyph Substitution Subtable. Its finite-state machine 12 | contains two states (0 and 1) with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A:
  • 17 |
      18 | 19 |
    • In state 0, the machine moves to state 1 using a transition 20 | that carries both the SetMark and DontAdvance flags.
    • 21 | 22 |
    • In state 1, the machine moves back to state 0 using a transition 23 | that executes glyph substitution #0 on the marked glyph, and 24 | also glyph substitution #1 on the current glyph.
    • 25 |
    26 |
27 | 28 |
29 | The input string for this test is A. If your rendering 30 | system implements Apple Advanced Typography, 31 | both MarkIndex and CurrentIndex will affect the 32 | same glyph. If your implementation is correct, it should 33 | first execute the glyph substitution for MarkIndex 34 | to replace A by B. Then, it should 35 | execute the glyph substitution for CurrentIndex, 36 | which replaces B (the result of the previous substitution) 37 | by C. Therefore, the final result should be C. 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 58 |
A
Expected
Observed 53 |
Conformance 57 |
59 | 60 | 61 | -------------------------------------------------------------------------------- /testcases/MORX-23.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-23: Contextual Glyph Substitution with CurrentIndex and DontAdvance

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Contextual Glyph Substitution Subtable. 12 | Its finite-state machine contains one state. For glyphs 13 | glyphs A, B, C, and D, 14 | the machine executes the per-glyph substitution #0 15 | on CurrentIndex on a transition that is also marked 16 | with the DontAdvance flag. The glyph substitution 17 | replaces A by B, B by C, 18 | C by D, and D by E. 19 |
20 | 21 |
22 | The input string for this test is ABCDE. If your rendering 23 | system correctly implements Apple Advanced Typography, the 24 | finite-state machine should loop for each glyph in state 0 until it 25 | gets rewritten to E. The final result should be EEEEE. 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 42 | 43 | 44 | 46 |
ABCDE
Expected
Observed 41 |
Conformance 45 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /testcases/MORX-24.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-24: Contextual Glyph Subsitution Forever

6 | 7 |
8 | The font for this 9 | test case attempts to run a denial-of-service attack on the 10 | rendering engine under test. The font’s finite-state transducer 11 | substitutes glyph A by B, B by C, 12 | C by D, D by E, 13 | and E by A. These transitions are all marked with 14 | the DontAdvance flag, so the machine never makes progress. 15 |
16 | 17 |
18 | If your rendering system is immune to this attack, it will detect 19 | getting stuck (for example, by imposing an upper limit on the number 20 | of transitions taken by the finite-state machine), and give up quickly. 21 | See fontkit 22 | bug 175. 23 |
24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 36 | 37 |
ExpectedShouldn’t crash
Conformance 35 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /testcases/MORX-26.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-26: Another State Machine for Contextual Glyph Substitution

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Contextual Glyph Substitution Subtable. Its 12 | finite-state machine contains two states (0 and 1). In state 0, 13 | glyph A moves to state 1; glyphs B, C, D, E get 14 | replaced by an encircled form. In state 1, no substitution happens. 15 | If your implementation is correct, the input string AB 16 | should not get any substitutions, but a stand-alone B 17 | should get rendered inside a circle. 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 44 |
ABB
Expected
Observed 37 | 38 |
Conformance 42 | 43 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /testcases/MORX-27.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-27: Ligature Substitution

6 | 7 |
8 | The font for this 9 | test case has 10 | an AAT Extended Glyph Metamorphosis Table with a 12 | single Ligature Subtable to sustitute the 13 | strings AEB, AEC and AED by ligatures. 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 30 | 31 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 46 |
AEBAECAED
Expected
Observed 37 | 38 | 39 |
Conformance 43 | 44 | 45 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /testcases/MORX-33.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-33: Twice the Fun

6 | 7 |
8 | The font for this 9 | test case has 10 | an AAT Extended Glyph Metamorphosis Table 12 | with a single Glyph Insertion Subtable. When consuming 13 | glyph ‘h’ in state 0, its finite-state machine transitions 14 | to state 1. When consuming 15 | glyph ‘a’ in state 1, its finite-state machine transitions 16 | back to state 0 while also inserting the string “ha”. 17 | If your implementation is correct, every ha in the input 18 | should get rendered twice. 19 |
20 | 21 |
22 | See also Apple 23 | Radar bug 44902550. 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 59 | 60 |
 hahahaah
Expected
Observed 49 | 50 | 51 |
Conformance 56 | 57 | 58 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /testcases/MORX-34.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-34: Inserting a Billion Laughs

6 | 7 |
8 | The font for this 9 | test case is an AAT version of the 10 | Billion 11 | laughs attack. It contains 12 | an AAT Extended Glyph Metamorphosis Table with nine 14 | identical Glyph Insertion Subtables whose embedded 15 | finite-state machine inserts the 16 | string hahahahahahahahahaha for every a in the 17 | input string. If the input is “ha” (one single laugh), the first 18 | subtable rewrites it to 10 laughs. The second subtable rewrites 10 19 | to 100 laughs; the third goes from 100 to 1000; the fourth from 1000 20 | to 10,000. After executing the ninth subtable, the final result 21 | will be a billion laughs, but this will take a very long time (and 22 | large amounts of memory) to compute. Your implementation should 23 | neither crash nor hang under attack. See also 24 | fontkit bug 174. 25 |
26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 37 |
ExpectedShouldn’t crash
Conformance 36 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /testcases/MORX-35.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-35: Insertion with DontAdvance

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Glyph Insertion Subtable. Its finite-state machine 12 | contains two states (0 and 1) with the following transitions: 13 |
14 | 15 |
    16 |
  • For glyph A
  • 17 |
      18 |
    • in state 0, the machine moves to state 1 while inserting 19 | C after the current position. 20 | This transition carries the DontAdvance flag.
    • 21 | 22 |
    • in state 1, the machine moves to state 0 while inserting 23 | B after the current position. 24 | This transition carries no flags.
    • 25 |
    26 | 27 |
  • For glyphs B and C, the machine stays 28 | in its current state while inserting E to the right of 29 | the current position. This transition carries no flags.
  • 30 | 31 |
  • For any other glyphs and “end of text”, the machine performs 32 | no action.
  • 33 |
34 | 35 |
36 | See also HarfBuzz 37 | bug 1224. 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 51 | 53 | 54 | 55 | 56 | 59 | 60 | 61 | 64 |
AXAY
Expected
Observed 57 | 58 |
Conformance 62 | 63 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /testcases/MORX-36.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-36: Insertion forever

6 | 7 |
8 | The font for this test case has 9 | an AAT Extended Glyph Metamorphosis Table 11 | with a single Glyph Insertion Subtable. Its finite-state machine 12 | contains three states (0, 1 and 2) with the following transitions: 13 |
14 | 15 |
    16 | 17 |
  • 18 | In state 0, the machine moves to state 1 for any glyph in 19 | {A, B, C, D} while inserting B after 20 | the current position. This transition carries the 21 | DontAdvance flag. 22 |
  • 23 | 24 |
  • 25 | In state 1, the machine moves to state 2 for any glyph in 26 | {A, B, C, D} while inserting C after 27 | the current position. This transition carries the 28 | DontAdvance flag. 29 |
  • 30 | 31 |
  • 32 | In state 2, the machine moves to state 0 for any glyph in 33 | {A, B, C, D} while inserting D after 34 | the current position. This transition carries the 35 | DontAdvance flag. 36 |
  • 37 | 38 |
  • Otherwise, the machine performs no action.
  • 39 |
40 | 41 |
42 | The input string for this test case is A. 43 | Your implementation should not hang (run without time limit) 44 | nor crash while rendering this input, even though the font is 45 | trying to trick the rendering engine into an infinite loop. 46 |
47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 59 |
ExpectedShouldn’t crash
Conformance 58 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /testcases/MORX-41.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 |

MORX-41: Ligature Substitution Under-/Overflow

6 | 7 |
8 | The font for this test 9 | case has 10 | an AAT Extended Glyph Metamorphosis Table with a 12 | single Ligature Subtable whose finite-state machine has one 13 | single state. For glyphs a and b, the transition 14 | marks the current glyph. For glyph c, the transition also 15 | marks the current glyph, and then it executes an action to substitue 16 | the marked glyphs by a ligature. When rendering the 17 | strings ac and bc, the implementation finds two 18 | glyphs on its glyph stack, which should get replaced by the 19 | corresponding ligature. When rendering the string cc, 20 | the implementation is asked to pop two glyphs from a stack 21 | that contains just one. When rendering abcc, 22 | the stack will contain three glyphs when handling the 23 | first c. 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 41 | 42 | 44 | 45 | 47 | 48 | 49 | 50 | 55 | 56 | 57 | 62 |
acbcccabcc
ExpectedNo crashNo crash
Observed 51 | 52 | 53 | 54 |
Conformance 58 | 59 | 60 | 61 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /testcases/MORX-7.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

MORX–7: Unstarted Rearrangement

12 | 13 |
14 | The font for this test case 15 | is the same as in MORX–2. When rendering the 16 | string OBCD1, we set the end of the marked glyph sequence 17 | to B; then we change it to C; finally, to D. 18 | However, we never set the start of the marked glyph sequence. 19 | If your rendering engine is correctly implemented, it should implicitly 20 | start the marked glyph range at the beginning of the string, 21 | and move the O after the D when executing the 22 | rearrangement for 1. 23 |
24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 39 |
Expected
Observed 34 |
Conformance 38 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /testcases/MORX-9.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

MORX–9: “Out of Bounds” Rearrangement

12 | 13 |
14 | The font for this test case has 15 | an AAT Extended Glyph Metamorphosis Table 17 | with a single Rearrangement Subtable. Its finite-state machine 18 | contains one single state with the following transitions: 19 |
20 | 21 |
    22 |
  • For glyph A, the machine sets both start 23 | and end of the marked glyph sequence to the current 24 | glyph position.
  • 25 | 26 |
  • For glyph B, the machine changes the end of the 27 | marked glyph sequence to the current position.
  • 28 | 29 |
  • For any other glyph (“out of bounds”), the machine executes a 30 | rearrangement action.
  • 31 |
32 | 33 |
34 | If your rendering system correctly implements Apple Advanced 35 | Typography, it should swap the first two letters in ABXAB. 36 |
37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | 53 |
Expected
Observed 48 |
Conformance 52 |
54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /testcases/SFNT-1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

SFNT–1: OpenType with PostScript Outlines

12 | 13 |
14 | The font for this test case, 15 | contributed by Simon 16 | Cozens, contains glyphs outlines in both CFF 17 | and glyf format. Because 18 | the Offset Table uses an sfntVersion of 20 | 0x4F54544F (‘OTTO’), your rendering engine should take the glyph 21 | outlines from the CFF table. If you see CFF below 22 | the characters A and B, your rendering engine 23 | makes correct use of the sfntVersion field. 24 | See also fontkit bug 214 and OpenType.js bug 419. 25 |
26 | 27 | 28 | 29 | 30 | 32 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 45 | 46 |
Expected
Observed 38 | 39 |
Conformance 43 | 44 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /testcases/SFNT-2.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

SFNT–2: OpenType with TrueType Outlines

12 | 13 |
14 | The font for this test case, 15 | contributed by Simon 16 | Cozens, contains glyphs outlines in both CFF 17 | and glyf format. Because 18 | the Offset Table uses an sfntVersion of 0x00010000, your 20 | rendering engine should take the glyph outlines from 21 | the glyf table. If you see glyf below the 22 | characters A and B, your rendering engine makes 23 | correct use of the sfntVersion field. 24 |
25 | 26 | 27 | 28 | 29 | 31 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 44 | 45 |
Expected
Observed 37 | 38 |
Conformance 42 | 43 |
46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /testcases/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Test Report for Rendering Engine “

10 |

11 |

Overview

12 |
13 | This report was generated on by running 14 | Unicode’s test suite for text rendering engines with 16 | . 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /testcases/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Vollkorn, serif; 3 | font-weight: 400; 4 | } 5 | .desc { 6 | margin-left:3em; 7 | margin-bottom:.5em; 8 | } 9 | h1 {text-align:center; margin:2em 2em .5em 2em} 10 | h2 { 11 | font-weight:400; font-style:italic; 12 | text-align:center; margin:0 2em 3em 2em 13 | } 14 | h3 { 15 | font-size:160%; 16 | font-weight:400; text-align:left; font-style:italic; 17 | margin-top:1.5em; 18 | margin-left:1em; 19 | margin-bottom:.5em; 20 | } 21 | table { 22 | margin: 1.5em 3.4em; 23 | padding: 0; 24 | text-align: center; 25 | font-size: 80%; 26 | } 27 | th { 28 | text-align: left; 29 | font-weight: 400; 30 | font-style: italic; 31 | margin: 0; 32 | padding: 0 0.5em; 33 | } 34 | th.conformance-header {line-height:2.5em} 35 | td {margin:0; padding:0 0.5em} 36 | td.conformance-pass {color:#3c7;font-size:150%} 37 | td.conformance-fail {color:#c33;font-size:150%} 38 | th.conformance {line-height:2.5em} 39 | svg {height:2.5em;transform:scaleY(-1)} 40 | --------------------------------------------------------------------------------