├── source ├── lib │ ├── __init__.py │ ├── MutatorScale │ │ ├── lib │ │ │ ├── __init__.py │ │ │ ├── mutatorScale │ │ │ │ ├── pens │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── utilityPens.py │ │ │ │ ├── objects │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── errorGlyph.py │ │ │ │ │ └── fonts.py │ │ │ │ ├── utilities │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── numbersUtils.py │ │ │ │ │ └── fontUtils.py │ │ │ │ └── __init__.py │ │ │ ├── testFonts │ │ │ │ ├── two-axes │ │ │ │ │ ├── bold-high-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ ├── fontinfo.plist │ │ │ │ │ │ └── lib.plist │ │ │ │ │ ├── bold-low-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ ├── fontinfo.plist │ │ │ │ │ │ └── lib.plist │ │ │ │ │ ├── bold-italic-low-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ ├── fontinfo.plist │ │ │ │ │ │ └── lib.plist │ │ │ │ │ ├── regular-high-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ └── fontinfo.plist │ │ │ │ │ ├── regular-low-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ └── fontinfo.plist │ │ │ │ │ └── regular-italic-low-contrast.ufo │ │ │ │ │ │ ├── glyphs │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ └── H_.glif │ │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ │ └── fontinfo.plist │ │ │ │ └── isotropic-anisotropic │ │ │ │ │ ├── bold-mid-contrast.ufo │ │ │ │ │ ├── glyphs │ │ │ │ │ │ ├── B_.glif │ │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ │ ├── contents.plist │ │ │ │ │ │ ├── I_.glif │ │ │ │ │ │ ├── A_.glif │ │ │ │ │ │ ├── O_.glif │ │ │ │ │ │ └── H_.glif │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ ├── fontinfo.plist │ │ │ │ │ └── lib.plist │ │ │ │ │ └── regular-mid-contrast.ufo │ │ │ │ │ ├── glyphs │ │ │ │ │ ├── B_.glif │ │ │ │ │ ├── Aacute_.glif │ │ │ │ │ ├── contents.plist │ │ │ │ │ ├── I_.glif │ │ │ │ │ ├── A_.glif │ │ │ │ │ ├── O_.glif │ │ │ │ │ └── H_.glif │ │ │ │ │ ├── metainfo.plist │ │ │ │ │ ├── fontinfo.plist │ │ │ │ │ └── lib.plist │ │ │ ├── robofont-test.py │ │ │ └── test-no-UI.py │ │ ├── images │ │ │ ├── mutatorScale-1.png │ │ │ ├── mutatorScale-2.png │ │ │ ├── mutatorScale-3.png │ │ │ ├── mutatorScale-4.png │ │ │ ├── mutatorScale-5.png │ │ │ └── mutatorScale-6.png │ │ ├── .gitignore │ │ ├── setup.py │ │ ├── LICENSE.txt │ │ └── Readme.md │ └── dynamicParameters │ │ ├── lib │ │ └── dynamicParameters │ │ │ ├── __init__.py │ │ │ ├── parameterTest-Robofont.py │ │ │ ├── vanillaParameterObjects.py │ │ │ └── baseParameter.py │ │ ├── slider-parameters.png │ │ ├── License.txt │ │ └── README.md └── html │ ├── images │ ├── scalefast-1.png │ ├── scalefast-2.png │ ├── scalefast-3.png │ ├── scalefast-4.png │ ├── scalefast-5.png │ ├── scalefast-6.png │ ├── scalefast-7.png │ ├── scalefast-8.png │ ├── scalefast-9.png │ ├── example-scalefast-1.png │ ├── example-scalefast-2.png │ ├── example-scalefast-3.png │ ├── example-scalefast-4.png │ ├── example-scalefast-5.png │ ├── example-scalefast-6.png │ └── example-scalefast-7.png │ └── index.md ├── .gitignore ├── README.md ├── .github └── workflows │ └── validate_build.yml ├── info.yaml └── notes.md /source/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .DS_Store 3 | */.DS_Store 4 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/pens/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/objects/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/utilities/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/lib/dynamicParameters/lib/dynamicParameters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.4" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ScaleFast 2 | ========= 3 | 4 | Documentation is [here](source/html/index.md) -------------------------------------------------------------------------------- /source/html/images/scalefast-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-1.png -------------------------------------------------------------------------------- /source/html/images/scalefast-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-2.png -------------------------------------------------------------------------------- /source/html/images/scalefast-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-3.png -------------------------------------------------------------------------------- /source/html/images/scalefast-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-4.png -------------------------------------------------------------------------------- /source/html/images/scalefast-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-5.png -------------------------------------------------------------------------------- /source/html/images/scalefast-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-6.png -------------------------------------------------------------------------------- /source/html/images/scalefast-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-7.png -------------------------------------------------------------------------------- /source/html/images/scalefast-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-8.png -------------------------------------------------------------------------------- /source/html/images/scalefast-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/scalefast-9.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-1.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-2.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-3.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-4.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-5.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-6.png -------------------------------------------------------------------------------- /source/html/images/example-scalefast-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/html/images/example-scalefast-7.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-1.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-2.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-3.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-4.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-5.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/images/mutatorScale-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/MutatorScale/images/mutatorScale-6.png -------------------------------------------------------------------------------- /source/lib/dynamicParameters/slider-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboDocs/ScaleFast/HEAD/source/lib/dynamicParameters/slider-parameters.png -------------------------------------------------------------------------------- /source/lib/MutatorScale/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.idea 3 | *.pyc 4 | *.sublime-project 5 | *.sublime-workspace 6 | lib/scaleFast-0.6.py 7 | build/ 8 | lib/tests/ -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/B_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/Aacute_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/validate_build.yml: -------------------------------------------------------------------------------- 1 | name: Validate and Build the Extension 2 | on: 3 | push 4 | 5 | jobs: 6 | validate_and_build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Validate and Build 10 | uses: typemytype/roboFont-Extension-action@v0.1.0 11 | with: 12 | autotagging: true -------------------------------------------------------------------------------- /info.yaml: -------------------------------------------------------------------------------- 1 | name: ScaleFast 2 | developer: "Loïc Sander" 3 | developerURL: https://github.com/loicsander 4 | launchAtStartUp: false 5 | mainScript: '' 6 | version: '1.1' 7 | addToMenu: 8 | - path: scaleFast.py 9 | preferredName: ScaleFast 10 | shortKey: '' 11 | html: true 12 | requiresVersionMajor: '3' 13 | requiresVersionMinor: '2' 14 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/metainfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | creator 6 | org.robofab.ufoLib 7 | formatVersion 8 | 2 9 | 10 | 11 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | Developer Notes 2 | =============== 3 | 4 | The ScaleFast extension contains code from two external modules: 5 | 6 | - [dynamicParameters](http://github.com/roboDocs/dynamicParameters) 7 | - [mutatorScale](http://github.com/roboDocs/MutatorScale) 8 | 9 | These modules are included in ScaleFast using `git subtree`. 10 | 11 | See [Git Subtree Merge](http://johnatten.com/2013/03/16/git-subtree-merge-the-quick-version/) for reference. 12 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/contents.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A 6 | A_.glif 7 | Aacute 8 | Aacute_.glif 9 | B 10 | B_.glif 11 | H 12 | H_.glif 13 | I 14 | I_.glif 15 | O 16 | O_.glif 17 | 18 | 19 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/utilities/numbersUtils.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from __future__ import division 3 | 4 | def mapValue(value, values1, values2): 5 | ''' 6 | For a value provided with an initial set of reference values, 7 | returns a new one proportionally defined between a second set of values. 8 | ''' 9 | lowValue1, highValue1 = values1 10 | lowValue2, highValue2 = values2 11 | 12 | delta1 = highValue1 - lowValue1 13 | delta2 = highValue2 - lowValue2 14 | if delta1 != 0: 15 | factor = (value - lowValue1) / delta1 16 | value = lowValue2 + (delta2 * factor) 17 | return value -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/robofont-test.py: -------------------------------------------------------------------------------- 1 | from mutatorScale.objects.scaler import MutatorScaleEngine 2 | 3 | # To test this, open some interpolatable fonts (if you don’t have any (duh?), use those in the TestFonts folder) 4 | 5 | fonts = [font for font in AllFonts() if font.info.familyName != 'Output'] 6 | 7 | scaler = MutatorScaleEngine(fonts) 8 | scaler.set({ 9 | 'scale':(0.85, 0.8) 10 | }) 11 | 12 | f = RFont(showInterface=False) 13 | f.info.familyName = 'Output' 14 | 15 | for glyphName in ['A','H','I','O']: 16 | stemValues = (100, 70) 17 | g = scaler.getScaledGlyph(glyphName, stemValues) 18 | f.insertGlyph(g, glyphName) 19 | 20 | f.openInterface() 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from distutils.core import setup 4 | 5 | setup(name = "MutatorScale", 6 | version = "0.6", 7 | description = "Tool for interpolated glyph scaling, based on Robofab, FontTools & MutatorMath.", 8 | author = "Loic Sander", 9 | author_email = "loic@akalollip.com", 10 | url = "https://github.com/loicsander/MutatorScale", 11 | license = "MIT", 12 | packages = [ 13 | "mutatorScale", 14 | "mutatorScale.booleanOperations", 15 | "mutatorScale.objects", 16 | "mutatorScale.pens", 17 | "mutatorScale.utilities", 18 | ], 19 | package_dir = {"":"lib"}, 20 | ) 21 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/test-no-UI.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | from mutatorScale.objects.scaler import MutatorScaleEngine 4 | from mutatorScale.utilities.fontUtils import intersect 5 | 6 | from fontParts.fontshell import RFont 7 | 8 | paths = [ 9 | 'testFonts/two-axes/regular-low-contrast.ufo', 10 | 'testFonts/two-axes/bold-low-contrast.ufo' 11 | ] 12 | outputPath = 'testFonts/two-axes/scaled-low-contrast.ufo' 13 | 14 | fonts = [] 15 | for p in paths: 16 | fonts.append(RFont(p)) 17 | 18 | scaler = MutatorScaleEngine(fonts) 19 | scaler.set({ 20 | 'scale' : (0.85, 0.8) 21 | }) 22 | 23 | outputFont = RFont() 24 | for glyphName in 'AHIO': 25 | glyph = scaler.getScaledGlyph(glyphName, (95, 75)) 26 | outputFont.insertGlyph(glyph, glyphName) 27 | 28 | outputFont.save(outputPath) -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/I_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Low Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Bold 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test High Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Bold 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Low Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Regular 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test High Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Regular 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Mid Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Bold 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Low Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Bold Italic 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Mid Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Regular 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/fontinfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ascender 6 | 750 7 | capHeight 8 | 750 9 | descender 10 | -250 11 | familyName 12 | Test Low Contrast 13 | postscriptBlueValues 14 | 15 | 16 | postscriptFamilyBlues 17 | 18 | 19 | postscriptFamilyOtherBlues 20 | 21 | 22 | postscriptOtherBlues 23 | 24 | 25 | postscriptStemSnapH 26 | 27 | 28 | postscriptStemSnapV 29 | 30 | 31 | styleName 32 | Regular Italic 33 | unitsPerEm 34 | 1000 35 | xHeight 36 | 500 37 | 38 | 39 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Loïc Sander 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. -------------------------------------------------------------------------------- /source/lib/dynamicParameters/License.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Loïc Sander 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 | -------------------------------------------------------------------------------- /source/lib/dynamicParameters/lib/dynamicParameters/parameterTest-Robofont.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | dynamicParametersLibFolder = os.path.dirname(os.getcwd()) 5 | if not dynamicParametersLibFolder in sys.path: 6 | sys.path.insert(0, dynamicParametersLibFolder) 7 | 8 | from dynamicParameters.vanillaParameterObjects import ParameterSliderTextInput, VanillaSingleValueParameter 9 | from vanilla import Window, Group 10 | 11 | class ParameterTester: 12 | 13 | def __init__(self): 14 | self.w = Window((300, 100)) 15 | self.w.inner = Group((10, 10, -10, -10)) 16 | 17 | p1 = VanillaSingleValueParameter('main', 10, (0, 100), 'int') 18 | p2 = VanillaSingleValueParameter('ratio', 10, (0, 100), 'int', master=p1, mode='ratio', dissociable=True) 19 | p3 = VanillaSingleValueParameter('offset', 10, (0, 100), 'int', master=p1, mode='offset', dissociable=True) 20 | 21 | self.w.inner.p1 = ParameterSliderTextInput(p1, (0, 0, -0, 22), 'master') 22 | self.w.inner.p2 = ParameterSliderTextInput(p2, (0, 25, -0, 22), 'ratio') 23 | self.w.inner.p3 = ParameterSliderTextInput(p3, (0, 50, -0, 22), 'offset') 24 | self.w.open() 25 | 26 | ParameterTester() 27 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/A_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-high-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-low-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/O_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/regular-italic-low-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/glyphs/H_.glif: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/pens/utilityPens.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from fontTools.pens.basePen import BasePen 3 | 4 | try: # RF >= 3.3b 5 | from fontTools.pens.pointPen import AbstractPointPen 6 | except: 7 | from ufoLib.pointPen import AbstractPointPen 8 | 9 | 10 | class ClockwiseTestPointPen(AbstractPointPen): 11 | 12 | def __init__(self): 13 | self._points = [] 14 | 15 | def beginPath(self): 16 | pass 17 | 18 | def endPath(self): 19 | pass 20 | 21 | def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): 22 | if segmentType: 23 | # overlapping points can give false results, so filter them out 24 | if self._points and self._points[-1] == pt: 25 | return 26 | self._points.append(pt) 27 | 28 | def getIsClockwise(self): 29 | points = self._points 30 | pointCount = len(points) 31 | # overlapping moves can give false results, so filter them out 32 | if points[0] == points[-1]: 33 | del points[-1] 34 | total = 0 35 | 36 | for index1 in xrange(pointCount): 37 | index2 = (index1 + 1) % pointCount 38 | x1, y1 = points[index1] 39 | x2, y2 = points[index2] 40 | total += (x1*y2)-(x2*y1) 41 | 42 | return total < 0 43 | 44 | class CollectSegmentsPen(BasePen): 45 | 46 | def __init__(self, glyphSet): 47 | self.glyphSet = glyphSet 48 | self.contours = [] 49 | 50 | def _moveTo(self, pt): 51 | self.segments = [] 52 | self.previousPoint = pt 53 | 54 | def _lineTo(self, pt): 55 | self.segments.append((self.previousPoint, pt)) 56 | self.previousPoint = pt 57 | 58 | def _curveToOne(self, pt1, pt2, pt3): 59 | self.segments.append((self.previousPoint, pt1, pt2, pt3)) 60 | self.previousPoint = pt3 61 | 62 | def endPath(self): 63 | self.contours.append(self.segments) 64 | 65 | def closePath(self): 66 | self.segments.append((self.previousPoint, self.segments[0][0])) 67 | self.contours.append(self.segments) 68 | 69 | def getSegments(self): 70 | return self.contours -------------------------------------------------------------------------------- /source/lib/dynamicParameters/README.md: -------------------------------------------------------------------------------- 1 | Dynamic Parameters 2 | ================== 3 | 4 | ## SingleValueParameter 5 | *(baseParameter.py)* 6 | 7 | This is an almost simple & independent object built to help defining values in relation to others, on a master/slave basis. 8 | Each instance of the SingleValueParameter bears a value and is either a master or a slave (or both). There’s no ideology in the choice of words, you can also call them parent and children. The value of a parameter that is enslaved to another will change with its master’s value, based on a ratio, or an offset value. 9 | The whole point of this object was primarily to make it easier to have dynamically linked values in a basic UI, but it can be used without any UI. 10 | 11 | At the least, a parameter object requires a name and a default value. 12 | 13 | ```python 14 | p = SingleValueParameter('myParameter', 40) 15 | ``` 16 | 17 | and here’s the whole object: 18 | ```python 19 | SingleValueParameter(name, defaultValue, limits=None, numType='float', master=None, mode=None) 20 | ``` 21 | 22 | + *limits* should be a tuple in the form (minValue, maxValue) 23 | + *numType* can be either ‘int’ or ‘float’ (used to format the output) 24 | + *master* would be another parameter object 25 | + *mode* the type of relationship to the master parameter, ‘ratio’ or ‘offset’ 26 | 27 | Defining a parameter’s value goes trough the **set()** method: 28 | ```python 29 | p.set(40) 30 | ``` 31 | 32 | If the parameter happens to be the master of other parameters, all the slave parameters will be modified as well, based on their ratio/offset. A parameter given a master but no mode will fail. 33 | 34 | The relationship can be changed at any time **setMode()**, and a slave parameter can be freed at any time as well with **setMaster(None)**. 35 | 36 | Independently from the chosen mode, 'ratio' or 'offset', the ratio and offset values can be retrieved with **getRatio()** and **getOffset**. Inversely, and still independent of the mode, ratio and offset can be set, **setRatio()**, **setOffset()**. 37 | 38 | Similarly, values of a parameter can be set relatively through the **set()** method: adding ('++20') or substracting ('--20'). Note that these inputs have to be strings for the ++ and -- operators to be considered. 39 | 40 | ## VanillaSingleValueParameter 41 | *(vanillaParameterObjects.py)* 42 | 43 | This is the UI linked implementation of the SingleValueParameter object. Specifically, it is made to function with ![vanilla](https://github.com/typesupply/vanilla) based UI elements for use inside of Robofont or DrawBot (or any application using ![vanilla](https://github.com/typesupply/vanilla), I guess). 44 | 45 | ![alt tag](slider-parameters.png) 46 | 47 | ## ParameterSliderTextInput 48 | *(vanillaParameterObjects.py)* 49 | 50 | And here’s a bunch of ![vanilla](https://github.com/typesupply/vanilla) object grouped together (a slider, text input and checkbox), linking the slider and text input values through the ways of a parameter object. 51 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/objects/errorGlyph.py: -------------------------------------------------------------------------------- 1 | #coding=utf8 2 | from __future__ import division 3 | 4 | from math import pi, cos, sin, hypot 5 | 6 | from fontParts.fontshell import RGlyph 7 | 8 | _LETTERFORMS = { 9 | 'interpolation':[ 10 | (296, 322), (201, 322), 11 | (201, 352), (231, 352), 12 | (231, 397), (201, 397), 13 | (201, 427), (296, 427), 14 | (296, 397), (266, 397), 15 | (266, 352), (296, 352) 16 | ], 17 | 'none':[ 18 | (231, 322), (201, 322), 19 | (201, 427), (236, 427), 20 | (266, 374), (266, 427), 21 | (296, 427), (296, 322), 22 | (261, 322), (231, 375) 23 | ] 24 | } 25 | 26 | class ErrorGlyph(RGlyph): 27 | 28 | def __new__(cls, errorName=None, report=None, size=500, upm=1000): 29 | newGlyph = super(ErrorGlyph, cls).__new__(cls) 30 | newGlyph.__init__(errorName, report, size, upm) 31 | return newGlyph 32 | 33 | def __init__(self, errorName=None, report=None, size=500, upm=1000): 34 | super(ErrorGlyph, self).__init__() 35 | self.note = str(report) 36 | self.name = '_error_' 37 | self.upm = upm 38 | self.pen = self.getPen() 39 | size = 300 40 | self._setSize(size) 41 | self.width = 500 42 | self._drawError(errorName) 43 | scale = upm / 1000 44 | self.scaleBy((scale, scale)) 45 | 46 | def _setSize(self, size): 47 | self.si = size 48 | self.st = ( 49 | 250 - (size / 4), 50 | (750 / 2) - (size / 2) 51 | ) 52 | self.le = hypot(size, size) / 4 53 | 54 | def _drawError(self, errorName): 55 | errorSign = self._getErrorSign() 56 | self._drawPoints(errorSign) 57 | if errorName is not None: 58 | points = self._getLetter(errorName) 59 | self._drawPoints(points) 60 | 61 | def _drawPoints(self, points): 62 | pen = self.pen 63 | for i, point in enumerate(points): 64 | if i == 0: 65 | pen.moveTo(point) 66 | else: 67 | pen.lineTo(point) 68 | pen.closePath() 69 | 70 | def _getErrorSign(self): 71 | points = [] 72 | a = pi/4 73 | size = self.le 74 | start = self.st 75 | px, py = start 76 | for i in range(12): 77 | x = px + (size * cos(a)) 78 | y = py + (size * sin(a)) 79 | points.append((x, y)) 80 | px = x 81 | py = y 82 | if i%3 == 0: 83 | a -= pi/2 84 | elif i%3 != 0: 85 | a += pi/2 86 | return points 87 | 88 | def _getLetter(self, errorName): 89 | errorName = errorName.lower() 90 | if errorName in _LETTERFORMS: 91 | return _LETTERFORMS[errorName] 92 | 93 | if __name__ == '__main__': 94 | 95 | import unittest 96 | 97 | class ErrorGlyphTests(unittest.TestCase): 98 | 99 | def test_building_errorGlyph_with_note(self): 100 | for letter in _LETTERFORMS: 101 | e = ErrorGlyph(letter, report='No idea what happened.') 102 | 103 | def test_building_errorGlyphs(self): 104 | for letter in _LETTERFORMS: 105 | e = ErrorGlyph(letter) 106 | 107 | unittest.main() 108 | -------------------------------------------------------------------------------- /source/lib/dynamicParameters/lib/dynamicParameters/vanillaParameterObjects.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # Loïc Sander — 2014 3 | from .baseParameter import SingleValueParameter 4 | from vanilla import Group, Slider, TextBox, CheckBox 5 | from mojo.UI import NumberEditText 6 | 7 | class BaseParameterVanillaInput: 8 | 9 | vanillaInputs = [] 10 | 11 | def __init__(self, parameter, posSize, callback=None): 12 | self.parameter = parameter 13 | self.callback = callback 14 | 15 | def get(self): 16 | return self.parameter.get() 17 | 18 | def enable(self, value): 19 | for item in self.vanillaInputs: 20 | item.enable(value) 21 | 22 | def valueInput(self, sender): 23 | value = sender.get() 24 | parameter = self.parameter 25 | if value == 'R': 26 | parameter.reset() 27 | parameter.update() 28 | if self.callback is not None: 29 | self.callback(self) 30 | return 31 | elif value != '*': 32 | parameter.setInput(value, sender=sender) 33 | parameter.update() 34 | if self.callback is not None: 35 | self.callback(self) 36 | 37 | def setFree(self, sender): 38 | value = bool(sender.get()) 39 | self.parameter.setFree(value) 40 | 41 | class ParameterTextInput(Group): 42 | 43 | def __init__(self, parameter, posSize, text='', callback=None, continuous=False, showRelativeValue=False): 44 | super(ParameterTextInput, self).__init__(posSize) 45 | self.parameter = parameter 46 | rel = self._relValue() 47 | self.callback = callback 48 | self.textInput = NumberEditText((0, 0, -40, -0), text=parameter.value, callback=self._valueInput, allowEmpty=False, continuous=continuous, decimals=1) 49 | self.relInfo = TextBox((-35, 5, -0, -0), rel, alignment='left', sizeStyle='small') 50 | self.showRelativeValue(showRelativeValue) 51 | self.vanillaInputs = [self.textInput] 52 | self.parameter.bind(self) 53 | 54 | def set(self, value): 55 | self.parameter.set(value) 56 | self.update(None) 57 | 58 | def get(self): 59 | return self.parameter.get() 60 | 61 | def enable(self, value): 62 | for item in self.vanillaInputs: 63 | item.enable(value) 64 | 65 | def _valueInput(self, sender): 66 | value = sender.get() 67 | parameter = self.parameter 68 | if value == 'R' and parameter.hasMaster: 69 | parameter.reset() 70 | parameter.update() 71 | if self.callback is not None: 72 | self.callback(self) 73 | return 74 | elif value != '*': 75 | if value == int(value): value = int(value) 76 | parameter.setInput(value, sender=sender) 77 | parameter.update() 78 | if self.callback is not None: 79 | self.callback(self) 80 | rel = self._relValue() 81 | self.relInfo.set(rel) 82 | 83 | def showRelativeValue(self, b): 84 | self.relInfo.show(b) 85 | 86 | def setFree(self, sender): 87 | value = bool(sender.get()) 88 | self.parameter.setFree(value) 89 | 90 | def update(self, sender): 91 | value = self.parameter.get() 92 | self.textInput.set(value) 93 | self._updateRelValue() 94 | 95 | def _updateRelValue(self): 96 | rel = self._relValue() 97 | self.relInfo.set(rel) 98 | 99 | def _relValue(self): 100 | parameter = self.parameter 101 | rel = '-' 102 | if parameter.hasMaster: 103 | if parameter.mode == 'ratio': 104 | rel = '%s' % (parameter.getRatio()) 105 | elif parameter.mode == 'offset': 106 | offsetValue = round(parameter.getOffset(), 1) 107 | sign = '+' if offsetValue >= 0 else '' 108 | rel = '%s%s' % (sign, offsetValue) 109 | return rel 110 | 111 | class ParameterSliderTextInput(Group): 112 | 113 | ''' 114 | Custom Vanilla object consisting mainly of a Slider & and text input linked together (through a parameter object) 115 | ''' 116 | 117 | def __init__(self, parameter, posSize, title=None, callback=None): 118 | super(ParameterSliderTextInput, self).__init__(posSize) 119 | self.parameter = parameter 120 | self.callback = callback 121 | editTextPosSize = (-65, 0, 40, 22) 122 | if title is None: 123 | sliderPosSize = (5, 3, -80, 15) 124 | elif title is not None: 125 | title = title.capitalize() 126 | sliderPosSize = (70, 3, -80, 15) 127 | self.title = TextBox((0, 3, 65, 30), title, sizeStyle='small') 128 | if parameter.dissociable: 129 | editTextPosSize = (-65, 0, 40, 22) 130 | self.checkBox = CheckBox((-22, 0, 22, 22), u'∞', callback=self.setFree, value=True, sizeStyle='mini') 131 | self.slider = Slider(sliderPosSize, minValue=parameter.limits[0], maxValue=parameter.limits[1], value=parameter.value, callback=self.valueInput, sizeStyle='small') 132 | self.textInput = NumberEditText(editTextPosSize, text=parameter.value, callback=self.valueInput, allowEmpty=False, continuous=False, sizeStyle='small') 133 | self.parameter.bind(self) 134 | 135 | def get(self): 136 | return self.parameter.get() 137 | 138 | def enable(self, b): 139 | self.slider.enable(b) 140 | self.textInput.enable(b) 141 | if hasattr(self, checkBox): 142 | self.checkBox.enable(b) 143 | 144 | def valueInput(self, sender): 145 | value = sender.get() 146 | parameter = self.parameter 147 | if value == 'R': 148 | parameter.reset() 149 | parameter.update() 150 | if self.callback is not None: 151 | self.callback(self) 152 | return 153 | elif value != '*': 154 | parameter.setInput(value, sender=sender) 155 | parameter.update() 156 | if self.callback is not None: 157 | self.callback(self) 158 | 159 | def update(self, sender): 160 | value = self.parameter.get() 161 | self.textInput.set(value) 162 | if (value != '*'): 163 | self.slider.set(value) 164 | if hasattr(self, 'checkBox'): 165 | free = self.parameter.hasMaster 166 | self.checkBox.set(free) 167 | 168 | def setFree(self, sender): 169 | value = not bool(sender.get()) 170 | self.parameter.setFree(value) 171 | 172 | class VanillaParameterWrap(object): 173 | 174 | ''' 175 | Base class, to be subclassed, 176 | making it easy to link a Parameter object 177 | with Vanilla UI input objects (Slider, EditText, CheckBox) 178 | ''' 179 | 180 | def __init__(self): 181 | self.controls = [] 182 | self.sender = None 183 | self.master = None 184 | 185 | def bind(self, vanillaObject): 186 | self.controls.append(vanillaObject) 187 | 188 | def unbind(self, vanillaObject): 189 | if vanillaObject in self.controls: 190 | self.controls.remove(vanillaObject) 191 | 192 | def updateControls(self): 193 | for vanillaObject in self.controls: 194 | vanillaObject.update(self.sender) 195 | 196 | class VanillaSingleValueParameter(SingleValueParameter, VanillaParameterWrap): 197 | 198 | ''' 199 | Subclass implementing a link between a vanilla UI and parameter object 200 | ''' 201 | 202 | def __init__(self, name, defaultValue=None, limits=None, numType='float', master=None, mode=None, enable=True, dissociable=False): 203 | VanillaParameterWrap.__init__(self) 204 | SingleValueParameter.__init__(self, name, defaultValue=defaultValue, limits=limits, numType=numType, master=master, mode=mode) 205 | self.enable = enable 206 | self.dissociable = dissociable 207 | self.formerMaster = None 208 | 209 | def setInput(self, value, sender): 210 | self.sender = sender 211 | self.set(value) 212 | 213 | def setFree(self, b): 214 | if b: 215 | self.formerMaster = self.master 216 | if self.master is not None: 217 | self.master.affranchise(self) 218 | self.master = None 219 | elif not b: 220 | if self.formerMaster is not None: 221 | self.master = self.formerMaster 222 | self.master.enslave(self) 223 | 224 | def update(self): 225 | self.relationValue = self._getRelationValue() 226 | self.propagate() 227 | self.updateControls() 228 | 229 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/Readme.md: -------------------------------------------------------------------------------- 1 | # MutatorScale 2 | 3 | Here’s an introduction to MutatorScale, a tool for interpolated glyph scaling, based on [FontParts](https://github.com/roboTools/fontParts), [FontTools](https://github.com/fontTools/fontTools), [MutatorMath](https://github.com/LettError/MutatorMath), [FontMath](https://github.com/typesupply/fontMath) & [BooleanOperations](https://github.com/typemytype/booleanOperations). 4 | 5 | It consists of a little set of objects — I wouldn’t go as far as to call it a library —, the most important and central one being what I call a *MutatorScaleEngine*. 6 | 7 | Its function is to build an interpolation design space, based on MutatorMath, with which it is rendered easier to scale glyphs while compensating for the loss of weight and/or contrast by interpolating. Such operations imply that you have at least two interpolatable fonts to begin with. 8 | 9 | Note: MutatorScale is used by the [ScaleFast](https://github.com/roboDocs/ScaleFast) extension. 10 | 11 | ![alt tag](images/mutatorScale-1.png) 12 | ![alt tag](images/mutatorScale-6.png) 13 | 14 | ## Overview 15 | 16 | Here’s how it goes. Providing you have a couple of interpolatable fonts, you can produce a wide range of derivative glyphs the design of which can be summed up as scaled down versions of others, the infamous example being small capitals. I’ll leave the ‘Small caps should be drawn’ purists to their romantic views and assume you’d love to hear more about generating small caps, among other things. 17 | 18 | You start by building a MutatorScaleEngine, feeding it fonts it can interpolate from: 19 | 20 | ```python 21 | scaler = MutatorScaleEngine(fonts) 22 | ``` 23 | 24 | Next, you provide information about the scaling you wish to perform. This can go two ways. The first and most direct one: 25 | 26 | ```python 27 | scaler.set({ 'scale': 0.8 }) 28 | ``` 29 | 30 | At all times, the .set() method of a MutatorScaleEngine is fed a dictionary containing scaling information. The alternate way to define your scaling goes like this: 31 | 32 | ```python 33 | scaler.set({ 34 | 'width': 1.03, 35 | 'referenceHeight': 'capHeight', 36 | 'targetHeight': 520 37 | }) 38 | ``` 39 | 40 | This way may seem less straightforward in terms of code but is closer to design. You provide the required meaningful proportions that allow the MutatorScaleEngine to compute scaling values. 41 | 42 | **width** corresponds to simple horizontal scaling and should be a float value akin to a percentage (100% == 1.0). 43 | 44 | **referenceHeight** can be either a string or a number (float or int), but if it is a string, it should be a height reference the master fonts will know about: vertical metrics. 45 | 46 | **targetHeight** is the height you wish to see your scaled glyphs have; should be a number (float or int). 47 | 48 | From these values, the MutatorScaleEngine computes proper scaling ratios. The interesting aspect in this approach is that the scaling ratios may vary among interpolation masters so that you can effectively interpolate glyphs from fonts with slightly different vertical metrics/proportions and still obtain scaled glyphs at the exact proportion you asked for — what it means concretely is that you could interpolate an ’H’ scaled down to 520 units in height from two master fonts with different capHeights. 49 | 50 | ***** 51 | 52 | Once scale and fonts are set, the MutatorScaleEngine is ready to produce scaled glyphs, on demand. 53 | 54 | Now if we ask: 55 | 56 | ```python 57 | scaledGlyph = scaler.getScaledGlyph('H', stems) 58 | ``` 59 | 60 | We get a new scaled letter H. 61 | 62 | With **glyphName** (‘H’, ‘a’, etc.), I’ve also provided a **stems** variable and it is a crucial part of the process, so I’ll elaborate on that. 63 | 64 | When a MutatorScaleEngine is given master fonts, it does a quick analysis to be able to place them in an interpolation space. It measures reference stems for each font so that you can later ask for scaled glyphs with a specific stem value. Working with stem values is arbitrary and you can actually override this if you’d rather work with some other values that are more meaningful to you, but I’ll get into that later on. 65 | 66 | Stems are measured on uppercase I and H, to get both a vertical and horizontal stem value of reference. 67 | 68 | As reference values are based on an H’s vertical and horizontal stems, you should use these as a reference when you scale glyphs and ask for specific stem values. 69 | 70 | In effect, if you ask: 71 | 72 | ```python 73 | scaler.getScaledGlyph('H', (100, 20)) 74 | ``` 75 | 76 | You’re asking for a scaled glyph ‘H’ that has 100 units for its vertical stems and 20 for its horizontal stems. If you ask for another glyph with these same values, you’re not asking to obtain that specific glyph with exactly these stem values but you’re asking for a scaled glyph, say ‘A’, with stems as they should consistently be next to an H with stem values of 100 and 20. 77 | 78 | ## Going Deeper 79 | 80 | Here I’ll focus on what’s happening inside a MutatorScaleEngine. As the name indicates, I got the idea from playing around with MutatorMath, and MutatorScale depends totally on MutatorMath’s mojo. 81 | 82 | To understand how glyphs are scaled down and corrected, you should first grasp how MutatorMath functions even if it’s just a general understanding. 83 | 84 | The whole point of MutatorMath is to define a design space for interpolation. The word *space* is meant quite literally here because one of the key objects of MutatorMath is a **Location**. 85 | With well defined key Locations (= masters), you obtain an axis on which you can move and retrieve interpolated data. 86 | 87 | Quite often with glyph interpolation, we use Location values that correspond to some weight pacing system (0 to 1000, 100 Thin, 300 Light, 400 Regular, etc.). But the numbers you use for locations can be anything. In MutatorScale I used stem values because that’s the thing I wanted to keep track of. If you build a mutator with stem values, you can effectively ask for an interpolated glyph with specific stem values. 88 | 89 | On top of MutatorMath, the only thing done by a MutatorScaleEngine is to use an interpolation space containing scaled glyphs, defining these as master Locations by their scaled stem values, and allowing you to retrieve instance glyphs with unscaled stem values. 90 | 91 | Let’s say I have two masters, a Regular and a Bold. In the regular weight, an H’s vertical stem is 100 units wide, and in the bold weight, 200 units. If I’d like to obtain a regular small capital H with vertical stems of 100 units, scaled down 85% in width and 80% in height, here’s what I have to do around MutatorMath: 92 | 93 | ![alt tag](images/mutatorScale-5.png) 94 | 95 | ```python 96 | # Scale down master glyphs to 0.85 width and 0.8 height 97 | regular_H.scale((0.85, 0.8)) 98 | bold_H.scale((0.85, 0.8)) 99 | 100 | # Calculate scaled down stem values 101 | scaled_regularStem = 100 * 0.85 # = 85 102 | scaled_boldStem = 200 * 0.85 # = 170 103 | 104 | # List masters with scaled glyph and scaled stem values 105 | masters = [ 106 | ( Location(stem=scaled_regularStem), regular_H ), 107 | ( Location(stem=scaled_boldStem), bold_H ) 108 | ] 109 | 110 | # Build a mutator of these scaled elements 111 | b, mutator = buildMutator(masters) 112 | 113 | # Ask for an instance of a scaled glyphs with an unscaled stem value, 100 for regular 114 | smallH = mutator.getInstance( Location(stem=100) ) 115 | ``` 116 | 117 | Now we retrieved a scaled down ‘H’ glyph with weight identical to a unscaled ‘H’, and that’s the basic operation happening inside of a MutatorScaleEngine. 118 | 119 | ## Types of interpolation 120 | 121 | A MutatorScaleEngine will switch from one interpolation type to another according to the fonts you provide and the stem values you’re asking for. 122 | 123 | The most basic mode is isotropic, it happens if you provide a single value for stems: 124 | 125 | ```python 126 | scaler.getScaledGlyph('H', 100) 127 | ``` 128 | 129 | Although it’s a start — and in occasional cases, a finish — it will often fall short of achieving the desired result. Mostly because serifs/thins will be too meagre. 130 | 131 | You can get better result if you work with anisotropic interpolation, providing two values: 132 | 133 | ```python 134 | scaler.getScaledGlyph('H', (100, 20)) 135 | ``` 136 | 137 | But you should be aware that this can lead to ugly deformations if pushed too far; it’s not an ideal solution. Still, used with reason, it can produce close to final results with some designs. 138 | 139 | *(When you go too far with anisotropic interpolation)* 140 | ![alt tag](images/mutatorScale-4.png) 141 | 142 | Last but not least, the scaling is best done with masters for both weight and contrast. This is the use case in which you will get results that require very little or no correction at all, most of the time. A MutatorScaleEngine determines by itself if conditions are met to interpolate on two axes rather than anisotropically. 143 | -------------------------------------------------------------------------------- /source/html/index.md: -------------------------------------------------------------------------------- 1 | ScaleFast 2 | ========= 3 | 4 | This extension’s mission is simple: keep stem widths consistent while you fiddle with proportions of a glyph. It manages that by trying to compensate for scale deformations through interpolation. To achieve this result, it requires at least two masters (a regular and a bold for instance). This way, you can easily produce scaled versions of existing glyph for any purpose you see fit, small capitals, superiors, extended or condensed styles, etc. 5 | Any transformation you input can be saved as a preset for a later use. Presets are stored inside the ufo file of the selected working font (among masters). 6 | 7 | *The tool’s flexibility comes a great deal from its relying on [MutatorMath](https://github.com/LettError/MutatorMath), written by Erik van Blokland.* 8 | 9 | ![alt tag](images/scalefast-1.png) 10 | ![alt tag](images/scalefast-2.png) 11 | ![alt tag](images/scalefast-3.png) 12 | ![alt tag](images/scalefast-4.png) 13 | 14 | ## Table of Contents 15 | 16 | - [How it works](#how-it-works) 17 | - [Scaling](#scaling) 18 | - [Stems](#stems) 19 | - [Modes](#modes) 20 | - [Presets](#presets) 21 | - [Guides](#guides) 22 | - [Transformations](#transformations) 23 | - [Offset](#offset) 24 | - [Sticky](#sticky) 25 | - [Tracking](#tracking) 26 | - [Generating](#generating) 27 | - [Current](#current) 28 | - [Batch](#batch) 29 | 30 | ## How it works 31 | 32 | To get the best possible results, here are a few explanations about how this extension works. 33 | 34 | The scaling is handled by a [scaling engine](https://github.com/loicsander/MutatorScale). When provided with fonts as masters, the scaling engine uses interpolation to scale glyphs according to settings defined by the user. In ScaleFast, adding or removing masters to the scaling engine is done by checking/unchecking the available fonts in the masters list. 35 | 36 | When you add masters (as many as you like), they are analyzed for vertical & horizontal stem width (based on capital I’s stem and the horizontal bar of H). These values are then used as reference points to build an interpolation space (with help of MutatorMath). If you don’t wish to work with stem values, you can replace them and work with units on any scale you like (0 to 1000 for instance). You should note however that this tool is built to work with stem widths, so if you work outside of this scheme, the script will work fine, but the experience won’t be as smooth. 37 | 38 | ## Scaling 39 | 40 | With ScaleFast, what you scale firstly are reference heights. This is why you’ll find a slider and text input requiring a value in units (per em) and a popup menu with predefined reference heights. What you’re asking for when you input [xHeight]>[300] is effectively that ScaleFast reduces glyphs with a ratio of 300/500, if the xHeight is 500 units high, for instance. The ratio part is taken care of, all you need to know is the change in dimensions you want. This specific input used as an example will result in lowercase letters having a 300 units high xHeight themselves. 41 | 42 | ### Stems 43 | 44 | As I mentioned earlier, the whole point of ScaleFast is allowing you to scale glyphs while defining the exact stem width (be it vertical or horizontal) you wish to obtain on the scaled glyphs. This being, be aware that scaled glyphs go through quite a lot of mathematical operations and rounding, so don’t be surprised if the results display some little inaccuracies (shouldn’t be beyond 2 or 3 units though). 45 | The way you define stem values depends on the mode you’re working with. 46 | 47 | ### Modes 48 | 49 | ScaleFast can work according to three modes, the default being isotropic. 50 | 51 | **Isotropic** 52 | 53 | This is the simplest interpolation, one that moves values linearly between two reference points, or masters. With this mode, the script will only be able to retain vertical stem width while you scale glyphs; which is not so bad to begin with. This means that serif thickness, for instance, will be smaller than the original size. With this mode, you can only define vertical stem values, which will define the interpolation factor between master stem values. If the masters stem values are accurate, the result will be as well. Only vertical stem width will be correct though. 54 | 55 | **Anisotropic** 56 | 57 | The anisotropic mode distinguishes interpolation on the X and Y axes. It provides the possibility of deformation along each of those two axes. Practically, it means that — to a certain extent — the script can compensate for reduction on the Y axis also and try to maintain horizontal stem width as well. Depending on the design, you might luckily not need to correct serif thickness or contrast. This mode requires two values for vertical and horizontal stems, with that and to the best of its capabilities, the tool will try to maintain these values for the stems of the scaled glyphs. Be aware that the result will strongly depend on your design, if you spot inconsistencies in size among the generated glyphs, please start by checking that these aren’t due to your masters’ stem widths. 58 | 59 | **Bi-dimensional** 60 | 61 | Being able to work in two-dimensional interpolation was the actual reason that pushed me to write this tool. Thanks to MutatorMath, handling interpolation along multiple axis has become incredibly easy, and it’s also incredibly powerful. The best use case (and the one I initially wrote this tool for) is the case of a contrasted type family with optical sizes. For type of which the weight evolves in the ‘usual’ way — that is to say relative contrast lessens while weight becomes heavier, effectively making horizontal stems thicker — working with isotropic or anisotropic interpolation will probably be sufficient to generate scaled glyphs that require little or no correction. 62 | 63 | But in the case of a family in which the thickness thin parts (serifs for instance) do not change with weight (random example: a Didot face), anisotropic interpolation can’t compensate anything because there’s no difference in contrast to work from. But if you have been working with optical sizes and your optical sizes are compatible for interpolation, then you do have a difference in contrast that can be put to good use. This situation allows you to work both with separate weight & contrast axes, and in that case you can use bi-dimensional interpolation to solve your scaling problems. To be honest, you could work out an an/isotropic interpolation scheme with your optical sizes, but that would be to the expense of much time spent generating intermediary masters. Not very practical. 64 | 65 | Now back to ScaleFast, if you provide at least three masters that allow the script to build a two axis interpolation scheme, then you can generate whatever scaled glyphs you need, and it’s actually the case in which the tool performs the best. 66 | 67 | To be more specific, this mode requires that at least two masters both share their horizontal stem values while having different vertical stem values, and that a a least one third master has an horizontal stem value different from the two others. 68 | But don’t bother keeping that in mind, ScaleFast figures out on its own if it has all that is required for bi-dimensional interpolation, it will switch automatically to this mode if it can. 69 | 70 | ### Presets 71 | 72 | Any settings you define can be store as a preset (through the right hand panel). Presets are stored in the selected working font, so they will stay in the UFO unless you remove them. 73 | 74 | ![alt tag](images/scalefast-5.png) 75 | ![alt tag](images/scalefast-6.png) 76 | ![alt tag](images/scalefast-7.png) 77 | 78 | ### Guides 79 | 80 | You can add custom guides that will be stored in the font and can be displayed to help with your scaling work. 81 | 82 | ## Transformations 83 | 84 | ### Offset 85 | 86 | On top of the scaling, you can defined X/Y offsets to be applied to all glyphs. 87 | 88 | ### Sticky 89 | 90 | In combination with manual offsetting, there’s a helper ‘sticky’ option that allows you to define alignments for scaled glyph. If you’re working on superiors for instance and you wish to see them aligned with the capHeight, you only need to specify [top][capHeight]. Note that the second Pop-up menu will recognize any custom guide as well as the base vertical metrics of a font. 91 | 92 | ### Tracking 93 | 94 | There are several things you can do about the spacing of the glyphs you scale. By default, the width of a scaled glyph is scaled as well. But if you’d rather avoid that, you can activate the ‘Keep inital sidebearings’ checkbox, the glyphs will be scaled but their sidebearings will remain those of the normally sized glyphs (using the source glyph of the selected master font as reference). 95 | On top of that — spacing being scaled or not — you can add tracking, either in percentage or units (per em). Note that if you apply tracking with percentages, you will probably get undesired results with components (because handling those is rather tricky); it will work great for glyphs containing only contours though. 96 | 97 | ## Generating 98 | 99 | You can generate any glyph set you want. The generated glyphs can then be directly reinserted into one of the existing masters, or another open font, or a new one created for the occasion. Additionally, you can suffix the generated glyphs. Note that if you reinsert generated glyphs in a existing font without suffixing glyph names, existing glyphs with the same name in the target font will be replaced. 100 | 101 | ### Current 102 | 103 | This generates glyphs with the current settings and provided glyphset + suffix. 104 | 105 | ### Batch 106 | 107 | You can also generate different glyphsets by using presets to define which settings should be applied to a specific series of glyphs. 108 | 109 | ![alt tag](images/scalefast-8.png) 110 | ![alt tag](images/scalefast-9.png) 111 | -------------------------------------------------------------------------------- /source/lib/dynamicParameters/lib/dynamicParameters/baseParameter.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | # Loïc Sander — 2014 3 | from __future__ import division 4 | import re 5 | 6 | class ParameterModeError(Exception): 7 | 8 | msg = "A slave parameter's mode cannot be" 9 | 10 | def __init__(self, mode): 11 | self.mode = mode 12 | 13 | def __str__(self): 14 | return '%s %s' % (self.msg, repr(self.mode)) 15 | 16 | class ParameterValueError(Exception): 17 | 18 | msg = "A parameter needs a default value or master." 19 | 20 | def __str__(self): 21 | return '%s' % (self.msg) 22 | 23 | def valueToRatio(referenceValue, value, rounding=8): 24 | if referenceValue: 25 | return round((value/referenceValue), rounding) 26 | return 1 27 | 28 | def ratioToValue(reference, ratio, rounding=8): 29 | return round(reference * ratio, rounding) 30 | 31 | class SingleValueParameter(object): 32 | 33 | ''' 34 | Base parameter object built to connect numerical values 35 | on a _ratio_ or _offset_ basis, dynamically. 36 | ''' 37 | 38 | def __init__(self, name, defaultValue=None, limits=None, numType='float', master=None, mode=None): 39 | self.name = name 40 | self.master = master 41 | if (master is None) and (defaultValue is None): 42 | raise ParameterValueError 43 | return 44 | if (master is None) and (defaultValue is not None): 45 | self.value = defaultValue 46 | elif (master is not None): 47 | self.value = master.get() 48 | self.mode = mode 49 | self.numType = numType 50 | self.validModes = ['ratio', 'offset'] 51 | self.limits = limits 52 | if master is not None: 53 | master.slaves.append(self) 54 | if mode not in self.validModes: 55 | raise ParameterModeError(mode) 56 | return 57 | self.limits = master.limits 58 | self.relationValue = self._getRelationValue() 59 | self.slaves = [] 60 | self.defaultValue = defaultValue 61 | 62 | def __repr__(self): 63 | if self.master is not None: master = self.master.name 64 | else: master = None 65 | return '' % (self.name, self.value, master, self.mode) 66 | 67 | def __add__(self, other): 68 | return self.mathOperate(other, 'add') 69 | 70 | __radd__ = __add__ 71 | 72 | def __sub__(self, other): 73 | return self.mathOperate(other, 'sub') 74 | 75 | __rsub__ = __sub__ 76 | 77 | def __mul__(self, other): 78 | return self.mathOperate(other, 'mul') 79 | 80 | __rmul__ = __mul__ 81 | 82 | def __div__(self, other): 83 | return self.mathOperate(other, 'div') 84 | 85 | __rdiv__ = __rtruediv__ = __truediv__ = __div__ 86 | 87 | def __eq__(self, other): 88 | if isinstance(other, self.__class__): 89 | return (self.name == other.name) and (self.mode == other.mode) and (self.master == other.master) and (self.limits == other.limits) and (self.numType == other.numType) 90 | return False 91 | 92 | def mathOperate(self, other, operation): 93 | firstValue = self.get() 94 | secondValue = None 95 | if self.__class__ == other.__class__: 96 | secondValue = other.get() 97 | elif isinstance(other, (float, int)): 98 | secondValue = other 99 | if secondValue is not None: 100 | p = self.clone() 101 | if operation == 'add': 102 | value = firstValue + secondValue 103 | elif operation == 'sub': 104 | value = firstValue - secondValue 105 | elif operation == 'mul': 106 | value = firstValue * secondValue 107 | elif operation == 'div': 108 | value = firstValue / secondValue 109 | p.set(value) 110 | return p 111 | else: 112 | raise TypeError 113 | 114 | def clone(self): 115 | return self.__class__(self.name, self.defaultValue, self.limits, self.numType, self.master, self.mode) 116 | 117 | def asDict(self): 118 | return dict( 119 | name = self.name, 120 | numType = self.numType, 121 | limits = self.limits, 122 | master = self.master, 123 | defaultValue = self.defaultValue, 124 | mode = self.mode, 125 | value = self.value 126 | ) 127 | 128 | def asShortDict(self): 129 | return dict(name = self.name, value = [self.value, self.master]) 130 | 131 | def digest(self): 132 | d = [] 133 | d.append('Parameter: %s'%(self.name)) 134 | d.append('Value: %s'%(self.get())) 135 | if (self.master is not None) and (self.mode is not None): 136 | d.append('mode: %s'%(self.mode)) 137 | d.append('ratio: %s'%(self.getRatio())) 138 | d.append('offset: %s'%(self.getOffset())) 139 | d.append('Master: %s [%s]'%(self.master.name, self.master.get())) 140 | d.append('\n') 141 | return '\n'.join(d) 142 | 143 | def set(self, value): 144 | self.value = self._checkValue(value) 145 | if self.master is not None: 146 | self.relationValue = self._getRelationValue() 147 | self.propagate() 148 | 149 | def setRatio(self, ratio): 150 | if self.master is not None: 151 | self.value = ratioToValue(self.master.get(), ratio) 152 | self.relationValue = self._getRelationValue() 153 | self.propagate() 154 | 155 | def setOffset(self, offset): 156 | if self.master is not None: 157 | self.value = self.master.get() + offset 158 | self.relationValue = self._getRelationValue() 159 | self.propagate() 160 | 161 | def setMode(self, mode): 162 | if mode in self.validModes: 163 | self.mode = mode 164 | self.update() 165 | 166 | def get(self): 167 | master = self.master 168 | mode = self.mode 169 | if (master is not None) and (mode is not None): 170 | relationValue = self.relationValue 171 | if mode == 'ratio': 172 | value = ratioToValue(master.get(), relationValue) 173 | elif mode == 'offset': 174 | value = master.get() + relationValue 175 | elif (master is None): 176 | value = self.value 177 | 178 | return self._constrainValue(value) 179 | 180 | def getRatio(self): 181 | if self.master is not None: 182 | masterValue = self.master.get() 183 | value = self.value 184 | return valueToRatio(masterValue, value) 185 | return 1 186 | 187 | def getOffset(self): 188 | if self.master is not None: 189 | masterValue = self.master.get() 190 | value = self.value 191 | return self._formatValue(value - masterValue) 192 | return 0 193 | 194 | def _getRelationValue(self): 195 | if self.mode == 'ratio': 196 | ratio = self.getRatio() 197 | return ratio 198 | elif self.mode == 'offset': 199 | offset = self.getOffset() 200 | return offset 201 | return 202 | 203 | def getInt(self): 204 | return int(round(self.get())) 205 | 206 | def update(self): 207 | self.relationValue = self._getRelationValue() 208 | self.propagate() 209 | 210 | def propagate(self): 211 | for slave in self.slaves: 212 | slave.value = slave.get() 213 | slave.update() 214 | 215 | def reset(self): 216 | master = self.master 217 | if master is None: 218 | self.value = self.defaultValue 219 | elif master is not None: 220 | self.value = master.get() 221 | self.relationValue = self._getRelationValue() 222 | 223 | def setDefault(self, value): 224 | value = self._checkValue(value) 225 | if value is not None: 226 | self.defaultValue = value 227 | 228 | def getDefault(self): 229 | if self.master is None: 230 | return self.defaultValue 231 | elif self.master is not None: 232 | return self.master.get() 233 | 234 | def enslave(self, parameter): 235 | if parameter not in self.slaves: 236 | if parameter.mode in ['ratio', 'offset']: 237 | self.slaves.append(parameter) 238 | parameter.master = self 239 | parameter.relationValue = parameter._getRelationValue() 240 | parameter.limits = self.limits 241 | parameter.value = parameter.get() 242 | parameter.update() 243 | else: 244 | raise ParameterModeError(mode) 245 | 246 | def affranchise(self, slave): 247 | if slave in self.slaves: 248 | self.slaves.remove(slave) 249 | 250 | def setMaster(self, master): 251 | # if this parameter already has a master 252 | # free it first 253 | if self.master is not None: 254 | self.master.affranchise(self) 255 | if master is not None: 256 | master.enslave(self) 257 | elif master is None: 258 | self.master = None 259 | 260 | @property 261 | def hasMaster(self): 262 | return self.master is not None 263 | 264 | def setLimits(self, minMaxValues): 265 | self.limits = minMaxValues # (minValue, maxValue) 266 | for slave in self.slaves: 267 | slave.limits = minMaxValues # (minValue, maxValue) 268 | slave.value = slave.get() 269 | slave.update() 270 | 271 | def _checkValue(self, value): 272 | if isinstance(value, str): 273 | s = re.search(r'(\+\+|--)(\d*\.?\d*)', value) 274 | if s is not None: 275 | offset = float(s.group(2)) 276 | if s.group(1) == '++': 277 | value = self.get() + offset 278 | elif s.group(1) == '--': 279 | value = self.get() - offset 280 | elif s is None: 281 | try: value = float(value) 282 | except: value = self.get() 283 | return self._constrainValue(value) 284 | elif isinstance(value, float) or isinstance(value, int): 285 | return self._constrainValue(value) 286 | return 287 | 288 | def _constrainValue(self, value): 289 | limits = self.limits 290 | if limits is not None: 291 | minValue, maxValue = limits 292 | if value < minValue: value = minValue 293 | elif value > maxValue: value = maxValue 294 | return self._formatValue(value) 295 | 296 | def _formatValue(self, value): 297 | if self.numType == 'int': 298 | value = int(round(value)) 299 | elif self.numType == 'float': 300 | if value == int(value): 301 | value = int(value) 302 | else: 303 | value = round(value, 2) 304 | return value 305 | 306 | # Testing stuff 307 | # fontWeight = SingleValueParameter('fontWeight', 80, (1,500), 'int') 308 | # capWeight = SingleValueParameter('capWeight', 100, (1,500), 'int', mode='ratio', master=fontWeight) 309 | # smallCapsWeight = SingleValueParameter('smallCapsWeight', 90, (1,500), 'int', mode='ratio', master=fontWeight) 310 | 311 | # fontWeight.set(100) 312 | 313 | # print fontWeight.digest() 314 | # print capWeight.digest() 315 | # print smallCapsWeight.digest() 316 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/objects/fonts.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from __future__ import division 3 | 4 | try: 5 | import mutatorScale 6 | except: 7 | import os 8 | import sys 9 | libFolder = os.path.dirname(os.path.dirname(os.getcwd())) 10 | if not libFolder in sys.path: 11 | sys.path.append(libFolder) 12 | 13 | from mutatorScale.objects.mathGlyph import MathGlyph 14 | from mutatorScale.utilities.fontUtils import makeListFontName, getRefStems, getSlantAngle 15 | 16 | from fontTools.pens.boundsPen import BoundsPen 17 | 18 | class ScaleFont(object): 19 | """ 20 | A ScaleFont takes a font object (FontParts or Defcon) and a scale setting, 21 | it is then ready to return any number of scaled glyphs. 22 | 23 | Usage: 24 | smallFont = ScaleFont(font, 0.5) 25 | small_Glyph_A = smallFont.getGlyph('A') 26 | Or: 27 | smallFont = ScaleFont(font) 28 | smallFont.setScale((1.05, 490, 'capHeight')) 29 | """ 30 | def __init__(self, font, scale=None): 31 | self.glyphSet = {glyph.name:glyph for glyph in font} 32 | self.scale = scale 33 | self.heights = { heightName:getattr(font.info, heightName) for heightName in ['capHeight','ascender','xHeight','descender'] } 34 | self.name = makeListFontName(font) 35 | self.italicAngle = -getSlantAngle(font, True) 36 | 37 | if scale is not None: 38 | self.setScale(scale) 39 | 40 | def __repr__(self): 41 | return '<{className} {fontName}>'.format(className = self.__class__.__name__, fontName = self.name) 42 | 43 | def __getitem__(self, key): 44 | return self.getGlyph(key) 45 | 46 | def __contains__(self, glyphName): 47 | return glyphName in self.glyphSet 48 | 49 | def keys(self): 50 | return self.glyphSet.keys() 51 | 52 | def getXScale(self): 53 | if self.scale is not None: 54 | return self.scale[0] 55 | return 56 | 57 | def getYScale(self): 58 | if self.scale is not None: 59 | return self.scale[1] 60 | return 61 | 62 | def getScale(self): 63 | return self.scale 64 | 65 | def setScale(self, scale): 66 | """ Setting scale for the font. 67 | 68 | – Either a simple (x, y) scale tuple; 69 | – or a tuple in the form (width, targetHeight, referenceHeight). 70 | – x, y, width should be floats; 71 | – targetHeight should be an int or float; 72 | – referenceHeight can be either a string or float/int. 73 | """ 74 | if len(scale) == 2: 75 | self.scale = scale 76 | 77 | elif len(scale) == 3: 78 | x, targetHeight, referenceHeight = scale 79 | 80 | try: 81 | xy = targetHeight / referenceHeight 82 | 83 | except: 84 | 85 | # try parsing referenceHeight to a numeric value 86 | if referenceHeight in self.heights: 87 | referenceHeightValue = self.heights[referenceHeight] 88 | elif referenceHeight in self.glyphSet: 89 | referenceHeightValue = self._getGlyphHeight(referenceHeight) 90 | if referenceHeightValue is None: 91 | referenceHeightValue = targetHeight 92 | else: 93 | referenceHeightValue = referenceHeight 94 | 95 | # try parsing targetHeight to a numeric value 96 | if targetHeight in self.heights: 97 | targetHeightValue = self.heights[targetHeight] 98 | elif targetHeight in self.glyphSet: 99 | targetHeightValue = self._getGlyphHeight(targetHeight) 100 | else: 101 | targetHeightValue = targetHeight 102 | 103 | try: 104 | xy = targetHeightValue / referenceHeightValue 105 | except: 106 | xy = 1 107 | 108 | finally: 109 | self.scale = (x * xy, xy) 110 | 111 | def _getGlyphHeight(self, glyphName): 112 | box = self._getGlyphBounds(glyphName) 113 | if box is not None: 114 | xMin, yMin, xMax, yMax = box 115 | return yMax - yMin 116 | return 117 | 118 | def _getGlyphBounds(self, glyphName): 119 | glyph = self.glyphSet[glyphName] 120 | pen = BoundsPen(self.glyphSet) 121 | glyph.draw(pen) 122 | return pen.bounds 123 | 124 | def getGlyph(self, glyphName): 125 | """Return a scaled glyph as a MathGlyph instance.""" 126 | if glyphName in self.glyphSet: 127 | glyph = self.glyphSet[glyphName] 128 | scale = self.scale 129 | scaledGlyph = self._scaleGlyph(glyph, scale) 130 | return scaledGlyph 131 | else: 132 | return KeyError 133 | 134 | def extractGlyph(self, glyphName, glyph): 135 | scaledGlyph = self.getGlyph(glyphName) 136 | for attribute in ['name','unicodes','width']: 137 | setattr(glyph, attribute, getattr(scaledGlyph, attribute)) 138 | pen = glyph.getPen() 139 | scaledGlyph.draw(pen) 140 | 141 | def _scaleGlyph(self, glyph, scale): 142 | """ 143 | Return a glyph scaled according to the font’s scale settings, 144 | if glyph has components, reset scaling on each component but keep scaled offset coordinates. 145 | """ 146 | glyph = MathGlyph(glyph) 147 | italicAngle = self.italicAngle 148 | # Skew to an upright position to prevent the slant angle from changing because of scaling 149 | if italicAngle: 150 | glyph.skewX(italicAngle) 151 | 152 | # Do the scaling 153 | glyph *= scale 154 | # Cancel scaling effect on components 155 | for i, component in enumerate(glyph.components): 156 | baseGlyph, matrix = component 157 | xx, yx, xy, yy, x, y = matrix 158 | xx, yx, xy, yy = 1, 0, 0, 1 159 | glyph.components[i] = (baseGlyph, (xx, yx, xy, yy, x, y)) 160 | # Reverting to initial slant angle 161 | if italicAngle: 162 | glyph.skewX(-italicAngle) 163 | 164 | return glyph 165 | 166 | class MutatorScaleFont(ScaleFont): 167 | """ Subclass extending a ScaleFont and adding reference stem values to be used inside a MutatorScaleEngine.""" 168 | 169 | def __init__(self, font, scale=(1, 1), vstem=None, hstem=None, stemsWithSlantedSection=False): 170 | super(MutatorScaleFont, self).__init__(font, scale) 171 | self._refVstem, self._refHstem = None, None 172 | self.stemsWithSlantedSection = stemsWithSlantedSection 173 | self.processDimensions(font, vstem, hstem) 174 | 175 | def __repr__(self): 176 | return '<{className} {fontName} v:{vstem} h:{hstem}>'.format(className=self.__class__.__name__, fontName=self.name, vstem=self._refVstem, hstem=self._refHstem) 177 | 178 | def processDimensions(self, font, vstem, hstem): 179 | if vstem is None and hstem is None: 180 | refVstem, refHstem = getRefStems(font, self.stemsWithSlantedSection) 181 | self._refVstem, self._refHstem = refVstem, refHstem 182 | elif hstem is None: 183 | self._refVstem = vstem 184 | self._refHstem = vstem 185 | else: 186 | self._refVstem = vstem 187 | self._refHstem = hstem 188 | 189 | 190 | def getStems(self): 191 | return self.vstem, self.hstem 192 | 193 | def setStems(self, stems): 194 | vstem, hstem = stems 195 | self.vstem = vstem 196 | self.hstem = hstem 197 | 198 | @property 199 | def vstem(self): 200 | return self._refVstem 201 | @vstem.setter 202 | def vstem(self, stem): 203 | self._refVstem = stem 204 | 205 | @property 206 | def hstem(self): 207 | return self._refHstem 208 | @hstem.setter 209 | def hstem(self, stem): 210 | self._refHstem = stem 211 | 212 | if __name__ == '__main__': 213 | 214 | import unittest 215 | import os 216 | from time import time 217 | from defcon import Font 218 | 219 | class ScaleFontsTest(unittest.TestCase): 220 | 221 | def setUp(self): 222 | self.glyphNames = ['H', 'Aacute', 'A', 'O', 'B'] 223 | libFolder = os.path.dirname(os.path.dirname((os.path.dirname(os.path.abspath(__file__))))) 224 | singleFontPath = u'testFonts/two-axes/regular-low-contrast.ufo' 225 | fontPath = os.path.join(libFolder, singleFontPath) 226 | font = Font(fontPath) 227 | self.smallFont = ScaleFont(font, (0.5, 0.4)) 228 | self.stemedSmallFont = MutatorScaleFont(font, (0.5, 0.4)) 229 | self.stemedSmallFont = MutatorScaleFont(font, (0.5, 0.4), stemsWithSlantedSection=True) 230 | self.stemedSmallFont = MutatorScaleFont(font, (0.5, 0.4), vstem=100, stemsWithSlantedSection=True) 231 | self.stemedSmallFont = MutatorScaleFont(font, (0.5, 0.4), vstem=120, hstem=140, stemsWithSlantedSection=True) 232 | 233 | def test_setScale_with_values(self): 234 | """Test changing scale with x, y values.""" 235 | for testFont in [self.smallFont, self.stemedSmallFont]: 236 | testFont.setScale((0.85, 0.79)) 237 | 238 | def test_setScale_with_references(self): 239 | """Test changing scale with width, targetHeight, referenceHeight arguments.""" 240 | for testFont in [self.smallFont, self.stemedSmallFont]: 241 | testFont.setScale((1.02, 450, 'capHeight')) 242 | testFont.setScale((0.65, 350, 250)) 243 | testFont.setScale((1, 400, 'A')) 244 | 245 | def test_get_scaled_glyph_as_MathGlyph(self): 246 | """Test scaled glyph retrieval.""" 247 | for testFont in [self.smallFont, self.stemedSmallFont]: 248 | for glyphName in self.glyphNames: 249 | scaledGlyph = testFont.getGlyph(glyphName) 250 | self.assertIsInstance(scaledGlyph, MathGlyph) 251 | scaledGlyph = testFont[glyphName] 252 | self.assertIsInstance(scaledGlyph, MathGlyph) 253 | 254 | def test_extract_scaled_glyph_as_Defcon_Glyph(self): 255 | """Test scaled glyph retrieval as a Defcon glyph.""" 256 | from defcon import Glyph 257 | for testFont in [self.smallFont, self.stemedSmallFont]: 258 | scaledGlyph = Glyph() 259 | for glyphName in self.glyphNames: 260 | testFont.extractGlyph(glyphName, scaledGlyph) 261 | self.assertIsInstance(scaledGlyph, Glyph) 262 | self.assertEqual(scaledGlyph.name, glyphName) 263 | 264 | def test_extract_scaled_glyph_as_FontParts_Glyph(self): 265 | """Test scaled glyph retrieval as a FontParts Glyph.""" 266 | from fontParts.fontshell import RGlyph 267 | for testFont in [self.smallFont, self.stemedSmallFont]: 268 | scaledGlyph = RGlyph() 269 | for glyphName in self.glyphNames: 270 | testFont.extractGlyph(glyphName, scaledGlyph) 271 | self.assertIsInstance(scaledGlyph, RGlyph) 272 | 273 | def test_set_stems(self): 274 | """Test setting stems on a MutatorScaleFont.""" 275 | self.stemedSmallFont.setStems((100, 40)) 276 | 277 | def test_set_stems_separately(self): 278 | """Test setting stems separately on a MutatorScaleFont.""" 279 | self.stemedSmallFont.vstem = 120 280 | self.stemedSmallFont.hstem = 50 281 | 282 | unittest.main() -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/mutatorScale/utilities/fontUtils.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | from __future__ import division 3 | from math import atan2, tan, hypot, cos, degrees, radians 4 | 5 | from fontParts.fontshell import RGlyph 6 | 7 | import fontTools 8 | import fontTools.misc.bezierTools as bezierTools 9 | import fontTools.misc.arrayTools as arrayTools 10 | import fontTools.misc.transform as transform 11 | from fontTools.pens.boundsPen import BoundsPen 12 | 13 | try: 14 | import mutatorScale 15 | except: 16 | import os 17 | import sys 18 | libFolder = os.path.dirname(os.path.dirname(os.getcwd())) 19 | if not libFolder in sys.path: 20 | sys.path.append(libFolder) 21 | 22 | from mutatorScale.pens.utilityPens import CollectSegmentsPen 23 | 24 | def makeListFontName(font): 25 | """ 26 | Return a font name in the form: 'Family name — style name'. 27 | The separator allows to easily split this full name later on with name.split(' — '). 28 | """ 29 | familyName = font.info.familyName 30 | styleName = font.info.styleName 31 | if familyName is None: 32 | familyName = font.info.familyName = 'Unnamed' 33 | if styleName is None: 34 | styleName = font.info.styleName = 'Unnamed' 35 | return joinFontName(familyName, styleName) 36 | 37 | 38 | def joinFontName(familyName, styleName): 39 | separator = '-' 40 | return '{familyName} {separator} {styleName}'.format(familyName=familyName, separator=separator, styleName=styleName) 41 | 42 | 43 | def getRefStems(font, slantedSection=False): 44 | """ 45 | Looks for stem values to serve as reference for a font in an interpolation scheme, 46 | only one typical value is returned for both horizontal and vertical stems. 47 | The method intersets the thick stem of a capital I and thin stem of a capital H. 48 | """ 49 | stems = [] 50 | angle = getSlantAngle(font, True) 51 | 52 | for i, glyphName in enumerate(['I','H']): 53 | 54 | if glyphName in font: 55 | 56 | baseGlyph = font[glyphName] 57 | 58 | # removing overlap 59 | glyph = freezeGlyph(baseGlyph) 60 | width = glyph.width 61 | 62 | glyph.skewBy((-angle, 0)) 63 | 64 | xMin, yMin, xMax, yMax = getGlyphBox(glyph) 65 | xCenter = width / 2 66 | yCenter = (yMax - yMin) / 2 67 | 68 | # glyph I, cut thick stem 69 | if i == 0: 70 | intersections = intersect(glyph, yCenter, True) 71 | 72 | # glyph H, cut thin stem 73 | elif i == 1: 74 | intersections = intersect(glyph, xCenter, False) 75 | 76 | if len(intersections) > 1: 77 | (x1,y1), (x2,y2) = (intersections[0], intersections[-1]) 78 | 79 | stemWidth = hypot(x2-x1, y2-y1) 80 | stems.append(round(stemWidth)) 81 | else: 82 | stems.append(None) 83 | 84 | elif glyphName not in font: 85 | stems.append(None) 86 | 87 | if slantedSection == True and stems[0] is not None: 88 | stems[0] *= cos(radians(angle)) 89 | 90 | return stems 91 | 92 | 93 | def getSlantAngle(font, returnDegrees=False): 94 | """Returns the probable slant/italic angle of a font measuring the slant of a capital I.""" 95 | 96 | if 'I' in font: 97 | testGlyph = font['I'] 98 | xMin, yMin, xMax, yMax = getGlyphBox(testGlyph) 99 | hCenter = (yMax - yMin) / 2 100 | delta = 10 101 | intersections = [] 102 | glyph = freezeGlyph(testGlyph) 103 | 104 | for i in range(2): 105 | horizontal = hCenter + (i * delta) 106 | intersections.append(intersect(glyph, horizontal, True)) 107 | 108 | if len(intersections) > 1: 109 | if len(intersections[0]) > 1 and len(intersections[1]) > 1: 110 | (x1,y1), (x2,y2) = (intersections[0][0], intersections[1][0]) 111 | angle = atan2(x2-x1, y2-y1) 112 | if returnDegrees == False: 113 | return angle 114 | elif returnDegrees == True: 115 | return round(degrees(angle), 2) 116 | return 0 117 | 118 | 119 | def freezeGlyph(glyph): 120 | """Return a copy of a glyph, with components decomposed and all overlap removed.""" 121 | 122 | toRFGlyph = RGlyph() 123 | toRFpen = toRFGlyph.getPen() 124 | # draw only the contours, decomposed components will be added later on 125 | for contour in glyph: 126 | contour.draw(toRFpen) 127 | 128 | if len(glyph.components): 129 | decomposedComponents = extractComposites(glyph) 130 | decomposedComponents.draw(toRFpen) 131 | 132 | singleContourGlyph = RGlyph() 133 | singleContourGlyph.width = glyph.width 134 | singleContourGlyph.name = glyph.name 135 | pointPen = singleContourGlyph.getPointPen() 136 | 137 | if len(toRFGlyph.contours) > 1: 138 | 139 | try: 140 | booleanGlyphs = [] 141 | 142 | for c in toRFGlyph.contours: 143 | if len(c) > 1: 144 | b = BooleanGlyph() 145 | pen = b.getPen() 146 | c.draw(pen) 147 | booleanGlyphs.append(b) 148 | 149 | finalBooleanGlyph = reduce(lambda g1, g2: g1 | g2, booleanGlyphs) 150 | finalBooleanGlyph.drawPoints(pointPen) 151 | 152 | except: 153 | toRFGlyph.drawPoints(pointPen) 154 | else: 155 | toRFGlyph.drawPoints(pointPen) 156 | 157 | return singleContourGlyph 158 | 159 | 160 | def extractComposites(glyph): 161 | """Return a new glyph with outline copies of each composite from the source glyph.""" 162 | 163 | decomposedComposites = RGlyph() 164 | 165 | if len(glyph.components): 166 | font = glyph.layer 167 | 168 | for comp in reversed(glyph.components): 169 | 170 | # obtain source data 171 | baseGlyphName = comp.baseGlyph 172 | baseGlyph = font[baseGlyphName] 173 | t = transform.Transform(*comp.transformation) 174 | 175 | # create a temporary glyph on which to draw the decomposed composite 176 | single_decomposedComposite = RGlyph() 177 | decompPen = single_decomposedComposite.getPen() 178 | baseGlyph.draw(decompPen) 179 | single_decomposedComposite.transformBy(tuple(t)) 180 | 181 | # add single composite to the returned glyph 182 | decomposedComposites.appendGlyph(single_decomposedComposite) 183 | 184 | return decomposedComposites 185 | 186 | 187 | def intersect(glyph, where, isHorizontal): 188 | """ 189 | Intersect a glyph with a horizontal or vertical line. 190 | Intersect each segment of a glyph using fontTools bezierTools.splitCubic and splitLine methods. 191 | """ 192 | pen = CollectSegmentsPen(glyph.layer) 193 | glyph.draw(pen) 194 | nakedGlyph = pen.getSegments() 195 | glyphIntersections = [] 196 | 197 | for i, contour in enumerate(nakedGlyph): 198 | 199 | for segment in contour: 200 | 201 | length = len(segment) 202 | 203 | if length == 2: 204 | pt1, pt2 = segment 205 | returnedSegments = splitLine(pt1, pt2, where, int(isHorizontal)) 206 | elif length == 4: 207 | pt1, pt2, pt3, pt4 = segment 208 | returnedSegments = bezierTools.splitCubic(pt1, pt2, pt3, pt4, where, int(isHorizontal)) 209 | 210 | if len(returnedSegments) > 1: 211 | intersectionPoints = findDuplicatePoints(returnedSegments) 212 | if len(intersectionPoints): 213 | box = calcBounds(segment) 214 | intersectionPoints = [point for point in intersectionPoints if arrayTools.pointInRect(point, box)] 215 | glyphIntersections.extend(intersectionPoints) 216 | 217 | return glyphIntersections 218 | 219 | 220 | def calcBounds(points): 221 | """ 222 | Return rectangular bounds of a list of points. 223 | Similar to fontTools’ calcBounds only with rounding added, 224 | rounding is required for the test in intersect() to work. 225 | """ 226 | xMin, xMax, yMin, yMax = None, None, None, None 227 | for (x, y) in points: 228 | for xRef in [xMin, xMax]: 229 | if xRef is None: xMin, xMax = x, x 230 | for yRef in [yMin, yMax]: 231 | if yRef is None: yMin, yMax = y, y 232 | if x > xMax: xMax = x 233 | if x < xMin: xMin = x 234 | if y > yMax: yMax = y 235 | if y < yMin: yMin = y 236 | box = [round(value, 4) for value in [xMin, yMin, xMax, yMax]] 237 | return tuple(box) 238 | 239 | 240 | def findDuplicatePoints(segments): 241 | counter = {} 242 | for seg in segments: 243 | for (x, y) in seg: 244 | p = round(x, 4), round(y, 4) 245 | if p in counter: 246 | counter[p] += 1 247 | elif not p in counter: 248 | counter[p] = 1 249 | return [key for key in counter if counter[key] > 1] 250 | 251 | 252 | def getGlyphBox(glyph): 253 | pen = BoundsPen(glyph.layer) 254 | glyph.draw(pen) 255 | return pen.bounds 256 | 257 | 258 | # had to fetch that splitLine method from Robofont’s version of fontTools 259 | # fontTools 2.4’s version was buggy. 260 | 261 | def splitLine(pt1, pt2, where, isHorizontal): 262 | """Split the line between pt1 and pt2 at position 'where', which 263 | is an x coordinate if isHorizontal is False, a y coordinate if 264 | isHorizontal is True. Return a list of two line segments if the 265 | line was successfully split, or a list containing the original 266 | line. 267 | 268 | >>> printSegments(splitLine((0, 0), (100, 100), 50, True)) 269 | ((0, 0), (50.0, 50.0)) 270 | ((50.0, 50.0), (100, 100)) 271 | >>> printSegments(splitLine((0, 0), (100, 100), 100, True)) 272 | ((0, 0), (100, 100)) 273 | >>> printSegments(splitLine((0, 0), (100, 100), 0, True)) 274 | ((0, 0), (0.0, 0.0)) 275 | ((0.0, 0.0), (100, 100)) 276 | >>> printSegments(splitLine((0, 0), (100, 100), 0, False)) 277 | ((0, 0), (0.0, 0.0)) 278 | ((0.0, 0.0), (100, 100)) 279 | """ 280 | pt1x, pt1y = pt1 281 | pt2x, pt2y = pt2 282 | 283 | ax = (pt2x - pt1x) 284 | ay = (pt2y - pt1y) 285 | 286 | bx = pt1x 287 | by = pt1y 288 | 289 | a = (ax, ay)[isHorizontal] 290 | 291 | if a == 0: 292 | return [(pt1, pt2)] 293 | 294 | t = float(where - (bx, by)[isHorizontal]) / a 295 | if 0 <= t < 1: 296 | midPt = ax * t + bx, ay * t + by 297 | return [(pt1, midPt), (midPt, pt2)] 298 | else: 299 | return [(pt1, pt2)] 300 | 301 | 302 | 303 | 304 | if __name__ == '__main__': 305 | 306 | import os 307 | import unittest 308 | from defcon import Font 309 | 310 | class FontUtilsTests(unittest.TestCase): 311 | 312 | def setUp(self): 313 | libFolder = os.path.dirname(os.path.dirname((os.path.dirname(os.path.abspath(__file__))))) 314 | singleFontPath = u'testFonts/isotropic-anisotropic/regular-mid-contrast.ufo' 315 | fontPath = os.path.join(libFolder, singleFontPath) 316 | self.font = Font(fontPath) 317 | 318 | def test_intersect_horizontal(self): 319 | glyph = self.font['I'] 320 | yCenter = self.font.info.capHeight / 2 321 | intersections = intersect(glyph, yCenter, True) 322 | self.assertEqual(intersections, [(234.0, 375.0), (134.0, 375.0)]) 323 | 324 | def test_intersect_vertical(self): 325 | glyph = self.font['H'] 326 | xCenter = glyph.width / 2 327 | intersections = intersect(glyph, xCenter, False) 328 | self.assertEqual(intersections, [(426.5, 356.0), (426.5, 396.0)]) 329 | 330 | def test_intersect_vertical_with_overlap_removed(self): 331 | glyph = freezeGlyph(self.font['H']) 332 | xCenter = glyph.width / 2 333 | intersections = intersect(glyph, xCenter, False) 334 | self.assertEqual(intersections, [(426.5, 356.0), (426.5, 396.0)]) 335 | 336 | def test_getRefStems(self): 337 | stems = getRefStems(self.font) 338 | 339 | unittest.main() 340 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/bold-mid-contrast.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typemytype.robofont.compileSettings.autohint 6 | 7 | com.typemytype.robofont.compileSettings.checkOutlines 8 | 9 | com.typemytype.robofont.compileSettings.decompose 10 | 11 | com.typemytype.robofont.compileSettings.generateFormat 12 | 0 13 | com.typemytype.robofont.compileSettings.releaseMode 14 | 15 | com.typemytype.robofont.italicSlantOffset 16 | 0 17 | com.typemytype.robofont.layerOrder 18 | 19 | 20 | com.typemytype.robofont.segmentType 21 | curve 22 | com.typemytype.robofont.shouldAddPointsInSplineConversion 23 | 0 24 | com.typemytype.robofont.sort 25 | 26 | 27 | ascending 28 | 29 | space 30 | exclam 31 | quotedbl 32 | numbersign 33 | dollar 34 | percent 35 | ampersand 36 | parenleft 37 | parenright 38 | asterisk 39 | plus 40 | comma 41 | hyphen 42 | period 43 | slash 44 | zero 45 | one 46 | two 47 | three 48 | four 49 | five 50 | six 51 | seven 52 | eight 53 | nine 54 | colon 55 | semicolon 56 | less 57 | equal 58 | greater 59 | question 60 | at 61 | A 62 | B 63 | C 64 | D 65 | E 66 | F 67 | G 68 | H 69 | I 70 | J 71 | K 72 | L 73 | M 74 | N 75 | O 76 | P 77 | Q 78 | R 79 | S 80 | T 81 | U 82 | V 83 | W 84 | X 85 | Y 86 | Z 87 | bracketleft 88 | backslash 89 | bracketright 90 | asciicircum 91 | underscore 92 | grave 93 | a 94 | b 95 | c 96 | d 97 | e 98 | f 99 | g 100 | h 101 | i 102 | j 103 | k 104 | l 105 | m 106 | n 107 | o 108 | p 109 | q 110 | r 111 | s 112 | t 113 | u 114 | v 115 | w 116 | x 117 | y 118 | z 119 | braceleft 120 | bar 121 | braceright 122 | asciitilde 123 | exclamdown 124 | cent 125 | sterling 126 | currency 127 | yen 128 | brokenbar 129 | section 130 | dieresis 131 | copyright 132 | ordfeminine 133 | guillemotleft 134 | logicalnot 135 | registered 136 | macron 137 | degree 138 | plusminus 139 | twosuperior 140 | threesuperior 141 | acute 142 | mu 143 | paragraph 144 | periodcentered 145 | cedilla 146 | onesuperior 147 | ordmasculine 148 | guillemotright 149 | onequarter 150 | onehalf 151 | threequarters 152 | questiondown 153 | Agrave 154 | Aacute 155 | Acircumflex 156 | Atilde 157 | Adieresis 158 | Aring 159 | AE 160 | Ccedilla 161 | Egrave 162 | Eacute 163 | Ecircumflex 164 | Edieresis 165 | Igrave 166 | Iacute 167 | Icircumflex 168 | Idieresis 169 | Eth 170 | Ntilde 171 | Ograve 172 | Oacute 173 | Ocircumflex 174 | Otilde 175 | Odieresis 176 | multiply 177 | Oslash 178 | Ugrave 179 | Uacute 180 | Ucircumflex 181 | Udieresis 182 | Yacute 183 | Thorn 184 | germandbls 185 | agrave 186 | aacute 187 | acircumflex 188 | atilde 189 | adieresis 190 | aring 191 | ae 192 | ccedilla 193 | egrave 194 | eacute 195 | ecircumflex 196 | edieresis 197 | igrave 198 | iacute 199 | icircumflex 200 | idieresis 201 | eth 202 | ntilde 203 | ograve 204 | oacute 205 | ocircumflex 206 | otilde 207 | odieresis 208 | divide 209 | oslash 210 | ugrave 211 | uacute 212 | ucircumflex 213 | udieresis 214 | yacute 215 | thorn 216 | ydieresis 217 | dotlessi 218 | circumflex 219 | caron 220 | breve 221 | dotaccent 222 | ring 223 | ogonek 224 | tilde 225 | hungarumlaut 226 | quoteleft 227 | quoteright 228 | minus 229 | 230 | type 231 | glyphList 232 | 233 | 234 | public.glyphOrder 235 | 236 | space 237 | exclam 238 | quotedbl 239 | numbersign 240 | dollar 241 | percent 242 | ampersand 243 | parenleft 244 | parenright 245 | asterisk 246 | plus 247 | comma 248 | hyphen 249 | period 250 | slash 251 | zero 252 | one 253 | two 254 | three 255 | four 256 | five 257 | six 258 | seven 259 | eight 260 | nine 261 | colon 262 | semicolon 263 | less 264 | equal 265 | greater 266 | question 267 | at 268 | A 269 | B 270 | C 271 | D 272 | E 273 | F 274 | G 275 | H 276 | I 277 | J 278 | K 279 | L 280 | M 281 | N 282 | O 283 | P 284 | Q 285 | R 286 | S 287 | T 288 | U 289 | V 290 | W 291 | X 292 | Y 293 | Z 294 | bracketleft 295 | backslash 296 | bracketright 297 | asciicircum 298 | underscore 299 | grave 300 | a 301 | b 302 | c 303 | d 304 | e 305 | f 306 | g 307 | h 308 | i 309 | j 310 | k 311 | l 312 | m 313 | n 314 | o 315 | p 316 | q 317 | r 318 | s 319 | t 320 | u 321 | v 322 | w 323 | x 324 | y 325 | z 326 | braceleft 327 | bar 328 | braceright 329 | asciitilde 330 | exclamdown 331 | cent 332 | sterling 333 | currency 334 | yen 335 | brokenbar 336 | section 337 | dieresis 338 | copyright 339 | ordfeminine 340 | guillemotleft 341 | logicalnot 342 | registered 343 | macron 344 | degree 345 | plusminus 346 | twosuperior 347 | threesuperior 348 | acute 349 | mu 350 | paragraph 351 | periodcentered 352 | cedilla 353 | onesuperior 354 | ordmasculine 355 | guillemotright 356 | onequarter 357 | onehalf 358 | threequarters 359 | questiondown 360 | Agrave 361 | Aacute 362 | Acircumflex 363 | Atilde 364 | Adieresis 365 | Aring 366 | AE 367 | Ccedilla 368 | Egrave 369 | Eacute 370 | Ecircumflex 371 | Edieresis 372 | Igrave 373 | Iacute 374 | Icircumflex 375 | Idieresis 376 | Eth 377 | Ntilde 378 | Ograve 379 | Oacute 380 | Ocircumflex 381 | Otilde 382 | Odieresis 383 | multiply 384 | Oslash 385 | Ugrave 386 | Uacute 387 | Ucircumflex 388 | Udieresis 389 | Yacute 390 | Thorn 391 | germandbls 392 | agrave 393 | aacute 394 | acircumflex 395 | atilde 396 | adieresis 397 | aring 398 | ae 399 | ccedilla 400 | egrave 401 | eacute 402 | ecircumflex 403 | edieresis 404 | igrave 405 | iacute 406 | icircumflex 407 | idieresis 408 | eth 409 | ntilde 410 | ograve 411 | oacute 412 | ocircumflex 413 | otilde 414 | odieresis 415 | divide 416 | oslash 417 | ugrave 418 | uacute 419 | ucircumflex 420 | udieresis 421 | yacute 422 | thorn 423 | ydieresis 424 | dotlessi 425 | circumflex 426 | caron 427 | breve 428 | dotaccent 429 | ring 430 | ogonek 431 | tilde 432 | hungarumlaut 433 | quoteleft 434 | quoteright 435 | minus 436 | 437 | 438 | 439 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/isotropic-anisotropic/regular-mid-contrast.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typemytype.robofont.compileSettings.autohint 6 | 7 | com.typemytype.robofont.compileSettings.checkOutlines 8 | 9 | com.typemytype.robofont.compileSettings.decompose 10 | 11 | com.typemytype.robofont.compileSettings.generateFormat 12 | 0 13 | com.typemytype.robofont.compileSettings.releaseMode 14 | 15 | com.typemytype.robofont.italicSlantOffset 16 | 0 17 | com.typemytype.robofont.layerOrder 18 | 19 | 20 | com.typemytype.robofont.segmentType 21 | curve 22 | com.typemytype.robofont.shouldAddPointsInSplineConversion 23 | 0 24 | com.typemytype.robofont.sort 25 | 26 | 27 | ascending 28 | 29 | space 30 | exclam 31 | quotedbl 32 | numbersign 33 | dollar 34 | percent 35 | ampersand 36 | parenleft 37 | parenright 38 | asterisk 39 | plus 40 | comma 41 | hyphen 42 | period 43 | slash 44 | zero 45 | one 46 | two 47 | three 48 | four 49 | five 50 | six 51 | seven 52 | eight 53 | nine 54 | colon 55 | semicolon 56 | less 57 | equal 58 | greater 59 | question 60 | at 61 | A 62 | B 63 | C 64 | D 65 | E 66 | F 67 | G 68 | H 69 | I 70 | J 71 | K 72 | L 73 | M 74 | N 75 | O 76 | P 77 | Q 78 | R 79 | S 80 | T 81 | U 82 | V 83 | W 84 | X 85 | Y 86 | Z 87 | bracketleft 88 | backslash 89 | bracketright 90 | asciicircum 91 | underscore 92 | grave 93 | a 94 | b 95 | c 96 | d 97 | e 98 | f 99 | g 100 | h 101 | i 102 | j 103 | k 104 | l 105 | m 106 | n 107 | o 108 | p 109 | q 110 | r 111 | s 112 | t 113 | u 114 | v 115 | w 116 | x 117 | y 118 | z 119 | braceleft 120 | bar 121 | braceright 122 | asciitilde 123 | exclamdown 124 | cent 125 | sterling 126 | currency 127 | yen 128 | brokenbar 129 | section 130 | dieresis 131 | copyright 132 | ordfeminine 133 | guillemotleft 134 | logicalnot 135 | registered 136 | macron 137 | degree 138 | plusminus 139 | twosuperior 140 | threesuperior 141 | acute 142 | mu 143 | paragraph 144 | periodcentered 145 | cedilla 146 | onesuperior 147 | ordmasculine 148 | guillemotright 149 | onequarter 150 | onehalf 151 | threequarters 152 | questiondown 153 | Agrave 154 | Aacute 155 | Acircumflex 156 | Atilde 157 | Adieresis 158 | Aring 159 | AE 160 | Ccedilla 161 | Egrave 162 | Eacute 163 | Ecircumflex 164 | Edieresis 165 | Igrave 166 | Iacute 167 | Icircumflex 168 | Idieresis 169 | Eth 170 | Ntilde 171 | Ograve 172 | Oacute 173 | Ocircumflex 174 | Otilde 175 | Odieresis 176 | multiply 177 | Oslash 178 | Ugrave 179 | Uacute 180 | Ucircumflex 181 | Udieresis 182 | Yacute 183 | Thorn 184 | germandbls 185 | agrave 186 | aacute 187 | acircumflex 188 | atilde 189 | adieresis 190 | aring 191 | ae 192 | ccedilla 193 | egrave 194 | eacute 195 | ecircumflex 196 | edieresis 197 | igrave 198 | iacute 199 | icircumflex 200 | idieresis 201 | eth 202 | ntilde 203 | ograve 204 | oacute 205 | ocircumflex 206 | otilde 207 | odieresis 208 | divide 209 | oslash 210 | ugrave 211 | uacute 212 | ucircumflex 213 | udieresis 214 | yacute 215 | thorn 216 | ydieresis 217 | dotlessi 218 | circumflex 219 | caron 220 | breve 221 | dotaccent 222 | ring 223 | ogonek 224 | tilde 225 | hungarumlaut 226 | quoteleft 227 | quoteright 228 | minus 229 | 230 | type 231 | glyphList 232 | 233 | 234 | public.glyphOrder 235 | 236 | space 237 | exclam 238 | quotedbl 239 | numbersign 240 | dollar 241 | percent 242 | ampersand 243 | parenleft 244 | parenright 245 | asterisk 246 | plus 247 | comma 248 | hyphen 249 | period 250 | slash 251 | zero 252 | one 253 | two 254 | three 255 | four 256 | five 257 | six 258 | seven 259 | eight 260 | nine 261 | colon 262 | semicolon 263 | less 264 | equal 265 | greater 266 | question 267 | at 268 | A 269 | B 270 | C 271 | D 272 | E 273 | F 274 | G 275 | H 276 | I 277 | J 278 | K 279 | L 280 | M 281 | N 282 | O 283 | P 284 | Q 285 | R 286 | S 287 | T 288 | U 289 | V 290 | W 291 | X 292 | Y 293 | Z 294 | bracketleft 295 | backslash 296 | bracketright 297 | asciicircum 298 | underscore 299 | grave 300 | a 301 | b 302 | c 303 | d 304 | e 305 | f 306 | g 307 | h 308 | i 309 | j 310 | k 311 | l 312 | m 313 | n 314 | o 315 | p 316 | q 317 | r 318 | s 319 | t 320 | u 321 | v 322 | w 323 | x 324 | y 325 | z 326 | braceleft 327 | bar 328 | braceright 329 | asciitilde 330 | exclamdown 331 | cent 332 | sterling 333 | currency 334 | yen 335 | brokenbar 336 | section 337 | dieresis 338 | copyright 339 | ordfeminine 340 | guillemotleft 341 | logicalnot 342 | registered 343 | macron 344 | degree 345 | plusminus 346 | twosuperior 347 | threesuperior 348 | acute 349 | mu 350 | paragraph 351 | periodcentered 352 | cedilla 353 | onesuperior 354 | ordmasculine 355 | guillemotright 356 | onequarter 357 | onehalf 358 | threequarters 359 | questiondown 360 | Agrave 361 | Aacute 362 | Acircumflex 363 | Atilde 364 | Adieresis 365 | Aring 366 | AE 367 | Ccedilla 368 | Egrave 369 | Eacute 370 | Ecircumflex 371 | Edieresis 372 | Igrave 373 | Iacute 374 | Icircumflex 375 | Idieresis 376 | Eth 377 | Ntilde 378 | Ograve 379 | Oacute 380 | Ocircumflex 381 | Otilde 382 | Odieresis 383 | multiply 384 | Oslash 385 | Ugrave 386 | Uacute 387 | Ucircumflex 388 | Udieresis 389 | Yacute 390 | Thorn 391 | germandbls 392 | agrave 393 | aacute 394 | acircumflex 395 | atilde 396 | adieresis 397 | aring 398 | ae 399 | ccedilla 400 | egrave 401 | eacute 402 | ecircumflex 403 | edieresis 404 | igrave 405 | iacute 406 | icircumflex 407 | idieresis 408 | eth 409 | ntilde 410 | ograve 411 | oacute 412 | ocircumflex 413 | otilde 414 | odieresis 415 | divide 416 | oslash 417 | ugrave 418 | uacute 419 | ucircumflex 420 | udieresis 421 | yacute 422 | thorn 423 | ydieresis 424 | dotlessi 425 | circumflex 426 | caron 427 | breve 428 | dotaccent 429 | ring 430 | ogonek 431 | tilde 432 | hungarumlaut 433 | quoteleft 434 | quoteright 435 | minus 436 | 437 | 438 | 439 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-high-contrast.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typemytype.robofont.background.layerStrokeColor 6 | 7 | 0.0 8 | 0.8 9 | 0.2 10 | 0.7 11 | 12 | com.typemytype.robofont.compileSettings.autohint 13 | 14 | com.typemytype.robofont.compileSettings.checkOutlines 15 | 16 | com.typemytype.robofont.compileSettings.decompose 17 | 18 | com.typemytype.robofont.compileSettings.generateFormat 19 | 0 20 | com.typemytype.robofont.compileSettings.releaseMode 21 | 22 | com.typemytype.robofont.italicSlantOffset 23 | 0 24 | com.typemytype.robofont.layerOrder 25 | 26 | background 27 | 28 | com.typemytype.robofont.segmentType 29 | curve 30 | com.typemytype.robofont.shouldAddPointsInSplineConversion 31 | 0 32 | com.typemytype.robofont.sort 33 | 34 | 35 | ascending 36 | 37 | space 38 | exclam 39 | quotedbl 40 | numbersign 41 | dollar 42 | percent 43 | ampersand 44 | parenleft 45 | parenright 46 | asterisk 47 | plus 48 | comma 49 | hyphen 50 | period 51 | slash 52 | zero 53 | one 54 | two 55 | three 56 | four 57 | five 58 | six 59 | seven 60 | eight 61 | nine 62 | colon 63 | semicolon 64 | less 65 | equal 66 | greater 67 | question 68 | at 69 | A 70 | B 71 | C 72 | D 73 | E 74 | F 75 | G 76 | H 77 | I 78 | J 79 | K 80 | L 81 | M 82 | N 83 | O 84 | P 85 | Q 86 | R 87 | S 88 | T 89 | U 90 | V 91 | W 92 | X 93 | Y 94 | Z 95 | bracketleft 96 | backslash 97 | bracketright 98 | asciicircum 99 | underscore 100 | grave 101 | a 102 | b 103 | c 104 | d 105 | e 106 | f 107 | g 108 | h 109 | i 110 | j 111 | k 112 | l 113 | m 114 | n 115 | o 116 | p 117 | q 118 | r 119 | s 120 | t 121 | u 122 | v 123 | w 124 | x 125 | y 126 | z 127 | braceleft 128 | bar 129 | braceright 130 | asciitilde 131 | exclamdown 132 | cent 133 | sterling 134 | currency 135 | yen 136 | brokenbar 137 | section 138 | dieresis 139 | copyright 140 | ordfeminine 141 | guillemotleft 142 | logicalnot 143 | registered 144 | macron 145 | degree 146 | plusminus 147 | twosuperior 148 | threesuperior 149 | acute 150 | mu 151 | paragraph 152 | periodcentered 153 | cedilla 154 | onesuperior 155 | ordmasculine 156 | guillemotright 157 | onequarter 158 | onehalf 159 | threequarters 160 | questiondown 161 | Agrave 162 | Aacute 163 | Acircumflex 164 | Atilde 165 | Adieresis 166 | Aring 167 | AE 168 | Ccedilla 169 | Egrave 170 | Eacute 171 | Ecircumflex 172 | Edieresis 173 | Igrave 174 | Iacute 175 | Icircumflex 176 | Idieresis 177 | Eth 178 | Ntilde 179 | Ograve 180 | Oacute 181 | Ocircumflex 182 | Otilde 183 | Odieresis 184 | multiply 185 | Oslash 186 | Ugrave 187 | Uacute 188 | Ucircumflex 189 | Udieresis 190 | Yacute 191 | Thorn 192 | germandbls 193 | agrave 194 | aacute 195 | acircumflex 196 | atilde 197 | adieresis 198 | aring 199 | ae 200 | ccedilla 201 | egrave 202 | eacute 203 | ecircumflex 204 | edieresis 205 | igrave 206 | iacute 207 | icircumflex 208 | idieresis 209 | eth 210 | ntilde 211 | ograve 212 | oacute 213 | ocircumflex 214 | otilde 215 | odieresis 216 | divide 217 | oslash 218 | ugrave 219 | uacute 220 | ucircumflex 221 | udieresis 222 | yacute 223 | thorn 224 | ydieresis 225 | dotlessi 226 | circumflex 227 | caron 228 | breve 229 | dotaccent 230 | ring 231 | ogonek 232 | tilde 233 | hungarumlaut 234 | quoteleft 235 | quoteright 236 | minus 237 | 238 | type 239 | glyphList 240 | 241 | 242 | public.glyphOrder 243 | 244 | space 245 | exclam 246 | quotedbl 247 | numbersign 248 | dollar 249 | percent 250 | ampersand 251 | parenleft 252 | parenright 253 | asterisk 254 | plus 255 | comma 256 | hyphen 257 | period 258 | slash 259 | zero 260 | one 261 | two 262 | three 263 | four 264 | five 265 | six 266 | seven 267 | eight 268 | nine 269 | colon 270 | semicolon 271 | less 272 | equal 273 | greater 274 | question 275 | at 276 | A 277 | B 278 | C 279 | D 280 | E 281 | F 282 | G 283 | H 284 | I 285 | J 286 | K 287 | L 288 | M 289 | N 290 | O 291 | P 292 | Q 293 | R 294 | S 295 | T 296 | U 297 | V 298 | W 299 | X 300 | Y 301 | Z 302 | bracketleft 303 | backslash 304 | bracketright 305 | asciicircum 306 | underscore 307 | grave 308 | a 309 | b 310 | c 311 | d 312 | e 313 | f 314 | g 315 | h 316 | i 317 | j 318 | k 319 | l 320 | m 321 | n 322 | o 323 | p 324 | q 325 | r 326 | s 327 | t 328 | u 329 | v 330 | w 331 | x 332 | y 333 | z 334 | braceleft 335 | bar 336 | braceright 337 | asciitilde 338 | exclamdown 339 | cent 340 | sterling 341 | currency 342 | yen 343 | brokenbar 344 | section 345 | dieresis 346 | copyright 347 | ordfeminine 348 | guillemotleft 349 | logicalnot 350 | registered 351 | macron 352 | degree 353 | plusminus 354 | twosuperior 355 | threesuperior 356 | acute 357 | mu 358 | paragraph 359 | periodcentered 360 | cedilla 361 | onesuperior 362 | ordmasculine 363 | guillemotright 364 | onequarter 365 | onehalf 366 | threequarters 367 | questiondown 368 | Agrave 369 | Aacute 370 | Acircumflex 371 | Atilde 372 | Adieresis 373 | Aring 374 | AE 375 | Ccedilla 376 | Egrave 377 | Eacute 378 | Ecircumflex 379 | Edieresis 380 | Igrave 381 | Iacute 382 | Icircumflex 383 | Idieresis 384 | Eth 385 | Ntilde 386 | Ograve 387 | Oacute 388 | Ocircumflex 389 | Otilde 390 | Odieresis 391 | multiply 392 | Oslash 393 | Ugrave 394 | Uacute 395 | Ucircumflex 396 | Udieresis 397 | Yacute 398 | Thorn 399 | germandbls 400 | agrave 401 | aacute 402 | acircumflex 403 | atilde 404 | adieresis 405 | aring 406 | ae 407 | ccedilla 408 | egrave 409 | eacute 410 | ecircumflex 411 | edieresis 412 | igrave 413 | iacute 414 | icircumflex 415 | idieresis 416 | eth 417 | ntilde 418 | ograve 419 | oacute 420 | ocircumflex 421 | otilde 422 | odieresis 423 | divide 424 | oslash 425 | ugrave 426 | uacute 427 | ucircumflex 428 | udieresis 429 | yacute 430 | thorn 431 | ydieresis 432 | dotlessi 433 | circumflex 434 | caron 435 | breve 436 | dotaccent 437 | ring 438 | ogonek 439 | tilde 440 | hungarumlaut 441 | quoteleft 442 | quoteright 443 | minus 444 | 445 | 446 | 447 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-low-contrast.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typemytype.robofont.background.layerStrokeColor 6 | 7 | 0.0 8 | 0.8 9 | 0.2 10 | 0.7 11 | 12 | com.typemytype.robofont.compileSettings.autohint 13 | 14 | com.typemytype.robofont.compileSettings.checkOutlines 15 | 16 | com.typemytype.robofont.compileSettings.decompose 17 | 18 | com.typemytype.robofont.compileSettings.generateFormat 19 | 0 20 | com.typemytype.robofont.compileSettings.releaseMode 21 | 22 | com.typemytype.robofont.italicSlantOffset 23 | 0 24 | com.typemytype.robofont.layerOrder 25 | 26 | background 27 | 28 | com.typemytype.robofont.segmentType 29 | curve 30 | com.typemytype.robofont.shouldAddPointsInSplineConversion 31 | 0 32 | com.typemytype.robofont.sort 33 | 34 | 35 | ascending 36 | 37 | space 38 | exclam 39 | quotedbl 40 | numbersign 41 | dollar 42 | percent 43 | ampersand 44 | parenleft 45 | parenright 46 | asterisk 47 | plus 48 | comma 49 | hyphen 50 | period 51 | slash 52 | zero 53 | one 54 | two 55 | three 56 | four 57 | five 58 | six 59 | seven 60 | eight 61 | nine 62 | colon 63 | semicolon 64 | less 65 | equal 66 | greater 67 | question 68 | at 69 | A 70 | B 71 | C 72 | D 73 | E 74 | F 75 | G 76 | H 77 | I 78 | J 79 | K 80 | L 81 | M 82 | N 83 | O 84 | P 85 | Q 86 | R 87 | S 88 | T 89 | U 90 | V 91 | W 92 | X 93 | Y 94 | Z 95 | bracketleft 96 | backslash 97 | bracketright 98 | asciicircum 99 | underscore 100 | grave 101 | a 102 | b 103 | c 104 | d 105 | e 106 | f 107 | g 108 | h 109 | i 110 | j 111 | k 112 | l 113 | m 114 | n 115 | o 116 | p 117 | q 118 | r 119 | s 120 | t 121 | u 122 | v 123 | w 124 | x 125 | y 126 | z 127 | braceleft 128 | bar 129 | braceright 130 | asciitilde 131 | exclamdown 132 | cent 133 | sterling 134 | currency 135 | yen 136 | brokenbar 137 | section 138 | dieresis 139 | copyright 140 | ordfeminine 141 | guillemotleft 142 | logicalnot 143 | registered 144 | macron 145 | degree 146 | plusminus 147 | twosuperior 148 | threesuperior 149 | acute 150 | mu 151 | paragraph 152 | periodcentered 153 | cedilla 154 | onesuperior 155 | ordmasculine 156 | guillemotright 157 | onequarter 158 | onehalf 159 | threequarters 160 | questiondown 161 | Agrave 162 | Aacute 163 | Acircumflex 164 | Atilde 165 | Adieresis 166 | Aring 167 | AE 168 | Ccedilla 169 | Egrave 170 | Eacute 171 | Ecircumflex 172 | Edieresis 173 | Igrave 174 | Iacute 175 | Icircumflex 176 | Idieresis 177 | Eth 178 | Ntilde 179 | Ograve 180 | Oacute 181 | Ocircumflex 182 | Otilde 183 | Odieresis 184 | multiply 185 | Oslash 186 | Ugrave 187 | Uacute 188 | Ucircumflex 189 | Udieresis 190 | Yacute 191 | Thorn 192 | germandbls 193 | agrave 194 | aacute 195 | acircumflex 196 | atilde 197 | adieresis 198 | aring 199 | ae 200 | ccedilla 201 | egrave 202 | eacute 203 | ecircumflex 204 | edieresis 205 | igrave 206 | iacute 207 | icircumflex 208 | idieresis 209 | eth 210 | ntilde 211 | ograve 212 | oacute 213 | ocircumflex 214 | otilde 215 | odieresis 216 | divide 217 | oslash 218 | ugrave 219 | uacute 220 | ucircumflex 221 | udieresis 222 | yacute 223 | thorn 224 | ydieresis 225 | dotlessi 226 | circumflex 227 | caron 228 | breve 229 | dotaccent 230 | ring 231 | ogonek 232 | tilde 233 | hungarumlaut 234 | quoteleft 235 | quoteright 236 | minus 237 | 238 | type 239 | glyphList 240 | 241 | 242 | public.glyphOrder 243 | 244 | space 245 | exclam 246 | quotedbl 247 | numbersign 248 | dollar 249 | percent 250 | ampersand 251 | parenleft 252 | parenright 253 | asterisk 254 | plus 255 | comma 256 | hyphen 257 | period 258 | slash 259 | zero 260 | one 261 | two 262 | three 263 | four 264 | five 265 | six 266 | seven 267 | eight 268 | nine 269 | colon 270 | semicolon 271 | less 272 | equal 273 | greater 274 | question 275 | at 276 | A 277 | B 278 | C 279 | D 280 | E 281 | F 282 | G 283 | H 284 | I 285 | J 286 | K 287 | L 288 | M 289 | N 290 | O 291 | P 292 | Q 293 | R 294 | S 295 | T 296 | U 297 | V 298 | W 299 | X 300 | Y 301 | Z 302 | bracketleft 303 | backslash 304 | bracketright 305 | asciicircum 306 | underscore 307 | grave 308 | a 309 | b 310 | c 311 | d 312 | e 313 | f 314 | g 315 | h 316 | i 317 | j 318 | k 319 | l 320 | m 321 | n 322 | o 323 | p 324 | q 325 | r 326 | s 327 | t 328 | u 329 | v 330 | w 331 | x 332 | y 333 | z 334 | braceleft 335 | bar 336 | braceright 337 | asciitilde 338 | exclamdown 339 | cent 340 | sterling 341 | currency 342 | yen 343 | brokenbar 344 | section 345 | dieresis 346 | copyright 347 | ordfeminine 348 | guillemotleft 349 | logicalnot 350 | registered 351 | macron 352 | degree 353 | plusminus 354 | twosuperior 355 | threesuperior 356 | acute 357 | mu 358 | paragraph 359 | periodcentered 360 | cedilla 361 | onesuperior 362 | ordmasculine 363 | guillemotright 364 | onequarter 365 | onehalf 366 | threequarters 367 | questiondown 368 | Agrave 369 | Aacute 370 | Acircumflex 371 | Atilde 372 | Adieresis 373 | Aring 374 | AE 375 | Ccedilla 376 | Egrave 377 | Eacute 378 | Ecircumflex 379 | Edieresis 380 | Igrave 381 | Iacute 382 | Icircumflex 383 | Idieresis 384 | Eth 385 | Ntilde 386 | Ograve 387 | Oacute 388 | Ocircumflex 389 | Otilde 390 | Odieresis 391 | multiply 392 | Oslash 393 | Ugrave 394 | Uacute 395 | Ucircumflex 396 | Udieresis 397 | Yacute 398 | Thorn 399 | germandbls 400 | agrave 401 | aacute 402 | acircumflex 403 | atilde 404 | adieresis 405 | aring 406 | ae 407 | ccedilla 408 | egrave 409 | eacute 410 | ecircumflex 411 | edieresis 412 | igrave 413 | iacute 414 | icircumflex 415 | idieresis 416 | eth 417 | ntilde 418 | ograve 419 | oacute 420 | ocircumflex 421 | otilde 422 | odieresis 423 | divide 424 | oslash 425 | ugrave 426 | uacute 427 | ucircumflex 428 | udieresis 429 | yacute 430 | thorn 431 | ydieresis 432 | dotlessi 433 | circumflex 434 | caron 435 | breve 436 | dotaccent 437 | ring 438 | ogonek 439 | tilde 440 | hungarumlaut 441 | quoteleft 442 | quoteright 443 | minus 444 | 445 | 446 | 447 | -------------------------------------------------------------------------------- /source/lib/MutatorScale/lib/testFonts/two-axes/bold-italic-low-contrast.ufo/lib.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.typemytype.robofont.background.layerStrokeColor 6 | 7 | 0.0 8 | 0.8 9 | 0.2 10 | 0.7 11 | 12 | com.typemytype.robofont.compileSettings.autohint 13 | 14 | com.typemytype.robofont.compileSettings.checkOutlines 15 | 16 | com.typemytype.robofont.compileSettings.decompose 17 | 18 | com.typemytype.robofont.compileSettings.generateFormat 19 | 0 20 | com.typemytype.robofont.compileSettings.releaseMode 21 | 22 | com.typemytype.robofont.italicSlantOffset 23 | 0 24 | com.typemytype.robofont.layerOrder 25 | 26 | background 27 | 28 | com.typemytype.robofont.segmentType 29 | curve 30 | com.typemytype.robofont.shouldAddPointsInSplineConversion 31 | 0 32 | com.typemytype.robofont.sort 33 | 34 | 35 | ascending 36 | 37 | space 38 | exclam 39 | quotedbl 40 | numbersign 41 | dollar 42 | percent 43 | ampersand 44 | parenleft 45 | parenright 46 | asterisk 47 | plus 48 | comma 49 | hyphen 50 | period 51 | slash 52 | zero 53 | one 54 | two 55 | three 56 | four 57 | five 58 | six 59 | seven 60 | eight 61 | nine 62 | colon 63 | semicolon 64 | less 65 | equal 66 | greater 67 | question 68 | at 69 | A 70 | B 71 | C 72 | D 73 | E 74 | F 75 | G 76 | H 77 | I 78 | J 79 | K 80 | L 81 | M 82 | N 83 | O 84 | P 85 | Q 86 | R 87 | S 88 | T 89 | U 90 | V 91 | W 92 | X 93 | Y 94 | Z 95 | bracketleft 96 | backslash 97 | bracketright 98 | asciicircum 99 | underscore 100 | grave 101 | a 102 | b 103 | c 104 | d 105 | e 106 | f 107 | g 108 | h 109 | i 110 | j 111 | k 112 | l 113 | m 114 | n 115 | o 116 | p 117 | q 118 | r 119 | s 120 | t 121 | u 122 | v 123 | w 124 | x 125 | y 126 | z 127 | braceleft 128 | bar 129 | braceright 130 | asciitilde 131 | exclamdown 132 | cent 133 | sterling 134 | currency 135 | yen 136 | brokenbar 137 | section 138 | dieresis 139 | copyright 140 | ordfeminine 141 | guillemotleft 142 | logicalnot 143 | registered 144 | macron 145 | degree 146 | plusminus 147 | twosuperior 148 | threesuperior 149 | acute 150 | mu 151 | paragraph 152 | periodcentered 153 | cedilla 154 | onesuperior 155 | ordmasculine 156 | guillemotright 157 | onequarter 158 | onehalf 159 | threequarters 160 | questiondown 161 | Agrave 162 | Aacute 163 | Acircumflex 164 | Atilde 165 | Adieresis 166 | Aring 167 | AE 168 | Ccedilla 169 | Egrave 170 | Eacute 171 | Ecircumflex 172 | Edieresis 173 | Igrave 174 | Iacute 175 | Icircumflex 176 | Idieresis 177 | Eth 178 | Ntilde 179 | Ograve 180 | Oacute 181 | Ocircumflex 182 | Otilde 183 | Odieresis 184 | multiply 185 | Oslash 186 | Ugrave 187 | Uacute 188 | Ucircumflex 189 | Udieresis 190 | Yacute 191 | Thorn 192 | germandbls 193 | agrave 194 | aacute 195 | acircumflex 196 | atilde 197 | adieresis 198 | aring 199 | ae 200 | ccedilla 201 | egrave 202 | eacute 203 | ecircumflex 204 | edieresis 205 | igrave 206 | iacute 207 | icircumflex 208 | idieresis 209 | eth 210 | ntilde 211 | ograve 212 | oacute 213 | ocircumflex 214 | otilde 215 | odieresis 216 | divide 217 | oslash 218 | ugrave 219 | uacute 220 | ucircumflex 221 | udieresis 222 | yacute 223 | thorn 224 | ydieresis 225 | dotlessi 226 | circumflex 227 | caron 228 | breve 229 | dotaccent 230 | ring 231 | ogonek 232 | tilde 233 | hungarumlaut 234 | quoteleft 235 | quoteright 236 | minus 237 | 238 | type 239 | glyphList 240 | 241 | 242 | public.glyphOrder 243 | 244 | space 245 | exclam 246 | quotedbl 247 | numbersign 248 | dollar 249 | percent 250 | ampersand 251 | parenleft 252 | parenright 253 | asterisk 254 | plus 255 | comma 256 | hyphen 257 | period 258 | slash 259 | zero 260 | one 261 | two 262 | three 263 | four 264 | five 265 | six 266 | seven 267 | eight 268 | nine 269 | colon 270 | semicolon 271 | less 272 | equal 273 | greater 274 | question 275 | at 276 | A 277 | B 278 | C 279 | D 280 | E 281 | F 282 | G 283 | H 284 | I 285 | J 286 | K 287 | L 288 | M 289 | N 290 | O 291 | P 292 | Q 293 | R 294 | S 295 | T 296 | U 297 | V 298 | W 299 | X 300 | Y 301 | Z 302 | bracketleft 303 | backslash 304 | bracketright 305 | asciicircum 306 | underscore 307 | grave 308 | a 309 | b 310 | c 311 | d 312 | e 313 | f 314 | g 315 | h 316 | i 317 | j 318 | k 319 | l 320 | m 321 | n 322 | o 323 | p 324 | q 325 | r 326 | s 327 | t 328 | u 329 | v 330 | w 331 | x 332 | y 333 | z 334 | braceleft 335 | bar 336 | braceright 337 | asciitilde 338 | exclamdown 339 | cent 340 | sterling 341 | currency 342 | yen 343 | brokenbar 344 | section 345 | dieresis 346 | copyright 347 | ordfeminine 348 | guillemotleft 349 | logicalnot 350 | registered 351 | macron 352 | degree 353 | plusminus 354 | twosuperior 355 | threesuperior 356 | acute 357 | mu 358 | paragraph 359 | periodcentered 360 | cedilla 361 | onesuperior 362 | ordmasculine 363 | guillemotright 364 | onequarter 365 | onehalf 366 | threequarters 367 | questiondown 368 | Agrave 369 | Aacute 370 | Acircumflex 371 | Atilde 372 | Adieresis 373 | Aring 374 | AE 375 | Ccedilla 376 | Egrave 377 | Eacute 378 | Ecircumflex 379 | Edieresis 380 | Igrave 381 | Iacute 382 | Icircumflex 383 | Idieresis 384 | Eth 385 | Ntilde 386 | Ograve 387 | Oacute 388 | Ocircumflex 389 | Otilde 390 | Odieresis 391 | multiply 392 | Oslash 393 | Ugrave 394 | Uacute 395 | Ucircumflex 396 | Udieresis 397 | Yacute 398 | Thorn 399 | germandbls 400 | agrave 401 | aacute 402 | acircumflex 403 | atilde 404 | adieresis 405 | aring 406 | ae 407 | ccedilla 408 | egrave 409 | eacute 410 | ecircumflex 411 | edieresis 412 | igrave 413 | iacute 414 | icircumflex 415 | idieresis 416 | eth 417 | ntilde 418 | ograve 419 | oacute 420 | ocircumflex 421 | otilde 422 | odieresis 423 | divide 424 | oslash 425 | ugrave 426 | uacute 427 | ucircumflex 428 | udieresis 429 | yacute 430 | thorn 431 | ydieresis 432 | dotlessi 433 | circumflex 434 | caron 435 | breve 436 | dotaccent 437 | ring 438 | ogonek 439 | tilde 440 | hungarumlaut 441 | quoteleft 442 | quoteright 443 | minus 444 | 445 | 446 | 447 | --------------------------------------------------------------------------------