├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle-mvn-push.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib-truetypeparser-light ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── jaredrummler │ └── truetypeparser │ ├── FontFileReader.java │ ├── TTFDirTabEntry.java │ ├── TTFFile.java │ └── TTFTableName.java ├── lib-truetypeparser ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── jaredrummler │ └── fontreader │ ├── complexscripts │ ├── bidi │ │ ├── BidiClass.java │ │ └── BidiConstants.java │ ├── fonts │ │ ├── AdvancedTypographicTableFormatException.java │ │ ├── GlyphClassMapping.java │ │ ├── GlyphClassTable.java │ │ ├── GlyphContextTester.java │ │ ├── GlyphCoverageMapping.java │ │ ├── GlyphCoverageTable.java │ │ ├── GlyphDefinition.java │ │ ├── GlyphDefinitionSubtable.java │ │ ├── GlyphDefinitionTable.java │ │ ├── GlyphMappingTable.java │ │ ├── GlyphPositioning.java │ │ ├── GlyphPositioningState.java │ │ ├── GlyphPositioningSubtable.java │ │ ├── GlyphPositioningTable.java │ │ ├── GlyphProcessingState.java │ │ ├── Positionable.java │ │ └── Substitutable.java │ ├── scripts │ │ ├── ArabicScriptProcessor.java │ │ ├── DefaultScriptProcessor.java │ │ ├── DevanagariScriptProcessor.java │ │ ├── GujaratiScriptProcessor.java │ │ ├── GurmukhiScriptProcessor.java │ │ ├── IndicScriptProcessor.java │ │ ├── ScriptProcessor.java │ │ └── TamilScriptProcessor.java │ └── util │ │ ├── CharAssociation.java │ │ └── CharScript.java │ ├── fonts │ ├── CMapSegment.java │ ├── CodePointMapping.java │ ├── Font.java │ ├── FontMetrics.java │ ├── FontTriplet.java │ ├── FontType.java │ ├── FontUtil.java │ ├── GlyphSubstitution.java │ ├── GlyphSubstitutionState.java │ ├── GlyphSubstitutionSubtable.java │ ├── GlyphSubstitutionTable.java │ ├── GlyphSubtable.java │ ├── Glyphs.java │ ├── OTFAdvancedTypographicTableReader.java │ ├── OTFLanguage.java │ ├── OTFScript.java │ ├── SingleByteEncoding.java │ └── Typeface.java │ ├── io │ ├── ByteArrayOutputStream.java │ ├── Charsets.java │ ├── ClosedInputStream.java │ ├── IOUtils.java │ ├── LineIterator.java │ └── StringBuilderWriter.java │ ├── truetype │ ├── FontFileReader.java │ ├── GlyphTable.java │ ├── OFDirTabEntry.java │ ├── OFMtxEntry.java │ ├── OFTableName.java │ ├── OpenFont.java │ ├── TTFFile.java │ ├── TTFGlyphOutputStream.java │ ├── TTFOutputStream.java │ └── TTFTableOutputStream.java │ └── util │ ├── CharUtilities.java │ ├── GlyphSequence.java │ ├── GlyphTester.java │ └── ScriptContextTester.java ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── font.ttf │ ├── java │ └── com │ │ └── jaredrummler │ │ └── truetype │ │ └── sample │ │ └── MainActivity.java │ └── res │ ├── drawable │ └── ic_font_white_24dp.xml │ ├── layout │ ├── activity_main.xml │ └── content_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ########### Specifies intentionally untracked files to ignore ########### 2 | 3 | ### Gradle 4 | .gradle/ 5 | build/ 6 | 7 | ### IntelliJ IDEA 8 | /.idea 9 | *.iml 10 | *.iws 11 | captures/ 12 | .navigation/ 13 | local.properties 14 | bin/ 15 | gen/ 16 | out/ 17 | *.apk 18 | *.ap_ 19 | 20 | ### Android 21 | *.jks 22 | *.dex 23 | 24 | ### Java 25 | *.class 26 | hs_err_pid* 27 | 28 | ### Windows 29 | Desktop.ini 30 | Thumbs.db 31 | ehthumbs.db 32 | 33 | ### OSX 34 | .DS_Store 35 | 36 | ### Linux 37 | *~ 38 | .fuse_hidden* 39 | .directory 40 | .Trash-* 41 | 42 | ### Logs 43 | *.log 44 | 45 | ### Crashlytics 46 | crashlytics.properties 47 | fabric.properties -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TrueTypeParser 2 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.jaredrummler/truetypeparser/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.jaredrummler/truetypeparser) [![License](http://img.shields.io/:license-apache-blue.svg)](LICENSE) [![API](https://img.shields.io/badge/API-7%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=7) 3 | 4 | TrueType Font Parser for Android based on [Apache FOP](http://xmlgraphics.apache.org/fop/). 5 | 6 | Download 7 | -------- 8 | 9 | Download [the latest AAR](https://repo1.maven.org/maven2/com/jaredrummler/truetypeparser/1.0.0/truetypeparser-1.0.0.aar) or grab via Gradle: 10 | 11 | ```groovy 12 | compile 'com.jaredrummler:truetypeparser:1.0.0' 13 | ``` 14 | or Maven: 15 | ```xml 16 | 17 | com.jaredrummler 18 | truetypeparser 19 | 1.0.0 20 | aar 21 | 22 | ``` 23 | 24 | Usage 25 | ----- 26 | 27 | ```java 28 | TTFFile ttfFile = TTFFile.open(getAssets().open("fonts/your-font.ttf")); 29 | String name = ttfFile.getFullName(); 30 | String family = ttfFile.getSubFamilyName(); 31 | int fontWeight = ttfFile.getWeightClass(); 32 | String copyright = ttfFile.getCopyrightNotice(); 33 | Map> kerning = ttfFile.getKerning(); 34 | ``` 35 | 36 | TrueTypeParser Light 37 | -------------------- 38 | 39 | If you don't need to read kerning pairs consider using the light version. The light version will read the font file's name, families, weight, and notice. The method count is much smaller. 40 | 41 | ```groovy 42 | compile 'com.jaredrummler:truetypeparser-light:1.0.0' 43 | ``` 44 | 45 | License 46 | -------- 47 | 48 | Copyright (C) 2016 Jared Rummler 49 | 50 | Licensed under the Apache License, Version 2.0 (the "License"); 51 | you may not use this file except in compliance with the License. 52 | You may obtain a copy of the License at 53 | 54 | http://www.apache.org/licenses/LICENSE-2.0 55 | 56 | Unless required by applicable law or agreed to in writing, software 57 | distributed under the License is distributed on an "AS IS" BASIS, 58 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 | See the License for the specific language governing permissions and 60 | limitations under the License. 61 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:2.2.0' 7 | } 8 | } 9 | 10 | allprojects { 11 | repositories { 12 | jcenter() 13 | } 14 | } 15 | 16 | task clean(type: Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /gradle-mvn-push.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Chris Banes 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'maven' 18 | apply plugin: 'signing' 19 | 20 | def isReleaseBuild() { 21 | return VERSION_NAME.contains("SNAPSHOT") == false 22 | } 23 | 24 | def getReleaseRepositoryUrl() { 25 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 26 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 27 | } 28 | 29 | def getSnapshotRepositoryUrl() { 30 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 31 | : "https://oss.sonatype.org/content/repositories/snapshots/" 32 | } 33 | 34 | def getRepositoryUsername() { 35 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" 36 | } 37 | 38 | def getRepositoryPassword() { 39 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" 40 | } 41 | 42 | afterEvaluate { project -> 43 | uploadArchives { 44 | repositories { 45 | mavenDeployer { 46 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 47 | 48 | pom.groupId = GROUP 49 | pom.artifactId = POM_ARTIFACT_ID 50 | pom.version = VERSION_NAME 51 | 52 | repository(url: getReleaseRepositoryUrl()) { 53 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 54 | } 55 | snapshotRepository(url: getSnapshotRepositoryUrl()) { 56 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 57 | } 58 | 59 | pom.project { 60 | name POM_NAME 61 | packaging POM_PACKAGING 62 | description POM_DESCRIPTION 63 | url POM_URL 64 | 65 | scm { 66 | url POM_SCM_URL 67 | connection POM_SCM_CONNECTION 68 | developerConnection POM_SCM_DEV_CONNECTION 69 | } 70 | 71 | licenses { 72 | license { 73 | name POM_LICENCE_NAME 74 | url POM_LICENCE_URL 75 | distribution POM_LICENCE_DIST 76 | } 77 | } 78 | 79 | developers { 80 | developer { 81 | id POM_DEVELOPER_ID 82 | name POM_DEVELOPER_NAME 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | signing { 91 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 92 | sign configurations.archives 93 | } 94 | 95 | task androidJavadocs(type: Javadoc) { 96 | failOnError = false 97 | source = android.sourceSets.main.java.srcDirs 98 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 99 | } 100 | 101 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 102 | classifier = 'javadoc' 103 | from androidJavadocs.destinationDir 104 | } 105 | 106 | task androidSourcesJar(type: Jar) { 107 | classifier = 'sources' 108 | from android.sourceSets.main.java.sourceFiles 109 | } 110 | 111 | artifacts { 112 | archives androidSourcesJar 113 | archives androidJavadocsJar 114 | } 115 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | VERSION_NAME=1.0.0 2 | VERSION_CODE=0 3 | GROUP=com.jaredrummler 4 | 5 | POM_NAME=True Type Parser 6 | POM_ARTIFACT_ID=truetypeparser 7 | POM_PACKAGING=aar 8 | 9 | POM_DESCRIPTION=TTF and OTF font parser 10 | POM_URL=https://github.com/jaredrummler/TrueTypeParser 11 | POM_SCM_URL=https://github.com/jaredrummler/TrueTypeParser 12 | POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/TrueTypeParser.git 13 | POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/TrueTypeParser.git 14 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 15 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 16 | POM_LICENCE_DIST=repo 17 | POM_DEVELOPER_ID=jaredrummler 18 | POM_DEVELOPER_NAME=Jared Rummler 19 | 20 | SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots 21 | RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 04 11:01:44 PDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.3" 6 | defaultConfig { 7 | minSdkVersion 4 8 | targetSdkVersion 24 9 | } 10 | lintOptions { 11 | abortOnError false 12 | } 13 | } 14 | 15 | apply from: '../gradle-mvn-push.gradle' 16 | 17 | afterEvaluate { 18 | androidJavadocs.classpath += project.android.libraryVariants.toList().first().javaCompile.classpath 19 | } -------------------------------------------------------------------------------- /lib-truetypeparser-light/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 Jared Rummler 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | 18 | VERSION_NAME=1.0.0 19 | VERSION_CODE=0 20 | POM_ARTIFACT_ID=truetypeparser-light -------------------------------------------------------------------------------- /lib-truetypeparser-light/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/src/main/java/com/jaredrummler/truetypeparser/FontFileReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.truetypeparser; 19 | 20 | import java.io.ByteArrayOutputStream; 21 | import java.io.EOFException; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | 27 | /** 28 | * Reads a TrueType font file into a byte array and provides file like functions for array access. 29 | */ 30 | public class FontFileReader { 31 | 32 | private int fsize; // file size 33 | private int current; // current position in file 34 | private byte[] file; 35 | 36 | /** 37 | * Constructor 38 | * 39 | * @param in 40 | * InputStream to read from 41 | * @throws IOException 42 | * In case of an I/O problem 43 | */ 44 | public FontFileReader(InputStream in) throws IOException { 45 | init(in); 46 | } 47 | 48 | /** 49 | * Constructor 50 | * 51 | * @param path 52 | * file to read 53 | * @throws IOException 54 | * In case of an I/O problem 55 | */ 56 | public FontFileReader(String path) throws IOException { 57 | InputStream in = new FileInputStream(new File(path)); 58 | try { 59 | init(in); 60 | } finally { 61 | in.close(); 62 | } 63 | } 64 | 65 | /** 66 | * Returns the full byte array representation of the file. 67 | * 68 | * @return byte array. 69 | */ 70 | public byte[] getAllBytes() { 71 | return file; 72 | } 73 | 74 | /** 75 | * Returns current file position. 76 | * 77 | * @return int The current position. 78 | */ 79 | public int getCurrentPos() { 80 | return current; 81 | } 82 | 83 | /** 84 | * Returns the size of the file. 85 | * 86 | * @return int The filesize 87 | */ 88 | public int getFileSize() { 89 | return fsize; 90 | } 91 | 92 | /** 93 | * Initializes class and reads stream. Init does not close stream. 94 | * 95 | * @param in 96 | * InputStream to read from new array with size + inc 97 | * @throws IOException 98 | * In case of an I/O problem 99 | */ 100 | private void init(InputStream in) throws IOException { 101 | ByteArrayOutputStream output = new ByteArrayOutputStream(); 102 | byte[] buffer = new byte[1024 * 4]; 103 | int n; 104 | while ((n = in.read(buffer)) != -1) { 105 | output.write(buffer, 0, n); 106 | } 107 | file = output.toByteArray(); 108 | fsize = file.length; 109 | current = 0; 110 | } 111 | 112 | /** 113 | * Read 1 byte. 114 | * 115 | * @return One byte 116 | * @throws IOException 117 | * If EOF is reached 118 | */ 119 | private byte read() throws IOException { 120 | if (current >= fsize) { 121 | throw new EOFException("Reached EOF, file size=" + fsize); 122 | } 123 | return file[current++]; 124 | } 125 | 126 | /** 127 | * Read 1 signed byte. 128 | * 129 | * @return One byte 130 | * @throws IOException 131 | * If EOF is reached 132 | */ 133 | public byte readTTFByte() throws IOException { 134 | return read(); 135 | } 136 | 137 | /** 138 | * Read 4 bytes. 139 | * 140 | * @return One signed integer 141 | * @throws IOException 142 | * If EOF is reached 143 | */ 144 | public int readTTFLong() throws IOException { 145 | long ret = readTTFUByte(); // << 8; 146 | ret = (ret << 8) + readTTFUByte(); 147 | ret = (ret << 8) + readTTFUByte(); 148 | ret = (ret << 8) + readTTFUByte(); 149 | return (int) ret; 150 | } 151 | 152 | /** 153 | * Read an ISO-8859-1 string of len bytes. 154 | * 155 | * @param len 156 | * The length of the string to read 157 | * @return A String 158 | * @throws IOException 159 | * If EOF is reached 160 | */ 161 | public String readTTFString(int len) throws IOException { 162 | if ((len + current) > fsize) { 163 | throw new EOFException("Reached EOF, file size=" + fsize); 164 | } 165 | 166 | byte[] tmp = new byte[len]; 167 | System.arraycopy(file, current, tmp, 0, len); 168 | current += len; 169 | String encoding; 170 | if ((tmp.length > 0) && (tmp[0] == 0)) { 171 | encoding = "UTF-16BE"; 172 | } else { 173 | encoding = "ISO-8859-1"; 174 | } 175 | return new String(tmp, encoding); 176 | } 177 | 178 | /** 179 | * Read an ISO-8859-1 string of len bytes. 180 | * 181 | * @param len 182 | * The length of the string to read 183 | * @param encodingID 184 | * the string encoding id (presently ignored; always uses UTF-16BE) 185 | * @return A String 186 | * @throws IOException 187 | * If EOF is reached 188 | */ 189 | public String readTTFString(int len, int encodingID) throws IOException { 190 | if ((len + current) > fsize) { 191 | throw new EOFException("Reached EOF, file size=" + fsize); 192 | } 193 | 194 | byte[] tmp = new byte[len]; 195 | System.arraycopy(file, current, tmp, 0, len); 196 | current += len; 197 | String encoding; 198 | encoding = "UTF-16BE"; // Use this for all known encoding IDs for now 199 | return new String(tmp, encoding); 200 | } 201 | 202 | /** 203 | * Read 1 unsigned byte. 204 | * 205 | * @return One unsigned byte 206 | * @throws IOException 207 | * If EOF is reached 208 | */ 209 | public int readTTFUByte() throws IOException { 210 | byte buf = read(); 211 | 212 | if (buf < 0) { 213 | return 256 + buf; 214 | } else { 215 | return buf; 216 | } 217 | } 218 | 219 | /** 220 | * Read 4 bytes. 221 | * 222 | * @return One unsigned integer 223 | * @throws IOException 224 | * If EOF is reached 225 | */ 226 | public long readTTFULong() throws IOException { 227 | long ret = readTTFUByte(); 228 | ret = (ret << 8) + readTTFUByte(); 229 | ret = (ret << 8) + readTTFUByte(); 230 | ret = (ret << 8) + readTTFUByte(); 231 | 232 | return ret; 233 | } 234 | 235 | /** 236 | * Read 2 bytes unsigned. 237 | * 238 | * @return One unsigned short 239 | * @throws IOException 240 | * If EOF is reached 241 | */ 242 | public int readTTFUShort() throws IOException { 243 | return (readTTFUByte() << 8) + readTTFUByte(); 244 | } 245 | 246 | /** 247 | * Set current file position to offset 248 | * 249 | * @param offset 250 | * The new offset to set 251 | * @throws IOException 252 | * In case of an I/O problem 253 | */ 254 | public void seekSet(long offset) throws IOException { 255 | if (offset > fsize || offset < 0) { 256 | throw new EOFException("Reached EOF, file size=" + fsize + " offset=" + offset); 257 | } 258 | current = (int) offset; 259 | } 260 | 261 | /** 262 | * Skip a given number of bytes. 263 | * 264 | * @param add 265 | * The number of bytes to advance 266 | * @throws IOException 267 | * In case of an I/O problem 268 | */ 269 | public void skip(long add) throws IOException { 270 | seekSet(current + add); 271 | } 272 | 273 | } 274 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/src/main/java/com/jaredrummler/truetypeparser/TTFDirTabEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /* $Id: TTFDirTabEntry.java 1357883 2012-07-05 20:29:53Z gadams $ */ 19 | 20 | package com.jaredrummler.truetypeparser; 21 | 22 | import java.io.IOException; 23 | import java.io.UnsupportedEncodingException; 24 | 25 | /** 26 | * This class represents an entry to a TrueType font's Dir Tab. 27 | */ 28 | public class TTFDirTabEntry { 29 | 30 | private final byte[] tag = new byte[4]; 31 | private long offset; 32 | private long length; 33 | 34 | TTFDirTabEntry() { 35 | } 36 | 37 | public TTFDirTabEntry(long offset, long length) { 38 | this.offset = offset; 39 | this.length = length; 40 | } 41 | 42 | /** 43 | * Returns the length. 44 | * 45 | * @return long 46 | */ 47 | public long getLength() { 48 | return length; 49 | } 50 | 51 | /** 52 | * Returns the offset. 53 | * 54 | * @return long 55 | */ 56 | public long getOffset() { 57 | return offset; 58 | } 59 | 60 | /** 61 | * Returns the tag bytes. 62 | * 63 | * @return byte[] 64 | */ 65 | public byte[] getTag() { 66 | return tag; 67 | } 68 | 69 | /** 70 | * Returns the tag bytes. 71 | * 72 | * @return byte[] 73 | */ 74 | public String getTagString() { 75 | try { 76 | return new String(tag, "ISO-8859-1"); 77 | } catch (UnsupportedEncodingException e) { 78 | return toString(); // Should never happen. 79 | } 80 | } 81 | 82 | /** 83 | * Read Dir Tab. 84 | * 85 | * @param in 86 | * font file reader 87 | * @return tag name 88 | * @throws IOException 89 | * upon I/O exception 90 | */ 91 | public String read(FontFileReader in) throws IOException { 92 | tag[0] = in.readTTFByte(); 93 | tag[1] = in.readTTFByte(); 94 | tag[2] = in.readTTFByte(); 95 | tag[3] = in.readTTFByte(); 96 | in.skip(4); // Skip checksum 97 | offset = in.readTTFULong(); 98 | length = in.readTTFULong(); 99 | return new String(tag, "ISO-8859-1"); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/src/main/java/com/jaredrummler/truetypeparser/TTFFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /* $Id: TTFFile.java 1395925 2012-10-09 09:13:18Z jeremias $ */ 19 | 20 | package com.jaredrummler.truetypeparser; 21 | 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.util.HashMap; 27 | import java.util.HashSet; 28 | import java.util.Map; 29 | import java.util.Set; 30 | 31 | /** 32 | * Reads a TrueType file or a TrueType Collection. The TrueType spec can be found at the Microsoft. 33 | * Typography site: http://www.microsoft.com/truetype/ 34 | */ 35 | public class TTFFile { 36 | 37 | /** 38 | * Reads a TTF file 39 | * 40 | * @param file 41 | * The font file 42 | * @return The TrueType file 43 | * @throws IOException 44 | * if an IO error occurs 45 | */ 46 | public static TTFFile open(File file) throws IOException { 47 | return open(new FileInputStream(file)); 48 | } 49 | 50 | /** 51 | * Reads a TTF file from an InputStream 52 | * 53 | * @param is 54 | * InputStream to read from 55 | * @return The TrueType file 56 | * @throws IOException 57 | * if an IO error occurs 58 | */ 59 | public static TTFFile open(InputStream is) throws IOException { 60 | TTFFile ttfFile = new TTFFile(); 61 | ttfFile.readFont(new FontFileReader(is)); 62 | return ttfFile; 63 | } 64 | 65 | private final Set familyNames = new HashSet<>(); 66 | /** The FontFileReader used to read this TrueType font. */ 67 | private FontFileReader fontFile; 68 | /** Table directory */ 69 | private Map dirTabs; 70 | private String postScriptName = ""; 71 | private String fullName = ""; 72 | private String notice = ""; 73 | private String subFamilyName = ""; 74 | private int weightClass; 75 | 76 | TTFFile() { 77 | 78 | } 79 | 80 | /** 81 | * Returns the font family names of the font. 82 | * 83 | * @return Set The family names (a Set of Strings) 84 | */ 85 | public Set getFamilyNames() { 86 | return familyNames; 87 | } 88 | 89 | /** 90 | * Returns the full name of the font. 91 | * 92 | * @return String The full name 93 | */ 94 | public String getFullName() { 95 | return fullName; 96 | } 97 | 98 | public String getNotice() { 99 | return notice; 100 | } 101 | 102 | /** 103 | * Returns the PostScript name of the font. 104 | * 105 | * @return String The PostScript name 106 | */ 107 | public String getPostScriptName() { 108 | return postScriptName; 109 | } 110 | 111 | /** 112 | * Returns the font sub family name of the font. 113 | * 114 | * @return String The sub family name 115 | */ 116 | public String getSubFamilyName() { 117 | return subFamilyName; 118 | } 119 | 120 | /** 121 | * Returns the weight class of this font. Valid values are 100, 200....,800, 900. 122 | * 123 | * @return the weight class value (or 0 if there was no OS/2 table in the font) 124 | */ 125 | public int getWeightClass() { 126 | return weightClass; 127 | } 128 | 129 | /** 130 | * Read Table Directory from the current position in the FontFileReader and fill the global 131 | * HashMap dirTabs with the table name (String) as key and a TTFDirTabEntry as value. 132 | * 133 | * @throws IOException 134 | * in case of an I/O problem 135 | */ 136 | private void readDirTabs() throws IOException { 137 | fontFile.readTTFLong(); // TTF_FIXED_SIZE (4 bytes) 138 | int ntabs = fontFile.readTTFUShort(); 139 | fontFile.skip(6); // 3xTTF_USHORT_SIZE 140 | 141 | dirTabs = new HashMap<>(); 142 | TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs]; 143 | 144 | for (int i = 0; i < ntabs; i++) { 145 | pd[i] = new TTFDirTabEntry(); 146 | String tableName = pd[i].read(fontFile); 147 | dirTabs.put(TTFTableName.getValue(tableName), pd[i]); 148 | } 149 | dirTabs.put(TTFTableName.TABLE_DIRECTORY, new TTFDirTabEntry(0L, fontFile.getCurrentPos())); 150 | } 151 | 152 | /** 153 | * Reads the font using a FontFileReader. 154 | * 155 | * @param in 156 | * The FontFileReader to use 157 | * @throws IOException 158 | * In case of an I/O problem 159 | */ 160 | void readFont(FontFileReader in) throws IOException { 161 | fontFile = in; 162 | readDirTabs(); 163 | 164 | TTFDirTabEntry os2Entry = dirTabs.get(TTFTableName.OS2); 165 | if (os2Entry != null) { 166 | seekTab(fontFile, TTFTableName.OS2, 0); 167 | fontFile.readTTFUShort(); 168 | fontFile.skip(2); //xAvgCharWidth 169 | weightClass = fontFile.readTTFUShort(); 170 | } 171 | 172 | readName(); 173 | } 174 | 175 | /** 176 | * Read the "name" table. 177 | * 178 | * @throws IOException 179 | * In case of a I/O problem 180 | */ 181 | private void readName() throws IOException { 182 | seekTab(fontFile, TTFTableName.NAME, 2); 183 | int i = fontFile.getCurrentPos(); 184 | int n = fontFile.readTTFUShort(); 185 | int j = fontFile.readTTFUShort() + i - 2; 186 | i += 2 * 2; 187 | 188 | while (n-- > 0) { 189 | fontFile.seekSet(i); 190 | int platformID = fontFile.readTTFUShort(); 191 | int encodingID = fontFile.readTTFUShort(); 192 | int languageID = fontFile.readTTFUShort(); 193 | 194 | int k = fontFile.readTTFUShort(); 195 | int l = fontFile.readTTFUShort(); 196 | 197 | if (((platformID == 1 || platformID == 3) && (encodingID == 0 || encodingID == 1))) { 198 | fontFile.seekSet(j + fontFile.readTTFUShort()); 199 | String txt; 200 | if (platformID == 3) { 201 | txt = fontFile.readTTFString(l, encodingID); 202 | } else { 203 | txt = fontFile.readTTFString(l); 204 | } 205 | switch (k) { 206 | case 0: 207 | if (notice.length() == 0) { 208 | notice = txt; 209 | } 210 | break; 211 | case 1: // Font Family Name 212 | case 16: // Preferred Family 213 | familyNames.add(txt); 214 | break; 215 | case 2: 216 | if (subFamilyName.length() == 0) { 217 | subFamilyName = txt; 218 | } 219 | break; 220 | case 4: 221 | if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) { 222 | fullName = txt; 223 | } 224 | break; 225 | case 6: 226 | if (postScriptName.length() == 0) { 227 | postScriptName = txt; 228 | } 229 | break; 230 | default: 231 | break; 232 | } 233 | } 234 | i += 6 * 2; 235 | } 236 | } 237 | 238 | /** 239 | * Position inputstream to position indicated in the dirtab offset + offset 240 | * 241 | * @param in 242 | * font file reader 243 | * @param tableName 244 | * (tag) of table 245 | * @param offset 246 | * from start of table 247 | * @return true if seek succeeded 248 | * @throws IOException 249 | * if I/O exception occurs during seek 250 | */ 251 | private boolean seekTab(FontFileReader in, TTFTableName tableName, long offset) 252 | throws IOException { 253 | TTFDirTabEntry dt = dirTabs.get(tableName); 254 | if (dt == null) { 255 | return false; 256 | } else { 257 | in.seekSet(dt.getOffset() + offset); 258 | } 259 | return true; 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /lib-truetypeparser-light/src/main/java/com/jaredrummler/truetypeparser/TTFTableName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | /* $Id: TTFTableName.java 1357883 2012-07-05 20:29:53Z gadams $ */ 19 | 20 | package com.jaredrummler.truetypeparser; 21 | 22 | /** 23 | * Represents table names as found in a TrueType font's Table Directory. TrueType fonts may have 24 | * custom tables so we cannot use an enum. 25 | */ 26 | public final class TTFTableName { 27 | 28 | /** The first table in a TrueType font file containing metadata about other tables. */ 29 | public static final TTFTableName TABLE_DIRECTORY = new TTFTableName("tableDirectory"); 30 | 31 | /** Naming table. */ 32 | public static final TTFTableName NAME = new TTFTableName("name"); 33 | 34 | /** OS/2 and Windows specific metrics. */ 35 | public static final TTFTableName OS2 = new TTFTableName("OS/2"); 36 | 37 | private final String name; 38 | 39 | private TTFTableName(String name) { 40 | this.name = name; 41 | } 42 | 43 | /** 44 | * Returns an instance of this class corresponding to the given string representation. 45 | * 46 | * @param tableName 47 | * table name as in the Table Directory 48 | * @return TTFTableName 49 | */ 50 | public static TTFTableName getValue(String tableName) { 51 | if (tableName != null) { 52 | return new TTFTableName(tableName); 53 | } 54 | throw new IllegalArgumentException("A TrueType font table name must not be null"); 55 | } 56 | 57 | @Override public boolean equals(Object o) { 58 | if (o == this) { 59 | return true; 60 | } 61 | if (!(o instanceof TTFTableName)) { 62 | return false; 63 | } 64 | TTFTableName to = (TTFTableName) o; 65 | return name.equals(to.getName()); 66 | } 67 | 68 | @Override public int hashCode() { 69 | return name.hashCode(); 70 | } 71 | 72 | @Override public String toString() { 73 | return name; 74 | } 75 | 76 | /** 77 | * Returns the name of the table as it should be in the Directory Table. 78 | */ 79 | public String getName() { 80 | return name; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /lib-truetypeparser/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /lib-truetypeparser/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 7 9 | targetSdkVersion 24 10 | } 11 | 12 | lintOptions { 13 | abortOnError false 14 | } 15 | } 16 | 17 | apply from: '../gradle-mvn-push.gradle' 18 | 19 | afterEvaluate { 20 | androidJavadocs.classpath += project.android.libraryVariants.toList().first().javaCompile.classpath 21 | } 22 | -------------------------------------------------------------------------------- /lib-truetypeparser/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/bidi/BidiConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.bidi; 19 | 20 | /** 21 | *

Constants used for bidirectional processing.

22 | * 23 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

24 | */ 25 | public interface BidiConstants { 26 | 27 | /** first external (official) category */ 28 | int FIRST = 1; 29 | 30 | // strong category 31 | 32 | /** left-to-right class */ 33 | int L = 1; 34 | 35 | /** left-to-right embedding class */ 36 | int LRE = 2; 37 | 38 | /** left-to-right override class */ 39 | int LRO = 3; 40 | 41 | /** right-to-left class */ 42 | int R = 4; 43 | 44 | /** right-to-left arabic class */ 45 | int AL = 5; 46 | 47 | /** right-to-left embedding class */ 48 | int RLE = 6; 49 | 50 | /** right-to-left override class */ 51 | int RLO = 7; 52 | 53 | // weak category 54 | 55 | /** pop directional formatting class */ 56 | int PDF = 8; 57 | 58 | /** european number class */ 59 | int EN = 9; 60 | 61 | /** european number separator class */ 62 | int ES = 10; 63 | 64 | /** european number terminator class */ 65 | int ET = 11; 66 | 67 | /** arabic number class */ 68 | int AN = 12; 69 | 70 | /** common number separator class */ 71 | int CS = 13; 72 | 73 | /** non-spacing mark class */ 74 | int NSM = 14; 75 | 76 | /** boundary neutral class */ 77 | int BN = 15; 78 | 79 | // neutral category 80 | 81 | /** paragraph separator class */ 82 | int B = 16; 83 | 84 | /** segment separator class */ 85 | int S = 17; 86 | 87 | /** whitespace class */ 88 | int WS = 18; 89 | 90 | /** other neutrals class */ 91 | int ON = 19; 92 | 93 | /** last external (official) category */ 94 | int LAST = 19; 95 | 96 | // implementation specific categories 97 | 98 | /** placeholder for low surrogate */ 99 | int SURROGATE = 20; 100 | 101 | // other constants 102 | 103 | /** 104 | * last 105 | * /** maximum bidirectional levels 106 | */ 107 | int MAX_LEVELS = 61; 108 | 109 | /** override flag */ 110 | int OVERRIDE = 128; 111 | } 112 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/AdvancedTypographicTableFormatException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

Exception thrown when attempting to decode a truetype font file and a format 22 | * constraint is violated.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public class AdvancedTypographicTableFormatException extends RuntimeException { 27 | 28 | /** 29 | * Instantiate ATT format exception. 30 | */ 31 | public AdvancedTypographicTableFormatException() { 32 | super(); 33 | } 34 | 35 | /** 36 | * Instantiate ATT format exception. 37 | * 38 | * @param message 39 | * a message string 40 | */ 41 | public AdvancedTypographicTableFormatException(String message) { 42 | super(message); 43 | } 44 | 45 | /** 46 | * Instantiate ATT format exception. 47 | * 48 | * @param message 49 | * a message string 50 | * @param cause 51 | * a Throwable that caused this exception 52 | */ 53 | public AdvancedTypographicTableFormatException(String message, Throwable cause) { 54 | super(message, cause); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphClassMapping.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

The GlyphClassMapping interface provides glyph identifier to class 22 | * index mapping support.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public interface GlyphClassMapping { 27 | 28 | /** 29 | * Obtain size of class table, i.e., ciMax + 1, where ciMax is the maximum 30 | * class index. 31 | * 32 | * @param set 33 | * for coverage set based class mappings, indicates set index, otherwise ignored 34 | * @return size of class table 35 | */ 36 | int getClassSize(int set); 37 | 38 | /** 39 | * Map glyph identifier (code) to coverge index. Returns -1 if glyph identifier is not in the domain of 40 | * the class table. 41 | * 42 | * @param gid 43 | * glyph identifier (code) 44 | * @param set 45 | * for coverage set based class mappings, indicates set index, otherwise ignored 46 | * @return non-negative glyph class index or -1 if glyph identifiers is not mapped by table 47 | */ 48 | int getClassIndex(int gid, int set); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphClassTable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import java.util.Iterator; 21 | import java.util.List; 22 | 23 | /** 24 | *

Base class implementation of glyph class table.

25 | * 26 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

27 | */ 28 | public final class GlyphClassTable extends GlyphMappingTable implements GlyphClassMapping { 29 | 30 | /** empty mapping table */ 31 | public static final int GLYPH_CLASS_TYPE_EMPTY = GLYPH_MAPPING_TYPE_EMPTY; 32 | 33 | /** mapped mapping table */ 34 | public static final int GLYPH_CLASS_TYPE_MAPPED = GLYPH_MAPPING_TYPE_MAPPED; 35 | 36 | /** range based mapping table */ 37 | public static final int GLYPH_CLASS_TYPE_RANGE = GLYPH_MAPPING_TYPE_RANGE; 38 | 39 | /** empty mapping table */ 40 | public static final int GLYPH_CLASS_TYPE_COVERAGE_SET = 3; 41 | 42 | private GlyphClassMapping cm; 43 | 44 | private GlyphClassTable(GlyphClassMapping cm) { 45 | assert cm != null; 46 | assert cm instanceof GlyphMappingTable; 47 | this.cm = cm; 48 | } 49 | 50 | /** {@inheritDoc} */ 51 | public int getType() { 52 | return ((GlyphMappingTable) cm).getType(); 53 | } 54 | 55 | /** {@inheritDoc} */ 56 | public List getEntries() { 57 | return ((GlyphMappingTable) cm).getEntries(); 58 | } 59 | 60 | /** {@inheritDoc} */ 61 | public int getClassSize(int set) { 62 | return cm.getClassSize(set); 63 | } 64 | 65 | /** {@inheritDoc} */ 66 | public int getClassIndex(int gid, int set) { 67 | return cm.getClassIndex(gid, set); 68 | } 69 | 70 | /** 71 | * Create glyph class table. 72 | * 73 | * @param entries 74 | * list of mapped or ranged class entries, or null or empty list 75 | * @return a new covera table instance 76 | */ 77 | public static GlyphClassTable createClassTable(List entries) { 78 | GlyphClassMapping cm; 79 | if ((entries == null) || (entries.size() == 0)) { 80 | cm = new EmptyClassTable(entries); 81 | } else if (isMappedClass(entries)) { 82 | cm = new MappedClassTable(entries); 83 | } else if (isRangeClass(entries)) { 84 | cm = new RangeClassTable(entries); 85 | } else if (isCoverageSetClass(entries)) { 86 | cm = new CoverageSetClassTable(entries); 87 | } else { 88 | cm = null; 89 | } 90 | assert cm != null : "unknown class type"; 91 | return new GlyphClassTable(cm); 92 | } 93 | 94 | private static boolean isMappedClass(List entries) { 95 | if ((entries == null) || (entries.size() == 0)) { 96 | return false; 97 | } else { 98 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 99 | Object o = it.next(); 100 | if (!(o instanceof Integer)) { 101 | return false; 102 | } 103 | } 104 | return true; 105 | } 106 | } 107 | 108 | private static boolean isRangeClass(List entries) { 109 | if ((entries == null) || (entries.size() == 0)) { 110 | return false; 111 | } else { 112 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 113 | Object o = it.next(); 114 | if (!(o instanceof MappingRange)) { 115 | return false; 116 | } 117 | } 118 | return true; 119 | } 120 | } 121 | 122 | private static boolean isCoverageSetClass(List entries) { 123 | if ((entries == null) || (entries.size() == 0)) { 124 | return false; 125 | } else { 126 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 127 | Object o = it.next(); 128 | if (!(o instanceof GlyphCoverageTable)) { 129 | return false; 130 | } 131 | } 132 | return true; 133 | } 134 | } 135 | 136 | private static class EmptyClassTable extends GlyphMappingTable.EmptyMappingTable implements GlyphClassMapping { 137 | 138 | public EmptyClassTable(List entries) { 139 | super(entries); 140 | } 141 | 142 | /** {@inheritDoc} */ 143 | public int getClassSize(int set) { 144 | return 0; 145 | } 146 | 147 | /** {@inheritDoc} */ 148 | public int getClassIndex(int gid, int set) { 149 | return -1; 150 | } 151 | } 152 | 153 | private static class MappedClassTable extends GlyphMappingTable.MappedMappingTable implements GlyphClassMapping { 154 | 155 | private int firstGlyph; 156 | private int[] gca; 157 | private int gcMax = -1; 158 | 159 | public MappedClassTable(List entries) { 160 | populate(entries); 161 | } 162 | 163 | /** {@inheritDoc} */ 164 | public List getEntries() { 165 | List entries = new java.util.ArrayList(); 166 | entries.add(Integer.valueOf(firstGlyph)); 167 | if (gca != null) { 168 | for (int i = 0, n = gca.length; i < n; i++) { 169 | entries.add(Integer.valueOf(gca[i])); 170 | } 171 | } 172 | return entries; 173 | } 174 | 175 | /** {@inheritDoc} */ 176 | public int getMappingSize() { 177 | return gcMax + 1; 178 | } 179 | 180 | /** {@inheritDoc} */ 181 | public int getMappedIndex(int gid) { 182 | int i = gid - firstGlyph; 183 | if ((i >= 0) && (i < gca.length)) { 184 | return gca[i]; 185 | } else { 186 | return -1; 187 | } 188 | } 189 | 190 | /** {@inheritDoc} */ 191 | public int getClassSize(int set) { 192 | return getMappingSize(); 193 | } 194 | 195 | /** {@inheritDoc} */ 196 | public int getClassIndex(int gid, int set) { 197 | return getMappedIndex(gid); 198 | } 199 | 200 | private void populate(List entries) { 201 | // obtain entries iterator 202 | Iterator it = entries.iterator(); 203 | // extract first glyph 204 | int firstGlyph = 0; 205 | if (it.hasNext()) { 206 | Object o = it.next(); 207 | if (o instanceof Integer) { 208 | firstGlyph = ((Integer) o).intValue(); 209 | } else { 210 | throw new AdvancedTypographicTableFormatException( 211 | "illegal entry, first entry must be Integer denoting first glyph value, but is: " + o); 212 | } 213 | } 214 | // extract glyph class array 215 | int i = 0; 216 | int n = entries.size() - 1; 217 | int gcMax = -1; 218 | int[] gca = new int[n]; 219 | while (it.hasNext()) { 220 | Object o = it.next(); 221 | if (o instanceof Integer) { 222 | int gc = ((Integer) o).intValue(); 223 | gca[i++] = gc; 224 | if (gc > gcMax) { 225 | gcMax = gc; 226 | } 227 | } else { 228 | throw new AdvancedTypographicTableFormatException("illegal mapping entry, must be Integer: " + o); 229 | } 230 | } 231 | assert i == n; 232 | assert this.gca == null; 233 | this.firstGlyph = firstGlyph; 234 | this.gca = gca; 235 | this.gcMax = gcMax; 236 | } 237 | 238 | /** {@inheritDoc} */ 239 | public String toString() { 240 | StringBuffer sb = new StringBuffer(); 241 | sb.append("{ firstGlyph = " + firstGlyph + ", classes = {"); 242 | for (int i = 0, n = gca.length; i < n; i++) { 243 | if (i > 0) { 244 | sb.append(','); 245 | } 246 | sb.append(Integer.toString(gca[i])); 247 | } 248 | sb.append("} }"); 249 | return sb.toString(); 250 | } 251 | } 252 | 253 | private static class RangeClassTable extends GlyphMappingTable.RangeMappingTable implements GlyphClassMapping { 254 | 255 | public RangeClassTable(List entries) { 256 | super(entries); 257 | } 258 | 259 | /** {@inheritDoc} */ 260 | public int getMappedIndex(int gid, int s, int m) { 261 | return m; 262 | } 263 | 264 | /** {@inheritDoc} */ 265 | public int getClassSize(int set) { 266 | return getMappingSize(); 267 | } 268 | 269 | /** {@inheritDoc} */ 270 | public int getClassIndex(int gid, int set) { 271 | return getMappedIndex(gid); 272 | } 273 | } 274 | 275 | private static class CoverageSetClassTable extends GlyphMappingTable.EmptyMappingTable implements GlyphClassMapping { 276 | 277 | public CoverageSetClassTable(List entries) { 278 | throw new UnsupportedOperationException("coverage set class table not yet supported"); 279 | } 280 | 281 | /** {@inheritDoc} */ 282 | public int getType() { 283 | return GLYPH_CLASS_TYPE_COVERAGE_SET; 284 | } 285 | 286 | /** {@inheritDoc} */ 287 | public int getClassSize(int set) { 288 | return 0; 289 | } 290 | 291 | /** {@inheritDoc} */ 292 | public int getClassIndex(int gid, int set) { 293 | return -1; 294 | } 295 | } 296 | 297 | } 298 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphContextTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import com.jaredrummler.fontreader.util.GlyphSequence; 21 | 22 | /** 23 | *

Interface for testing the originating (source) character context of a glyph sequence.

24 | * 25 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

26 | */ 27 | public interface GlyphContextTester { 28 | 29 | /** 30 | * Perform a test on a glyph sequence in a specific (originating) character context. 31 | * 32 | * @param script 33 | * governing script 34 | * @param language 35 | * governing language 36 | * @param feature 37 | * governing feature 38 | * @param gs 39 | * glyph sequence to test 40 | * @param index 41 | * index into glyph sequence to test 42 | * @param flags 43 | * that apply to lookup in scope 44 | * @return true if test is satisfied 45 | */ 46 | boolean test(String script, String language, String feature, GlyphSequence gs, int index, int flags); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphCoverageMapping.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

The GlyphCoverageMapping interface provides glyph identifier to coverage 22 | * index mapping support.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public interface GlyphCoverageMapping { 27 | 28 | /** 29 | * Obtain size of coverage table, i.e., ciMax + 1, where ciMax is the maximum 30 | * coverage index. 31 | * 32 | * @return size of coverage table 33 | */ 34 | int getCoverageSize(); 35 | 36 | /** 37 | * Map glyph identifier (code) to coverge index. Returns -1 if glyph identifier is not in the domain of 38 | * the coverage table. 39 | * 40 | * @param gid 41 | * glyph identifier (code) 42 | * @return non-negative glyph coverage index or -1 if glyph identifiers is not mapped by table 43 | */ 44 | int getCoverageIndex(int gid); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphCoverageTable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import java.util.Arrays; 21 | import java.util.Iterator; 22 | import java.util.List; 23 | 24 | /** 25 | *

.Base class implementation of glyph coverage table.

26 | * 27 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

28 | */ 29 | public final class GlyphCoverageTable extends GlyphMappingTable implements GlyphCoverageMapping { 30 | 31 | /** empty mapping table */ 32 | public static final int GLYPH_COVERAGE_TYPE_EMPTY = GLYPH_MAPPING_TYPE_EMPTY; 33 | 34 | /** mapped mapping table */ 35 | public static final int GLYPH_COVERAGE_TYPE_MAPPED = GLYPH_MAPPING_TYPE_MAPPED; 36 | 37 | /** range based mapping table */ 38 | public static final int GLYPH_COVERAGE_TYPE_RANGE = GLYPH_MAPPING_TYPE_RANGE; 39 | 40 | private GlyphCoverageMapping cm; 41 | 42 | private GlyphCoverageTable(GlyphCoverageMapping cm) { 43 | this.cm = cm; 44 | } 45 | 46 | /** {@inheritDoc} */ 47 | public int getType() { 48 | return ((GlyphMappingTable) cm).getType(); 49 | } 50 | 51 | /** {@inheritDoc} */ 52 | public List getEntries() { 53 | return ((GlyphMappingTable) cm).getEntries(); 54 | } 55 | 56 | /** {@inheritDoc} */ 57 | public int getCoverageSize() { 58 | return cm.getCoverageSize(); 59 | } 60 | 61 | /** {@inheritDoc} */ 62 | public int getCoverageIndex(int gid) { 63 | return cm.getCoverageIndex(gid); 64 | } 65 | 66 | /** 67 | * Create glyph coverage table. 68 | * 69 | * @param entries 70 | * list of mapped or ranged coverage entries, or null or empty list 71 | * @return a new covera table instance 72 | */ 73 | public static GlyphCoverageTable createCoverageTable(List entries) { 74 | GlyphCoverageMapping cm; 75 | if ((entries == null) || (entries.size() == 0)) { 76 | cm = new EmptyCoverageTable(entries); 77 | } else if (isMappedCoverage(entries)) { 78 | cm = new MappedCoverageTable(entries); 79 | } else if (isRangeCoverage(entries)) { 80 | cm = new RangeCoverageTable(entries); 81 | } else { 82 | cm = null; 83 | } 84 | assert cm != null : "unknown coverage type"; 85 | return new GlyphCoverageTable(cm); 86 | } 87 | 88 | private static boolean isMappedCoverage(List entries) { 89 | if ((entries == null) || (entries.size() == 0)) { 90 | return false; 91 | } else { 92 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 93 | Object o = it.next(); 94 | if (!(o instanceof Integer)) { 95 | return false; 96 | } 97 | } 98 | return true; 99 | } 100 | } 101 | 102 | private static boolean isRangeCoverage(List entries) { 103 | if ((entries == null) || (entries.size() == 0)) { 104 | return false; 105 | } else { 106 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 107 | Object o = it.next(); 108 | if (!(o instanceof MappingRange)) { 109 | return false; 110 | } 111 | } 112 | return true; 113 | } 114 | } 115 | 116 | private static class EmptyCoverageTable extends GlyphMappingTable.EmptyMappingTable implements GlyphCoverageMapping { 117 | 118 | public EmptyCoverageTable(List entries) { 119 | super(entries); 120 | } 121 | 122 | /** {@inheritDoc} */ 123 | public int getCoverageSize() { 124 | return 0; 125 | } 126 | 127 | /** {@inheritDoc} */ 128 | public int getCoverageIndex(int gid) { 129 | return -1; 130 | } 131 | } 132 | 133 | private static class MappedCoverageTable extends GlyphMappingTable.MappedMappingTable 134 | implements GlyphCoverageMapping { 135 | 136 | private int[] map; 137 | 138 | public MappedCoverageTable(List entries) { 139 | populate(entries); 140 | } 141 | 142 | /** {@inheritDoc} */ 143 | public List getEntries() { 144 | List entries = new java.util.ArrayList(); 145 | if (map != null) { 146 | for (int i = 0, n = map.length; i < n; i++) { 147 | entries.add(Integer.valueOf(map[i])); 148 | } 149 | } 150 | return entries; 151 | } 152 | 153 | /** {@inheritDoc} */ 154 | public int getMappingSize() { 155 | return (map != null) ? map.length : 0; 156 | } 157 | 158 | public int getMappedIndex(int gid) { 159 | int i; 160 | if ((i = Arrays.binarySearch(map, gid)) >= 0) { 161 | return i; 162 | } else { 163 | return -1; 164 | } 165 | } 166 | 167 | /** {@inheritDoc} */ 168 | public int getCoverageSize() { 169 | return getMappingSize(); 170 | } 171 | 172 | /** {@inheritDoc} */ 173 | public int getCoverageIndex(int gid) { 174 | return getMappedIndex(gid); 175 | } 176 | 177 | private void populate(List entries) { 178 | int i = 0; 179 | int skipped = 0; 180 | int n = entries.size(); 181 | int gidMax = -1; 182 | int[] map = new int[n]; 183 | for (Iterator it = entries.iterator(); it.hasNext(); ) { 184 | Object o = it.next(); 185 | if (o instanceof Integer) { 186 | int gid = ((Integer) o).intValue(); 187 | if ((gid >= 0) && (gid < 65536)) { 188 | if (gid > gidMax) { 189 | map[i++] = gidMax = gid; 190 | } else { 191 | skipped++; 192 | } 193 | } else { 194 | throw new AdvancedTypographicTableFormatException("illegal glyph index: " + gid); 195 | } 196 | } else { 197 | throw new AdvancedTypographicTableFormatException("illegal coverage entry, must be Integer: " + o); 198 | } 199 | } 200 | assert (i + skipped) == n; 201 | assert this.map == null; 202 | this.map = map; 203 | } 204 | 205 | /** {@inheritDoc} */ 206 | public String toString() { 207 | StringBuffer sb = new StringBuffer(); 208 | sb.append('{'); 209 | for (int i = 0, n = map.length; i < n; i++) { 210 | if (i > 0) { 211 | sb.append(','); 212 | } 213 | sb.append(Integer.toString(map[i])); 214 | } 215 | sb.append('}'); 216 | return sb.toString(); 217 | } 218 | } 219 | 220 | private static class RangeCoverageTable extends GlyphMappingTable.RangeMappingTable implements GlyphCoverageMapping { 221 | 222 | public RangeCoverageTable(List entries) { 223 | super(entries); 224 | } 225 | 226 | /** {@inheritDoc} */ 227 | public int getMappedIndex(int gid, int s, int m) { 228 | return m + gid - s; 229 | } 230 | 231 | /** {@inheritDoc} */ 232 | public int getCoverageSize() { 233 | return getMappingSize(); 234 | } 235 | 236 | /** {@inheritDoc} */ 237 | public int getCoverageIndex(int gid) { 238 | return getMappedIndex(gid); 239 | } 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

The GlyphDefinition interface is a marker interface implemented by a glyph definition 22 | * subtable.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public interface GlyphDefinition { 27 | 28 | /** 29 | * Determine if some definition is available for a specific glyph. 30 | * 31 | * @param gi 32 | * a glyph index 33 | * @return true if some (unspecified) definition is available for the specified glyph 34 | */ 35 | boolean hasDefinition(int gi); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphDefinitionSubtable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import com.jaredrummler.fontreader.fonts.GlyphSubtable; 21 | import com.jaredrummler.fontreader.truetype.GlyphTable; 22 | 23 | /** 24 | *

The GlyphDefinitionSubtable implements an abstract base of a glyph definition subtable, 25 | * providing a default implementation of the GlyphDefinition interface.

26 | * 27 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

28 | */ 29 | public abstract class GlyphDefinitionSubtable extends GlyphSubtable implements GlyphDefinition { 30 | 31 | /** 32 | * Instantiate a GlyphDefinitionSubtable. 33 | * 34 | * @param id 35 | * subtable identifier 36 | * @param sequence 37 | * subtable sequence 38 | * @param flags 39 | * subtable flags 40 | * @param format 41 | * subtable format 42 | * @param mapping 43 | * subtable coverage table 44 | */ 45 | protected GlyphDefinitionSubtable(String id, int sequence, int flags, int format, GlyphMappingTable mapping) { 46 | super(id, sequence, flags, format, mapping); 47 | } 48 | 49 | /** {@inheritDoc} */ 50 | public int getTableType() { 51 | return GlyphTable.GLYPH_TABLE_TYPE_DEFINITION; 52 | } 53 | 54 | /** {@inheritDoc} */ 55 | public String getTypeName() { 56 | return GlyphDefinitionTable.getLookupTypeName(getType()); 57 | } 58 | 59 | /** {@inheritDoc} */ 60 | public boolean usesReverseScan() { 61 | return false; 62 | } 63 | 64 | /** {@inheritDoc} */ 65 | public boolean hasDefinition(int gi) { 66 | GlyphCoverageMapping cvm; 67 | if ((cvm = getCoverage()) != null) { 68 | if (cvm.getCoverageIndex(gi) >= 0) { 69 | return true; 70 | } 71 | } 72 | GlyphClassMapping clm; 73 | if ((clm = getClasses()) != null) { 74 | if (clm.getClassIndex(gi, 0) >= 0) { 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphPositioning.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

The GlyphPositioning interface is implemented by a glyph positioning subtable 22 | * that supports the determination of glyph positioning information based on script and 23 | * language of the corresponding character content.

24 | * 25 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

26 | */ 27 | public interface GlyphPositioning { 28 | 29 | /** 30 | * Perform glyph positioning at the current index, mutating the positioning state object as required. 31 | * Only the context associated with the current index is processed. 32 | * 33 | * @param ps 34 | * glyph positioning state object 35 | * @return true if the glyph subtable applies, meaning that the current context matches the 36 | * associated input context glyph coverage table; note that returning true does not mean any position 37 | * adjustment occurred; it only means that no further glyph subtables for the current lookup table 38 | * should be applied. 39 | */ 40 | boolean position(GlyphPositioningState ps); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphPositioningState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import com.jaredrummler.fontreader.util.GlyphSequence; 21 | import com.jaredrummler.fontreader.truetype.GlyphTable; 22 | import com.jaredrummler.fontreader.util.ScriptContextTester; 23 | 24 | /** 25 | *

The GlyphPositioningState implements an state object used during glyph positioning 26 | * processing.

27 | * 28 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

29 | */ 30 | public class GlyphPositioningState extends GlyphProcessingState { 31 | 32 | /** font size */ 33 | private int fontSize; 34 | /** default advancements */ 35 | private int[] widths; 36 | /** current adjustments */ 37 | private int[][] adjustments; 38 | /** if true, then some adjustment was applied */ 39 | private boolean adjusted; 40 | 41 | /** 42 | * Construct default (reset) glyph positioning state. 43 | */ 44 | public GlyphPositioningState() { 45 | } 46 | 47 | /** 48 | * Construct glyph positioning state. 49 | * 50 | * @param gs 51 | * input glyph sequence 52 | * @param script 53 | * script identifier 54 | * @param language 55 | * language identifier 56 | * @param feature 57 | * feature identifier 58 | * @param fontSize 59 | * font size (in micropoints) 60 | * @param widths 61 | * array of design advancements (in glyph index order) 62 | * @param adjustments 63 | * positioning adjustments to which positioning is applied 64 | * @param sct 65 | * script context tester (or null) 66 | */ 67 | public GlyphPositioningState(GlyphSequence gs, String script, String language, String feature, int fontSize, 68 | int[] widths, int[][] adjustments, ScriptContextTester sct) { 69 | super(gs, script, language, feature, sct); 70 | this.fontSize = fontSize; 71 | this.widths = widths; 72 | this.adjustments = adjustments; 73 | } 74 | 75 | /** 76 | * Construct glyph positioning state using an existing state object using shallow copy 77 | * except as follows: input glyph sequence is copied deep except for its characters array. 78 | * 79 | * @param ps 80 | * existing positioning state to copy from 81 | */ 82 | public GlyphPositioningState(GlyphPositioningState ps) { 83 | super(ps); 84 | this.fontSize = ps.fontSize; 85 | this.widths = ps.widths; 86 | this.adjustments = ps.adjustments; 87 | } 88 | 89 | /** 90 | * Reset glyph positioning state. 91 | * 92 | * @param gs 93 | * input glyph sequence 94 | * @param script 95 | * script identifier 96 | * @param language 97 | * language identifier 98 | * @param feature 99 | * feature identifier 100 | * @param fontSize 101 | * font size (in micropoints) 102 | * @param widths 103 | * array of design advancements (in glyph index order) 104 | * @param adjustments 105 | * positioning adjustments to which positioning is applied 106 | * @param sct 107 | * script context tester (or null) 108 | */ 109 | public GlyphPositioningState reset(GlyphSequence gs, String script, String language, String feature, int fontSize, 110 | int[] widths, int[][] adjustments, ScriptContextTester sct) { 111 | super.reset(gs, script, language, feature, sct); 112 | this.fontSize = fontSize; 113 | this.widths = widths; 114 | this.adjustments = adjustments; 115 | this.adjusted = false; 116 | return this; 117 | } 118 | 119 | /** 120 | * Obtain design advancement (width) of glyph at specified index. 121 | * 122 | * @param gi 123 | * glyph index 124 | * @return design advancement, or zero if glyph index is not present 125 | */ 126 | public int getWidth(int gi) { 127 | if ((widths != null) && (gi < widths.length)) { 128 | return widths[gi]; 129 | } else { 130 | return 0; 131 | } 132 | } 133 | 134 | /** 135 | * Perform adjustments at current position index. 136 | * 137 | * @param v 138 | * value containing adjustments 139 | * @return true if a non-zero adjustment was made 140 | */ 141 | public boolean adjust(GlyphPositioningTable.Value v) { 142 | return adjust(v, 0); 143 | } 144 | 145 | /** 146 | * Perform adjustments at specified offset from current position index. 147 | * 148 | * @param v 149 | * value containing adjustments 150 | * @param offset 151 | * from current position index 152 | * @return true if a non-zero adjustment was made 153 | */ 154 | public boolean adjust(GlyphPositioningTable.Value v, int offset) { 155 | assert v != null; 156 | if ((index + offset) < indexLast) { 157 | return v.adjust(adjustments[index + offset], fontSize); 158 | } else { 159 | throw new IndexOutOfBoundsException(); 160 | } 161 | } 162 | 163 | /** 164 | * Obtain current adjustments at current position index. 165 | * 166 | * @return array of adjustments (int[4]) at current position 167 | */ 168 | public int[] getAdjustment() { 169 | return getAdjustment(0); 170 | } 171 | 172 | /** 173 | * Obtain current adjustments at specified offset from current position index. 174 | * 175 | * @param offset 176 | * from current position index 177 | * @return array of adjustments (int[4]) at specified offset 178 | * @throws IndexOutOfBoundsException 179 | * if offset is invalid 180 | */ 181 | public int[] getAdjustment(int offset) throws IndexOutOfBoundsException { 182 | if ((index + offset) < indexLast) { 183 | return adjustments[index + offset]; 184 | } else { 185 | throw new IndexOutOfBoundsException(); 186 | } 187 | } 188 | 189 | /** 190 | * Apply positioning subtable to current state at current position (only), 191 | * resulting in the consumption of zero or more input glyphs. 192 | * 193 | * @param st 194 | * the glyph positioning subtable to apply 195 | * @return true if subtable applied, or false if it did not (e.g., its 196 | * input coverage table did not match current input context) 197 | */ 198 | public boolean apply(GlyphPositioningSubtable st) { 199 | assert st != null; 200 | updateSubtableState(st); 201 | boolean applied = st.position(this); 202 | return applied; 203 | } 204 | 205 | /** 206 | * Apply a sequence of matched rule lookups to the nig input glyphs 207 | * starting at the current position. If lookups are non-null and non-empty, then 208 | * all input glyphs specified by nig are consumed irregardless of 209 | * whether any specified lookup applied. 210 | * 211 | * @param lookups 212 | * array of matched lookups (or null) 213 | * @param nig 214 | * number of glyphs in input sequence, starting at current position, to which 215 | * the lookups are to apply, and to be consumed once the application has finished 216 | * @return true if lookups are non-null and non-empty; otherwise, false 217 | */ 218 | public boolean apply(GlyphTable.RuleLookup[] lookups, int nig) { 219 | if ((lookups != null) && (lookups.length > 0)) { 220 | // apply each rule lookup to extracted input glyph array 221 | for (int i = 0, n = lookups.length; i < n; i++) { 222 | GlyphTable.RuleLookup l = lookups[i]; 223 | if (l != null) { 224 | GlyphTable.LookupTable lt = l.getLookup(); 225 | if (lt != null) { 226 | // perform positioning on a copy of previous state 227 | GlyphPositioningState ps = new GlyphPositioningState(this); 228 | // apply lookup table positioning 229 | if (lt.position(ps, l.getSequenceIndex())) { 230 | setAdjusted(true); 231 | } 232 | } 233 | } 234 | } 235 | consume(nig); 236 | return true; 237 | } else { 238 | return false; 239 | } 240 | } 241 | 242 | /** 243 | * Apply default application semantices; namely, consume one input glyph. 244 | */ 245 | public void applyDefault() { 246 | super.applyDefault(); 247 | } 248 | 249 | /** 250 | * Set adjusted state, used to record effect of non-zero adjustment. 251 | * 252 | * @param adjusted 253 | * true if to set adjusted state, otherwise false to 254 | * clear adjusted state 255 | */ 256 | public void setAdjusted(boolean adjusted) { 257 | this.adjusted = adjusted; 258 | } 259 | 260 | /** 261 | * Get adjusted state. 262 | * 263 | * @return adjusted true if some non-zero adjustment occurred and 264 | * was recorded by {@link #setAdjusted}; otherwise, false. 265 | */ 266 | public boolean getAdjusted() { 267 | return adjusted; 268 | } 269 | 270 | } 271 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/GlyphPositioningSubtable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import com.jaredrummler.fontreader.util.GlyphSequence; 21 | import com.jaredrummler.fontreader.fonts.GlyphSubtable; 22 | import com.jaredrummler.fontreader.truetype.GlyphTable; 23 | import com.jaredrummler.fontreader.util.ScriptContextTester; 24 | 25 | /** 26 | *

The GlyphPositioningSubtable implements an abstract base of a glyph subtable, 27 | * providing a default implementation of the GlyphPositioning interface.

28 | * 29 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

30 | */ 31 | public abstract class GlyphPositioningSubtable extends GlyphSubtable implements GlyphPositioning { 32 | 33 | private static final GlyphPositioningState STATE = new GlyphPositioningState(); 34 | 35 | /** 36 | * Instantiate a GlyphPositioningSubtable. 37 | * 38 | * @param id 39 | * subtable identifier 40 | * @param sequence 41 | * subtable sequence 42 | * @param flags 43 | * subtable flags 44 | * @param format 45 | * subtable format 46 | * @param coverage 47 | * subtable coverage table 48 | */ 49 | protected GlyphPositioningSubtable(String id, int sequence, int flags, int format, GlyphCoverageTable coverage) { 50 | super(id, sequence, flags, format, coverage); 51 | } 52 | 53 | /** {@inheritDoc} */ 54 | public int getTableType() { 55 | return GlyphTable.GLYPH_TABLE_TYPE_POSITIONING; 56 | } 57 | 58 | /** {@inheritDoc} */ 59 | public String getTypeName() { 60 | return GlyphPositioningTable.getLookupTypeName(getType()); 61 | } 62 | 63 | /** {@inheritDoc} */ 64 | public boolean isCompatible(GlyphSubtable subtable) { 65 | return subtable instanceof GlyphPositioningSubtable; 66 | } 67 | 68 | /** {@inheritDoc} */ 69 | public boolean usesReverseScan() { 70 | return false; 71 | } 72 | 73 | /** {@inheritDoc} */ 74 | public boolean position(GlyphPositioningState ps) { 75 | return false; 76 | } 77 | 78 | /** 79 | * Apply positioning using specified state and subtable array. For each position in input sequence, 80 | * apply subtables in order until some subtable applies or none remain. If no subtable applied or no 81 | * input was consumed for a given position, then apply default action (no adjustments and advance). 82 | * If sequenceIndex is non-negative, then apply subtables only when current position 83 | * matches sequenceIndex in relation to the starting position. Furthermore, upon 84 | * successful application at sequenceIndex, then discontinue processing the remaining 85 | * 86 | * @param ps 87 | * positioning state 88 | * @param sta 89 | * array of subtables to apply 90 | * @param sequenceIndex 91 | * if non negative, then apply subtables only at specified sequence index 92 | * @return true if a non-zero adjustment occurred 93 | */ 94 | public static final boolean position(GlyphPositioningState ps, GlyphPositioningSubtable[] sta, int sequenceIndex) { 95 | int sequenceStart = ps.getPosition(); 96 | boolean appliedOneShot = false; 97 | while (ps.hasNext()) { 98 | boolean applied = false; 99 | if (!appliedOneShot && ps.maybeApplicable()) { 100 | for (int i = 0, n = sta.length; !applied && (i < n); i++) { 101 | if (sequenceIndex < 0) { 102 | applied = ps.apply(sta[i]); 103 | } else if (ps.getPosition() == (sequenceStart + sequenceIndex)) { 104 | applied = ps.apply(sta[i]); 105 | if (applied) { 106 | appliedOneShot = true; 107 | } 108 | } 109 | } 110 | } 111 | if (!applied || !ps.didConsume()) { 112 | ps.applyDefault(); 113 | } 114 | ps.next(); 115 | } 116 | return ps.getAdjusted(); 117 | } 118 | 119 | /** 120 | * Apply positioning. 121 | * 122 | * @param gs 123 | * input glyph sequence 124 | * @param script 125 | * tag 126 | * @param language 127 | * tag 128 | * @param feature 129 | * tag 130 | * @param fontSize 131 | * the font size 132 | * @param sta 133 | * subtable array 134 | * @param widths 135 | * array 136 | * @param adjustments 137 | * array (receives output adjustments) 138 | * @param sct 139 | * script context tester 140 | * @return true if a non-zero adjustment occurred 141 | */ 142 | public static final boolean position(GlyphSequence gs, String script, String language, String feature, int fontSize, 143 | GlyphPositioningSubtable[] sta, int[] widths, int[][] adjustments, 144 | ScriptContextTester sct) { 145 | synchronized (STATE) { 146 | return position(STATE.reset(gs, script, language, feature, fontSize, widths, adjustments, sct), sta, -1); 147 | } 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/Positionable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | /** 21 | *

Optional interface which indicates that glyph positioning is supported and, if supported, 22 | * can perform positioning.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public interface Positionable { 27 | 28 | /** 29 | * Determines if font performs glyph positioning. 30 | * 31 | * @return true if performs positioning 32 | */ 33 | boolean performsPositioning(); 34 | 35 | /** 36 | * Perform glyph positioning. 37 | * 38 | * @param cs 39 | * character sequence to map to position offsets (advancement adjustments) 40 | * @param script 41 | * a script identifier 42 | * @param language 43 | * a language identifier 44 | * @param fontSize 45 | * font size 46 | * @return array (sequence) of 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, in that order, 47 | * with one 4-tuple for each element of glyph sequence, or null if no non-zero adjustment applies 48 | */ 49 | int[][] performPositioning(CharSequence cs, String script, String language, int fontSize); 50 | 51 | /** 52 | * Perform glyph positioning using an implied font size. 53 | * 54 | * @param cs 55 | * character sequence to map to position offsets (advancement adjustments) 56 | * @param script 57 | * a script identifier 58 | * @param language 59 | * a language identifier 60 | * @return array (sequence) of 4-tuples of placement [PX,PY] and advance [AX,AY] adjustments, in that order, 61 | * with one 4-tuple for each element of glyph sequence, or null if no non-zero adjustment applies 62 | */ 63 | int[][] performPositioning(CharSequence cs, String script, String language); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/fonts/Substitutable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.fonts; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | *

Optional interface which indicates that glyph substitution is supported and, if supported, 24 | * can perform substitution.

25 | * 26 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

27 | */ 28 | public interface Substitutable { 29 | 30 | /** 31 | * Determines if font performs glyph substitution. 32 | * 33 | * @return true if performs substitution. 34 | */ 35 | boolean performsSubstitution(); 36 | 37 | /** 38 | * Perform substitutions on characters to effect glyph substitution. If some substitution is performed, it 39 | * entails mapping from one or more input characters denoting textual character information to one or more 40 | * output character codes denoting glyphs in this font, where the output character codes may make use of 41 | * private character code values that have significance only for this font. 42 | * 43 | * @param cs 44 | * character sequence to map to output font encoding character sequence 45 | * @param script 46 | * a script identifier 47 | * @param language 48 | * a language identifier 49 | * @param associations 50 | * optional list to receive list of character associations 51 | * @param retainControls 52 | * if true, then retain control characters and their glyph mappings, otherwise remove 53 | * @return output sequence (represented as a character sequence, where each character in the returned sequence 54 | * denotes "font characters", i.e., character codes that map directly (1-1) to their associated glyphs 55 | */ 56 | CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, 57 | boolean retainControls); 58 | 59 | /** 60 | * Reorder combining marks in character sequence so that they precede (within the sequence) the base 61 | * character to which they are applied. N.B. In the case of LTR segments, marks are not reordered by this, 62 | * method since when the segment is reversed by BIDI processing, marks are automatically reordered to precede 63 | * their base character. 64 | * 65 | * @param cs 66 | * character sequence within which combining marks to be reordered 67 | * @param gpa 68 | * associated glyph position adjustments (also reordered) 69 | * @param script 70 | * a script identifier 71 | * @param language 72 | * a language identifier 73 | * @param associations 74 | * optional list of associations to be reordered 75 | * @return output sequence containing reordered "font characters" 76 | */ 77 | CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa, String script, String language, List associations); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/complexscripts/scripts/DefaultScriptProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.complexscripts.scripts; 19 | 20 | import com.jaredrummler.fontreader.complexscripts.util.CharAssociation; 21 | import com.jaredrummler.fontreader.util.GlyphSequence; 22 | import com.jaredrummler.fontreader.util.ScriptContextTester; 23 | import com.jaredrummler.fontreader.complexscripts.fonts.GlyphDefinitionTable; 24 | 25 | /** 26 | *

Default script processor, which enables default glyph composition/decomposition, common ligatures, localized 27 | * forms 28 | * and kerning.

29 | * 30 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

31 | */ 32 | public class DefaultScriptProcessor extends ScriptProcessor { 33 | 34 | /** features to use for substitutions */ 35 | private static final String[] GSUB_FEATURES = { 36 | "ccmp", // glyph composition/decomposition 37 | "liga", // common ligatures 38 | "locl" // localized forms 39 | }; 40 | 41 | /** features to use for positioning */ 42 | private static final String[] GPOS_FEATURES = { 43 | "kern", // kerning 44 | "mark", // mark to base or ligature positioning 45 | "mkmk" // mark to mark positioning 46 | }; 47 | 48 | DefaultScriptProcessor(String script) { 49 | super(script); 50 | } 51 | 52 | @Override 53 | /** {@inheritDoc} */ 54 | public String[] getSubstitutionFeatures() { 55 | return GSUB_FEATURES; 56 | } 57 | 58 | @Override 59 | /** {@inheritDoc} */ 60 | public ScriptContextTester getSubstitutionContextTester() { 61 | return null; 62 | } 63 | 64 | @Override 65 | /** {@inheritDoc} */ 66 | public String[] getPositioningFeatures() { 67 | return GPOS_FEATURES; 68 | } 69 | 70 | @Override 71 | /** {@inheritDoc} */ 72 | public ScriptContextTester getPositioningContextTester() { 73 | return null; 74 | } 75 | 76 | @Override 77 | /** {@inheritDoc} */ 78 | public GlyphSequence reorderCombiningMarks(GlyphDefinitionTable gdef, GlyphSequence gs, int[] unscaledWidths, 79 | int[][] gpa, String script, String language) { 80 | int ng = gs.getGlyphCount(); 81 | int[] ga = gs.getGlyphArray(false); 82 | int nm = 0; 83 | // count combining marks 84 | for (int i = 0; i < ng; i++) { 85 | int gid = ga[i]; 86 | int gw = unscaledWidths[i]; 87 | if (isReorderedMark(gdef, ga, unscaledWidths, i)) { 88 | nm++; 89 | } 90 | } 91 | // only reorder if there is at least one mark and at least one non-mark glyph 92 | if ((nm > 0) && ((ng - nm) > 0)) { 93 | CharAssociation[] aa = gs.getAssociations(0, -1); 94 | int[] nga = new int[ng]; 95 | int[][] npa = (gpa != null) ? new int[ng][] : null; 96 | CharAssociation[] naa = new CharAssociation[ng]; 97 | int k = 0; 98 | CharAssociation ba = null; 99 | int bg = -1; 100 | int[] bpa = null; 101 | for (int i = 0; i < ng; i++) { 102 | int gid = ga[i]; 103 | int[] pa = (gpa != null) ? gpa[i] : null; 104 | CharAssociation ca = aa[i]; 105 | if (isReorderedMark(gdef, ga, unscaledWidths, i)) { 106 | nga[k] = gid; 107 | naa[k] = ca; 108 | if (npa != null) { 109 | npa[k] = pa; 110 | } 111 | k++; 112 | } else { 113 | if (bg != -1) { 114 | nga[k] = bg; 115 | naa[k] = ba; 116 | if (npa != null) { 117 | npa[k] = bpa; 118 | } 119 | k++; 120 | bg = -1; 121 | ba = null; 122 | bpa = null; 123 | } 124 | if (bg == -1) { 125 | bg = gid; 126 | ba = ca; 127 | bpa = pa; 128 | } 129 | } 130 | } 131 | if (bg != -1) { 132 | nga[k] = bg; 133 | naa[k] = ba; 134 | if (npa != null) { 135 | npa[k] = bpa; 136 | } 137 | k++; 138 | } 139 | assert k == ng; 140 | if (npa != null) { 141 | System.arraycopy(npa, 0, gpa, 0, ng); 142 | } 143 | return new GlyphSequence(gs, null, nga, null, null, naa, null); 144 | } else { 145 | return gs; 146 | } 147 | } 148 | 149 | protected boolean isReorderedMark(GlyphDefinitionTable gdef, int[] glyphs, int[] unscaledWidths, int index) { 150 | return gdef.isGlyphClass(glyphs[index], GlyphDefinitionTable.GLYPH_CLASS_MARK) && (unscaledWidths[index] != 0); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/CMapSegment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | /** 21 | * A segment in a cmap table of format 4. Unicode code points between 22 | * {@link #getUnicodeStart()} and {@link #getUnicodeEnd()} map to contiguous glyph indices 23 | * starting from {@link #getGlyphStartIndex()}. 24 | */ 25 | public final class CMapSegment { 26 | 27 | private final int unicodeStart; 28 | private final int unicodeEnd; 29 | private final int glyphStartIndex; 30 | 31 | /** 32 | * Creates a new segment. 33 | * 34 | * @param unicodeStart 35 | * Unicode start index 36 | * @param unicodeEnd 37 | * Unicode end index 38 | * @param glyphStartIndex 39 | * glyph start index 40 | */ 41 | public CMapSegment(int unicodeStart, int unicodeEnd, int glyphStartIndex) { 42 | this.unicodeStart = unicodeStart; 43 | this.unicodeEnd = unicodeEnd; 44 | this.glyphStartIndex = glyphStartIndex; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | int hc = 17; 50 | hc = 31 * hc + unicodeStart; 51 | hc = 31 * hc + unicodeEnd; 52 | hc = 31 * hc + glyphStartIndex; 53 | return hc; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (o instanceof CMapSegment) { 59 | CMapSegment ce = (CMapSegment) o; 60 | return ce.unicodeStart == this.unicodeStart 61 | && ce.unicodeEnd == this.unicodeEnd 62 | && ce.glyphStartIndex == this.glyphStartIndex; 63 | } 64 | return false; 65 | } 66 | 67 | /** 68 | * Returns the unicodeStart. 69 | * 70 | * @return the Unicode start index 71 | */ 72 | public int getUnicodeStart() { 73 | return unicodeStart; 74 | } 75 | 76 | /** 77 | * Returns the unicodeEnd. 78 | * 79 | * @return the Unicode end index 80 | */ 81 | public int getUnicodeEnd() { 82 | return unicodeEnd; 83 | } 84 | 85 | /** 86 | * Returns the glyphStartIndex. 87 | * 88 | * @return the glyph start index 89 | */ 90 | public int getGlyphStartIndex() { 91 | return glyphStartIndex; 92 | } 93 | 94 | /** {@inheritDoc} */ 95 | @Override 96 | public String toString() { 97 | StringBuilder sb = new StringBuilder("CMapSegment: "); 98 | sb.append("{ UC["); 99 | sb.append(unicodeStart); 100 | sb.append(','); 101 | sb.append(unicodeEnd); 102 | sb.append("]: GC["); 103 | sb.append(glyphStartIndex); 104 | sb.append(','); 105 | sb.append(glyphStartIndex + (unicodeEnd - unicodeStart)); 106 | sb.append("] }"); 107 | return sb.toString(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/FontMetrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | import android.graphics.Rect; 21 | 22 | import java.net.URI; 23 | import java.util.Map; 24 | import java.util.Set; 25 | 26 | /** 27 | * Main interface for access to font metrics. 28 | */ 29 | public interface FontMetrics { 30 | 31 | /** 32 | * Returns the URI of the font file from which these metrics were loaded. 33 | * 34 | * @return the font file's URI 35 | */ 36 | URI getFontURI(); 37 | 38 | /** 39 | * Returns the "PostScript" font name (Example: "Helvetica-BoldOblique"). 40 | * 41 | * @return the font name 42 | */ 43 | String getFontName(); 44 | 45 | /** 46 | * Returns the font's full name (Example: "Helvetica Bold Oblique"). 47 | * 48 | * @return the font's full name 49 | */ 50 | String getFullName(); 51 | 52 | /** 53 | * Returns the font's family names as a Set of Strings (Example: "Helvetica"). 54 | * 55 | * @return the font's family names (a Set of Strings) 56 | */ 57 | Set getFamilyNames(); 58 | 59 | /** 60 | * Returns the font name for font embedding (may include a prefix, Example: "1E28bcArialMT"). 61 | * 62 | * @return the name for font embedding 63 | */ 64 | String getEmbedFontName(); 65 | 66 | /** 67 | * Returns the type of the font. 68 | * 69 | * @return the font type 70 | */ 71 | FontType getFontType(); 72 | 73 | /** 74 | * Returns the maximum ascent of the font described by this 75 | * FontMetrics object. Note: This is not the same as getAscender(). 76 | * 77 | * @param size 78 | * font size 79 | * @return ascent in milliponts 80 | */ 81 | int getMaxAscent(int size); 82 | 83 | /** 84 | * Returns the ascent of the font described by this 85 | * FontMetrics object. It returns the nominal ascent within the em box. 86 | * 87 | * @param size 88 | * font size 89 | * @return ascent in milliponts 90 | */ 91 | int getAscender(int size); 92 | 93 | /** 94 | * Returns the size of a capital letter measured from the font's baseline. 95 | * 96 | * @param size 97 | * font size 98 | * @return height of capital characters 99 | */ 100 | int getCapHeight(int size); 101 | 102 | /** 103 | * Returns the descent of the font described by this 104 | * FontMetrics object. 105 | * 106 | * @param size 107 | * font size 108 | * @return descent in milliponts 109 | */ 110 | int getDescender(int size); 111 | 112 | /** 113 | * Determines the typical font height of this 114 | * FontMetrics object 115 | * 116 | * @param size 117 | * font size 118 | * @return font height in millipoints 119 | */ 120 | int getXHeight(int size); 121 | 122 | /** 123 | * Return the width (in 1/1000ths of point size) of the character at 124 | * code point i. 125 | * 126 | * @param i 127 | * code point index 128 | * @param size 129 | * font size 130 | * @return the width of the character 131 | */ 132 | int getWidth(int i, int size); 133 | 134 | /** 135 | * Return the array of widths. 136 | *

137 | * This is used to get an array for inserting in an output format. 138 | * It should not be used for lookup. 139 | * 140 | * @return an array of widths 141 | */ 142 | int[] getWidths(); 143 | 144 | /** 145 | * Returns the bounding box of the glyph at the given index, for the given font size. 146 | * 147 | * @param glyphIndex 148 | * glyph index 149 | * @param size 150 | * font size 151 | * @return the scaled bounding box scaled in 1/1000ths of the given size 152 | */ 153 | Rect getBoundingBox(int glyphIndex, int size); 154 | 155 | /** 156 | * Indicates if the font has kerning information. 157 | * 158 | * @return true if kerning is available. 159 | */ 160 | boolean hasKerningInfo(); 161 | 162 | /** 163 | * Returns the kerning map for the font. 164 | * 165 | * @return the kerning map 166 | */ 167 | Map> getKerningInfo(); 168 | 169 | /** 170 | * Returns the distance from the baseline to the center of the underline (negative 171 | * value indicates below baseline). 172 | * 173 | * @param size 174 | * font size 175 | * @return the position in 1/1000ths of the font size 176 | */ 177 | int getUnderlinePosition(int size); 178 | 179 | /** 180 | * Returns the thickness of the underline. 181 | * 182 | * @param size 183 | * font size 184 | * @return the thickness in 1/1000ths of the font size 185 | */ 186 | int getUnderlineThickness(int size); 187 | 188 | /** 189 | * Returns the distance from the baseline to the center of the strikeout line 190 | * (negative value indicates below baseline). 191 | * 192 | * @param size 193 | * font size 194 | * @return the position in 1/1000ths of the font size 195 | */ 196 | int getStrikeoutPosition(int size); 197 | 198 | /** 199 | * Returns the thickness of the strikeout line. 200 | * 201 | * @param size 202 | * font size 203 | * @return the thickness in 1/1000ths of the font size 204 | */ 205 | int getStrikeoutThickness(int size); 206 | 207 | /** 208 | * Determine if metrics supports specific feature in specified font table. 209 | * 210 | * @param tableType 211 | * type of table (GSUB, GPOS, ...), see GlyphTable.GLYPH_TABLE_TYPE_* 212 | * @param script 213 | * to qualify feature lookup 214 | * @param language 215 | * to qualify feature lookup 216 | * @param feature 217 | * to test 218 | * @return true if feature supported (and has at least one lookup) 219 | */ 220 | boolean hasFeature(int tableType, String script, String language, String feature); 221 | 222 | /** 223 | * Determines whether the font is a multibyte font. 224 | * 225 | * @return True if it is multibyte 226 | */ 227 | boolean isMultiByte(); 228 | 229 | } 230 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/FontTriplet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | import java.io.IOException; 21 | import java.io.ObjectInputStream; 22 | import java.io.Serializable; 23 | 24 | /** 25 | * FontTriplet contains information on name, style and weight of one font 26 | */ 27 | public class FontTriplet implements Comparable, Serializable { 28 | 29 | public static final FontTriplet DEFAULT_FONT_TRIPLET 30 | = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); 31 | 32 | /** serial version UID */ 33 | private static final long serialVersionUID = 1168991106658033508L; 34 | 35 | private String name; 36 | private String style; 37 | private int weight; 38 | private int priority; // priority of this triplet/font mapping 39 | 40 | //This is only a cache 41 | private transient String key; 42 | 43 | public FontTriplet() { 44 | this(null, null, 0); 45 | } 46 | 47 | /** 48 | * Creates a new font triplet. 49 | * 50 | * @param name 51 | * font name 52 | * @param style 53 | * font style (normal, italic etc.) 54 | * @param weight 55 | * font weight (100, 200, 300...800, 900) 56 | */ 57 | public FontTriplet(String name, String style, int weight) { 58 | this(name, style, weight, Font.PRIORITY_DEFAULT); 59 | } 60 | 61 | /** 62 | * Creates a new font triplet. 63 | * 64 | * @param name 65 | * font name 66 | * @param style 67 | * font style (normal, italic etc.) 68 | * @param weight 69 | * font weight (100, 200, 300...800, 900) 70 | * @param priority 71 | * priority of this triplet/font mapping 72 | */ 73 | public FontTriplet(String name, String style, int weight, int priority) { 74 | this.name = name; 75 | this.style = style; 76 | this.weight = weight; 77 | this.priority = priority; 78 | } 79 | 80 | private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 81 | ois.defaultReadObject(); 82 | } 83 | 84 | /** @return the font name */ 85 | public String getName() { 86 | return name; 87 | } 88 | 89 | /** @return the font style */ 90 | public String getStyle() { 91 | return style; 92 | } 93 | 94 | /** @return the font weight */ 95 | public int getWeight() { 96 | return weight; 97 | } 98 | 99 | /** @return the priority of this triplet/font mapping */ 100 | public int getPriority() { 101 | return priority; 102 | } 103 | 104 | private String getKey() { 105 | if (this.key == null) { 106 | //This caches the combined key 107 | this.key = getName() + "," + getStyle() + "," + getWeight(); 108 | } 109 | return this.key; 110 | } 111 | 112 | /** {@inheritDoc} */ 113 | public int compareTo(FontTriplet o) { 114 | return getKey().compareTo(o.getKey()); 115 | } 116 | 117 | /** {@inheritDoc} */ 118 | public int hashCode() { 119 | return toString().hashCode(); 120 | } 121 | 122 | /** {@inheritDoc} */ 123 | public boolean equals(Object obj) { 124 | if (obj == null) { 125 | return false; 126 | } else if (obj == this) { 127 | return true; 128 | } else { 129 | if (obj instanceof FontTriplet) { 130 | FontTriplet other = (FontTriplet) obj; 131 | return (getName().equals(other.getName()) 132 | && getStyle().equals(other.getStyle()) 133 | && (getWeight() == other.getWeight())); 134 | } 135 | } 136 | return false; 137 | } 138 | 139 | /** {@inheritDoc} */ 140 | public String toString() { 141 | return getKey(); 142 | } 143 | 144 | /** 145 | * Matcher interface for {@link FontTriplet}. 146 | */ 147 | public interface Matcher { 148 | 149 | /** 150 | * Indicates whether the given {@link FontTriplet} matches a particular criterium. 151 | * 152 | * @param triplet 153 | * the font triplet 154 | * @return true if the font triplet is a match 155 | */ 156 | boolean matches(FontTriplet triplet); 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/FontType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | /** 21 | * This class enumerates all supported font types. 22 | */ 23 | public class FontType { 24 | 25 | /** 26 | * Collective identifier for "other" font types 27 | */ 28 | public static final FontType OTHER = new FontType("Other", 0); 29 | /** 30 | * Adobe Type 0 fonts (composite font) 31 | */ 32 | public static final FontType TYPE0 = new FontType("Type0", 1); 33 | /** 34 | * Adobe Type 1 fonts 35 | */ 36 | public static final FontType TYPE1 = new FontType("Type1", 2); 37 | /** 38 | * Adobe Multiple Master Type 1 fonts 39 | */ 40 | public static final FontType MMTYPE1 = new FontType("MMType1", 3); 41 | /** 42 | * Adobe Type 3 fonts ("user-defined" fonts) 43 | */ 44 | public static final FontType TYPE3 = new FontType("Type3", 4); 45 | /** 46 | * TrueType fonts 47 | */ 48 | public static final FontType TRUETYPE = new FontType("TrueType", 5); 49 | 50 | public static final FontType TYPE1C = new FontType("Type1C", 6); 51 | 52 | public static final FontType CIDTYPE0 = new FontType("CIDFontType0", 7); 53 | 54 | private final String name; 55 | private final int value; 56 | 57 | /** 58 | * Construct a font type. 59 | * 60 | * @param name 61 | * a font type name 62 | * @param value 63 | * a font type value 64 | */ 65 | protected FontType(String name, int value) { 66 | this.name = name; 67 | this.value = value; 68 | } 69 | 70 | /** 71 | * Returns the FontType by name. 72 | * 73 | * @param name 74 | * Name of the font type to look up 75 | * @return the font type 76 | */ 77 | public static FontType byName(String name) { 78 | if (name.equalsIgnoreCase(FontType.OTHER.getName())) { 79 | return FontType.OTHER; 80 | } else if (name.equalsIgnoreCase(FontType.TYPE0.getName())) { 81 | return FontType.TYPE0; 82 | } else if (name.equalsIgnoreCase(FontType.TYPE1.getName())) { 83 | return FontType.TYPE1; 84 | } else if (name.equalsIgnoreCase(FontType.MMTYPE1.getName())) { 85 | return FontType.MMTYPE1; 86 | } else if (name.equalsIgnoreCase(FontType.TYPE3.getName())) { 87 | return FontType.TYPE3; 88 | } else if (name.equalsIgnoreCase(FontType.TRUETYPE.getName())) { 89 | return FontType.TRUETYPE; 90 | } else { 91 | throw new IllegalArgumentException("Invalid font type: " + name); 92 | } 93 | } 94 | 95 | /** 96 | * Returns the FontType by value. 97 | * 98 | * @param value 99 | * Value of the font type to look up 100 | * @return the font type 101 | */ 102 | public static FontType byValue(int value) { 103 | if (value == FontType.OTHER.getValue()) { 104 | return FontType.OTHER; 105 | } else if (value == FontType.TYPE0.getValue()) { 106 | return FontType.TYPE0; 107 | } else if (value == FontType.TYPE1.getValue()) { 108 | return FontType.TYPE1; 109 | } else if (value == FontType.MMTYPE1.getValue()) { 110 | return FontType.MMTYPE1; 111 | } else if (value == FontType.TYPE3.getValue()) { 112 | return FontType.TYPE3; 113 | } else if (value == FontType.TRUETYPE.getValue()) { 114 | return FontType.TRUETYPE; 115 | } else { 116 | throw new IllegalArgumentException("Invalid font type: " + value); 117 | } 118 | } 119 | 120 | /** 121 | * Returns the name 122 | * 123 | * @return the name 124 | */ 125 | public String getName() { 126 | return name; 127 | } 128 | 129 | /** 130 | * Returns the value 131 | * 132 | * @return the value 133 | */ 134 | public int getValue() { 135 | return value; 136 | } 137 | 138 | @Override 139 | public String toString() { 140 | return name; 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/FontUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | import com.jaredrummler.fontreader.fonts.Font; 21 | 22 | /** 23 | * Font utilities. 24 | */ 25 | public final class FontUtil { 26 | 27 | private FontUtil() { 28 | } 29 | 30 | /** 31 | * Parses an CSS2 (SVG and XSL-FO) font weight (normal, bold, 100-900) to 32 | * an integer. 33 | * See http://www.w3.org/TR/REC-CSS2/fonts.html#propdef-font-weight 34 | * TODO: Implement "lighter" and "bolder". 35 | * 36 | * @param text 37 | * the font weight to parse 38 | * @return an integer between 100 and 900 (100, 200, 300...) 39 | */ 40 | public static int parseCSS2FontWeight(String text) { 41 | int weight = 400; 42 | try { 43 | weight = Integer.parseInt(text); 44 | weight = (weight / 100) * 100; 45 | weight = Math.max(weight, 100); 46 | weight = Math.min(weight, 900); 47 | } catch (NumberFormatException nfe) { 48 | //weight is no number, so convert symbolic name to number 49 | if (text.equals("normal")) { 50 | weight = 400; 51 | } else if (text.equals("bold")) { 52 | weight = 700; 53 | } else { 54 | throw new IllegalArgumentException( 55 | "Illegal value for font weight: '" 56 | + text 57 | + "'. Use one of: 100, 200, 300, " 58 | + "400, 500, 600, 700, 800, 900, " 59 | + "normal (=400), bold (=700)"); 60 | } 61 | } 62 | return weight; 63 | } 64 | 65 | /** 66 | * Removes all white space from a string (used primarily for font names) 67 | * 68 | * @param str 69 | * the string 70 | * @return the processed result 71 | */ 72 | public static String stripWhiteSpace(String str) { 73 | if (str != null) { 74 | StringBuffer stringBuffer = new StringBuffer(str.length()); 75 | for (int i = 0, strLen = str.length(); i < strLen; i++) { 76 | final char ch = str.charAt(i); 77 | if (ch != ' ' && ch != '\r' && ch != '\n' && ch != '\t') { 78 | stringBuffer.append(ch); 79 | } 80 | } 81 | return stringBuffer.toString(); 82 | } 83 | return str; 84 | } 85 | 86 | /** font constituent names which identify a font as being of "italic" style */ 87 | private static final String[] ITALIC_WORDS = { 88 | Font.STYLE_ITALIC, Font.STYLE_OBLIQUE, Font.STYLE_INCLINED 89 | }; 90 | 91 | /** font constituent names which identify a font as being of "light" weight */ 92 | private static final String[] LIGHT_WORDS = {"light"}; 93 | /** font constituent names which identify a font as being of "medium" weight */ 94 | private static final String[] MEDIUM_WORDS = {"medium"}; 95 | /** font constituent names which identify a font as being of "demi/semi" weight */ 96 | private static final String[] DEMI_WORDS = {"demi", "semi"}; 97 | /** font constituent names which identify a font as being of "bold" weight */ 98 | private static final String[] BOLD_WORDS = {"bold"}; 99 | /** font constituent names which identify a font as being of "extra bold" weight */ 100 | private static final String[] EXTRA_BOLD_WORDS = {"extrabold", "extra bold", "black", 101 | "heavy", "ultra", "super"}; 102 | 103 | /** 104 | * Guesses the font style of a font using its name. 105 | * 106 | * @param fontName 107 | * the font name 108 | * @return "normal" or "italic" 109 | */ 110 | public static String guessStyle(String fontName) { 111 | if (fontName != null) { 112 | for (int i = 0; i < ITALIC_WORDS.length; i++) { 113 | if (fontName.indexOf(ITALIC_WORDS[i]) != -1) { 114 | return Font.STYLE_ITALIC; 115 | } 116 | } 117 | } 118 | return Font.STYLE_NORMAL; 119 | } 120 | 121 | /** 122 | * Guesses the font weight of a font using its name. 123 | * 124 | * @param fontName 125 | * the font name 126 | * @return an integer between 100 and 900 127 | */ 128 | public static int guessWeight(String fontName) { 129 | // weight 130 | int weight = Font.WEIGHT_NORMAL; 131 | 132 | for (int i = 0; i < BOLD_WORDS.length; i++) { 133 | if (fontName.indexOf(BOLD_WORDS[i]) != -1) { 134 | weight = Font.WEIGHT_BOLD; 135 | break; 136 | } 137 | } 138 | for (int i = 0; i < MEDIUM_WORDS.length; i++) { 139 | if (fontName.indexOf(MEDIUM_WORDS[i]) != -1) { 140 | weight = Font.WEIGHT_NORMAL + 100; //500 141 | break; 142 | } 143 | } 144 | //Search for "semi/demi" before "light", but after "bold" 145 | //(normally semi/demi-bold is meant, but it can also be semi/demi-light) 146 | for (int i = 0; i < DEMI_WORDS.length; i++) { 147 | if (fontName.indexOf(DEMI_WORDS[i]) != -1) { 148 | weight = Font.WEIGHT_BOLD - 100; //600 149 | break; 150 | } 151 | } 152 | for (int i = 0; i < EXTRA_BOLD_WORDS.length; i++) { 153 | if (fontName.indexOf(EXTRA_BOLD_WORDS[i]) != -1) { 154 | weight = Font.WEIGHT_EXTRA_BOLD; 155 | break; 156 | } 157 | } 158 | for (int i = 0; i < LIGHT_WORDS.length; i++) { 159 | if (fontName.indexOf(LIGHT_WORDS[i]) != -1) { 160 | weight = Font.WEIGHT_LIGHT; 161 | break; 162 | } 163 | } 164 | return weight; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/GlyphSubstitution.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | // CSOFF: LineLengthCheck 21 | 22 | /** 23 | *

The GlyphSubstitution interface is implemented by a glyph substitution subtable 24 | * that supports the determination of glyph substitution information based on script and 25 | * language of the corresponding character content.

26 | * 27 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

28 | */ 29 | public interface GlyphSubstitution { 30 | 31 | /** 32 | * Perform glyph substitution at the current index, mutating the substitution state object as required. 33 | * Only the context associated with the current index is processed. 34 | * 35 | * @param ss 36 | * glyph substitution state object 37 | * @return true if the glyph subtable was applied, meaning that the current context matches the 38 | * associated input context glyph coverage table 39 | */ 40 | boolean substitute(GlyphSubstitutionState ss); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/GlyphSubstitutionSubtable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | // CSOFF: LineLengthCheck 21 | 22 | import com.jaredrummler.fontreader.complexscripts.fonts.GlyphCoverageTable; 23 | import com.jaredrummler.fontreader.truetype.GlyphTable; 24 | import com.jaredrummler.fontreader.util.GlyphSequence; 25 | import com.jaredrummler.fontreader.util.ScriptContextTester; 26 | 27 | /** 28 | *

The GlyphSubstitutionSubtable implements an abstract base of a glyph substitution subtable, 29 | * providing a default implementation of the GlyphSubstitution interface.

30 | * 31 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

32 | */ 33 | public abstract class GlyphSubstitutionSubtable extends GlyphSubtable implements GlyphSubstitution { 34 | 35 | private static final GlyphSubstitutionState STATE = new GlyphSubstitutionState(); 36 | 37 | /** 38 | * Instantiate a GlyphSubstitutionSubtable. 39 | * 40 | * @param id 41 | * subtable identifier 42 | * @param sequence 43 | * subtable sequence 44 | * @param flags 45 | * subtable flags 46 | * @param format 47 | * subtable format 48 | * @param coverage 49 | * subtable coverage table 50 | */ 51 | protected GlyphSubstitutionSubtable(String id, int sequence, int flags, int format, GlyphCoverageTable coverage) { 52 | super(id, sequence, flags, format, coverage); 53 | } 54 | 55 | /** {@inheritDoc} */ 56 | public int getTableType() { 57 | return GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION; 58 | } 59 | 60 | /** {@inheritDoc} */ 61 | public String getTypeName() { 62 | return GlyphSubstitutionTable.getLookupTypeName(getType()); 63 | } 64 | 65 | /** {@inheritDoc} */ 66 | public boolean isCompatible(GlyphSubtable subtable) { 67 | return subtable instanceof GlyphSubstitutionSubtable; 68 | } 69 | 70 | /** {@inheritDoc} */ 71 | public boolean usesReverseScan() { 72 | return false; 73 | } 74 | 75 | /** {@inheritDoc} */ 76 | public boolean substitute(GlyphSubstitutionState ss) { 77 | return false; 78 | } 79 | 80 | /** 81 | * Apply substitutions using specified state and subtable array. For each position in input sequence, 82 | * apply subtables in order until some subtable applies or none remain. If no subtable applied or no 83 | * input was consumed for a given position, then apply default action (copy input glyph and advance). 84 | * If sequenceIndex is non-negative, then apply subtables only when current position 85 | * matches sequenceIndex in relation to the starting position. Furthermore, upon 86 | * successful application at sequenceIndex, then apply default action for all remaining 87 | * glyphs in input sequence. 88 | * 89 | * @param ss 90 | * substitution state 91 | * @param sta 92 | * array of subtables to apply 93 | * @param sequenceIndex 94 | * if non negative, then apply subtables only at specified sequence index 95 | * @return output glyph sequence 96 | */ 97 | public static final GlyphSequence substitute(GlyphSubstitutionState ss, GlyphSubstitutionSubtable[] sta, 98 | int sequenceIndex) { 99 | int sequenceStart = ss.getPosition(); 100 | boolean appliedOneShot = false; 101 | while (ss.hasNext()) { 102 | boolean applied = false; 103 | if (!appliedOneShot && ss.maybeApplicable()) { 104 | for (int i = 0, n = sta.length; !applied && (i < n); i++) { 105 | if (sequenceIndex < 0) { 106 | applied = ss.apply(sta[i]); 107 | } else if (ss.getPosition() == (sequenceStart + sequenceIndex)) { 108 | applied = ss.apply(sta[i]); 109 | if (applied) { 110 | appliedOneShot = true; 111 | } 112 | } 113 | } 114 | } 115 | if (!applied || !ss.didConsume()) { 116 | ss.applyDefault(); 117 | } 118 | ss.next(); 119 | } 120 | return ss.getOutput(); 121 | } 122 | 123 | /** 124 | * Apply substitutions. 125 | * 126 | * @param gs 127 | * input glyph sequence 128 | * @param script 129 | * tag 130 | * @param language 131 | * tag 132 | * @param feature 133 | * tag 134 | * @param sta 135 | * subtable array 136 | * @param sct 137 | * script context tester 138 | * @return output glyph sequence 139 | */ 140 | public static final GlyphSequence substitute(GlyphSequence gs, String script, String language, String feature, 141 | GlyphSubstitutionSubtable[] sta, ScriptContextTester sct) { 142 | synchronized (STATE) { 143 | return substitute(STATE.reset(gs, script, language, feature, sct), sta, -1); 144 | } 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/Glyphs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | public class Glyphs { 21 | 22 | /** 23 | * The characters in WinAnsiEncoding 24 | */ 25 | public static final char[] WINANSI_ENCODING = { 26 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', '\u0021', 27 | '\"', '\u0023', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '\u002d', '\u002e', '/', '0', '1', '2', '3', '4', 28 | '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 29 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u005b', '\\', '\u005d', '^', '_', 30 | '\u2018', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 31 | 'v', 'w', 'x', 'y', 'z', '\u007b', '\u007c', '\u007d', '\u007e', '\u2022', '\u20ac', '\u2022', '\u201a', '\u0192', 32 | '\u201e', '\u2026', '\u2020', '\u2021', '\u02c6', '\u2030', '\u0160', '\u2039', '\u0152', '\u2022', '\u017d', 33 | '\u2022', '\u2022', '\u2018', '\u2019', '\u201c', '\u201d', '\u2022', '\u2013', '\u2014', '~', '\u2122', '\u0161', 34 | '\u203a', '\u0153', '\u2022', '\u017e', '\u0178', ' ', '\u00a1', '\u00a2', '\u00a3', '\u00a4', '\u00a5', '\u00a6', 35 | '\u00a7', '\u00a8', '\u00a9', '\u00aa', '\u00ab', '\u00ac', '\u00ad', '\u00ae', '\u00af', '\u00b0', '\u00b1', 36 | '\u00b2', '\u00b3', '\u00b4', '\u00b5', '\u00b6', '\u00b7', '\u00b8', '\u00b9', '\u00ba', '\u00bb', '\u00bc', 37 | '\u00bd', '\u00be', '\u00bf', '\u00c0', '\u00c1', '\u00c2', '\u00c3', '\u00c4', '\u00c5', '\u00c6', '\u00c7', 38 | '\u00c8', '\u00c9', '\u00ca', '\u00cb', '\u00cc', '\u00cd', '\u00ce', '\u00cf', '\u00d0', '\u00d1', '\u00d2', 39 | '\u00d3', '\u00d4', '\u00d5', '\u00d6', '\u00d7', '\u00d8', '\u00d9', '\u00da', '\u00db', '\u00dc', '\u00dd', 40 | '\u00de', '\u00df', '\u00e0', '\u00e1', '\u00e2', '\u00e3', '\u00e4', '\u00e5', '\u00e6', '\u00e7', '\u00e8', 41 | '\u00e9', '\u00ea', '\u00eb', '\u00ec', '\u00ed', '\u00ee', '\u00ef', '\u00f0', '\u00f1', '\u00f2', '\u00f3', 42 | '\u00f4', '\u00f5', '\u00f6', '\u00f7', '\u00f8', '\u00f9', '\u00fa', '\u00fb', '\u00fc', '\u00fd', '\u00fe', 43 | '\u00ff' 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/OTFScript.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | /** 21 | *

Script tags defined by OTF specification. Note that this set and their 22 | * values do not correspond with ISO 15924 or Unicode Script names.

23 | * 24 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

25 | */ 26 | public final class OTFScript { 27 | 28 | public static final String ARABIC = "arab"; 29 | public static final String ARMENIAN = "armn"; 30 | public static final String AVESTAN = "avst"; 31 | public static final String BALINESE = "bali"; 32 | public static final String BAMUM = "bamu"; 33 | public static final String BATAK = "batk"; 34 | public static final String BENGALI = "beng"; 35 | public static final String BENGALI_V2 = "bng2"; 36 | public static final String BOPOMOFO = "bopo"; 37 | public static final String BRAILLE = "brai"; 38 | public static final String BRAHMI = "brah"; 39 | public static final String BUGINESE = "bugi"; 40 | public static final String BUHID = "buhd"; 41 | public static final String BYZANTINE_MUSIC = "byzm"; 42 | public static final String CANADIAN_SYLLABICS = "cans"; 43 | public static final String CARIAN = "cari"; 44 | public static final String CHAKMA = "cakm"; 45 | public static final String CHAM = "cham"; 46 | public static final String CHEROKEE = "cher"; 47 | public static final String CJK_IDEOGRAPHIC = "hani"; 48 | public static final String COPTIC = "copt"; 49 | public static final String CYPRIOT_SYLLABARY = "cprt"; 50 | public static final String CYRILLIC = "cyrl"; 51 | public static final String DEFAULT = "DFLT"; 52 | public static final String DESERET = "dsrt"; 53 | public static final String DEVANAGARI = "deva"; 54 | public static final String DEVANAGARI_V2 = "dev2"; 55 | public static final String EGYPTIAN_HEIROGLYPHS = "egyp"; 56 | public static final String ETHIOPIC = "ethi"; 57 | public static final String GEORGIAN = "geor"; 58 | public static final String GLAGOLITIC = "glag"; 59 | public static final String GOTHIC = "goth"; 60 | public static final String GREEK = "grek"; 61 | public static final String GUJARATI = "gujr"; 62 | public static final String GUJARATI_V2 = "gjr2"; 63 | public static final String GURMUKHI = "guru"; 64 | public static final String GURMUKHI_V2 = "gur2"; 65 | public static final String HANGUL = "hang"; 66 | public static final String HANGUL_JAMO = "jamo"; 67 | public static final String HANUNOO = "hano"; 68 | public static final String HEBREW = "hebr"; 69 | public static final String HIRAGANA = "kana"; 70 | public static final String IMPERIAL_ARAMAIC = "armi"; 71 | public static final String INSCRIPTIONAL_PAHLAVI = "phli"; 72 | public static final String INSCRIPTIONAL_PARTHIAN = "prti"; 73 | public static final String JAVANESE = "java"; 74 | public static final String KAITHI = "kthi"; 75 | public static final String KANNADA = "knda"; 76 | public static final String KANNADA_V2 = "knd2"; 77 | public static final String KATAKANA = "kana"; 78 | public static final String KAYAH_LI = "kali"; 79 | public static final String KHAROSTHI = "khar"; 80 | public static final String KHMER = "khmr"; 81 | public static final String LAO = "lao"; 82 | public static final String LATIN = "latn"; 83 | public static final String LEPCHA = "lepc"; 84 | public static final String LIMBU = "limb"; 85 | public static final String LINEAR_B = "linb"; 86 | public static final String LISU = "lisu"; 87 | public static final String LYCIAN = "lyci"; 88 | public static final String LYDIAN = "lydi"; 89 | public static final String MALAYALAM = "mlym"; 90 | public static final String MALAYALAM_V2 = "mlm2"; 91 | public static final String MANDAIC = "mand"; 92 | public static final String MATHEMATICAL_ALPHANUMERIC_SYMBOLS = "math"; 93 | public static final String MEITEI = "mtei"; 94 | public static final String MEROITIC_CURSIVE = "merc"; 95 | public static final String MEROITIC_HIEROGLYPHS = "mero"; 96 | public static final String MONGOLIAN = "mong"; 97 | public static final String MUSICAL_SYMBOLS = "musc"; 98 | public static final String MYANMAR = "mymr"; 99 | public static final String NEW_TAI_LUE = "talu"; 100 | public static final String NKO = "nko"; 101 | public static final String OGHAM = "ogam"; 102 | public static final String OL_CHIKI = "olck"; 103 | public static final String OLD_ITALIC = "ital"; 104 | public static final String OLD_PERSIAN_CUNEIFORM = "xpeo"; 105 | public static final String OLD_SOUTH_ARABIAN = "sarb"; 106 | public static final String OLD_TURKIC = "orkh"; 107 | public static final String ORIYA = "orya"; 108 | public static final String ORIYA_V2 = "ory2"; 109 | public static final String OSMANYA = "osma"; 110 | public static final String PHAGS_PA = "phag"; 111 | public static final String PHOENICIAN = "phnx"; 112 | public static final String REJANG = "rjng"; 113 | public static final String RUNIC = "runr"; 114 | public static final String SAMARITAN = "samr"; 115 | public static final String SAURASHTRA = "saur"; 116 | public static final String SHARADA = "shrd"; 117 | public static final String SHAVIAN = "shaw"; 118 | public static final String SINHALA = "sinh"; 119 | public static final String SORA_SOMPENG = "sora"; 120 | public static final String SUMERO_AKKADIAN_CUNEIFORM = "xsux"; 121 | public static final String SUNDANESE = "sund"; 122 | public static final String SYLOTI_NAGRI = "sylo"; 123 | public static final String SYRIAC = "syrc"; 124 | public static final String TAGALOG = "tglg"; 125 | public static final String TAGBANWA = "tagb"; 126 | public static final String TAI_LE = "tale"; 127 | public static final String TAI_THAM = "lana"; 128 | public static final String TAI_VIET = "tavt"; 129 | public static final String TAKRI = "takr"; 130 | public static final String TAMIL = "taml"; 131 | public static final String TAMIL_V2 = "tml2"; 132 | public static final String TELUGU = "telu"; 133 | public static final String TELUGU_V2 = "tel2"; 134 | public static final String THAANA = "thaa"; 135 | public static final String THAI = "thai"; 136 | public static final String TIBETAN = "tibt"; 137 | public static final String TIFINAGH = "tfng"; 138 | public static final String UGARITIC_CUNEIFORM = "ugar"; 139 | public static final String VAI = "vai"; 140 | public static final String WILDCARD = "*"; 141 | public static final String YI = "yi"; 142 | 143 | public static boolean isDefault(String script) { 144 | return (script != null) && script.equals(DEFAULT); 145 | } 146 | 147 | public static boolean isWildCard(String script) { 148 | return (script != null) && script.equals(DEFAULT); 149 | } 150 | 151 | private OTFScript() { 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/SingleByteEncoding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | /** 21 | * The interface defines a 1-byte character encoding (with 256 characters). 22 | */ 23 | public interface SingleByteEncoding { 24 | 25 | /** Code point that is used if no code point for a specific character has been found. */ 26 | char NOT_FOUND_CODE_POINT = '\0'; 27 | 28 | /** 29 | * Returns the encoding's name. 30 | * 31 | * @return the name of the encoding 32 | */ 33 | String getName(); 34 | 35 | /** 36 | * Maps a Unicode character to a code point in the encoding. 37 | * 38 | * @param c 39 | * the Unicode character to map 40 | * @return the code point in the encoding or 0 (=.notdef) if not found 41 | */ 42 | char mapChar(char c); 43 | 44 | /** 45 | * Returns the array of character names for this encoding. 46 | * 47 | * @return the array of character names 48 | * (unmapped code points are represented by a ".notdef" value) 49 | */ 50 | String[] getCharNameMap(); 51 | 52 | /** 53 | * Returns a character array with Unicode scalar values which can be used to map encoding 54 | * code points to Unicode values. Note that this does not return all possible Unicode values 55 | * that the encoding maps. 56 | * 57 | * @return a character array with Unicode scalar values 58 | */ 59 | char[] getUnicodeCharMap(); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/fonts/Typeface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.fonts; 19 | 20 | import java.util.HashSet; 21 | import java.util.Set; 22 | 23 | /** 24 | * Base class for font classes 25 | */ 26 | public abstract class Typeface implements FontMetrics { 27 | 28 | /** 29 | * Code point that is used if no code point for a specific character has 30 | * been found. 31 | */ 32 | public static final char NOT_FOUND = '#'; 33 | 34 | /** 35 | * Used to identify whether a font has been used (a character map operation 36 | * is used as the trigger). This could just as well be a boolean but is a 37 | * long out of statistical interest. 38 | */ 39 | private long charMapOps; 40 | 41 | private Set warnedChars; 42 | 43 | /** 44 | * Get the encoding of the font. 45 | * 46 | * @return the encoding 47 | */ 48 | public abstract String getEncodingName(); 49 | 50 | /** 51 | * Map a Unicode character to a code point in the font. 52 | * 53 | * @param c 54 | * character to map 55 | * @return the mapped character 56 | */ 57 | public abstract char mapChar(char c); 58 | 59 | /** 60 | * Used for keeping track of character mapping operations in order to determine if a font 61 | * was used at all or not. 62 | */ 63 | protected void notifyMapOperation() { 64 | this.charMapOps++; 65 | } 66 | 67 | /** 68 | * Indicates whether this font had to do any character mapping operations. If that was 69 | * not the case, it's an indication that the font has never actually been used. 70 | * 71 | * @return true if the font had to do any character mapping operations 72 | */ 73 | public boolean hadMappingOperations() { 74 | return (this.charMapOps > 0); 75 | } 76 | 77 | /** 78 | * Determines whether this font contains a particular character/glyph. 79 | * 80 | * @param c 81 | * character to check 82 | * @return True if the character is supported, Falso otherwise 83 | */ 84 | public abstract boolean hasChar(char c); 85 | 86 | /** 87 | * Determines whether the font is a multibyte font. 88 | * 89 | * @return True if it is multibyte 90 | */ 91 | public boolean isMultiByte() { 92 | return false; 93 | } 94 | 95 | /** {@inheritDoc} */ 96 | public int getMaxAscent(int size) { 97 | return getAscender(size); 98 | } 99 | 100 | /** {@inheritDoc} */ 101 | public boolean hasFeature(int tableType, String script, String language, String feature) { 102 | return false; 103 | } 104 | 105 | /** 106 | * Provide proper warning if a glyph is not available. 107 | * 108 | * @param c 109 | * the character which is missing. 110 | */ 111 | protected void warnMissingGlyph(char c) { 112 | // Give up, character is not available 113 | Character ch = new Character(c); 114 | if (warnedChars == null) { 115 | warnedChars = new HashSet(); 116 | } 117 | if (warnedChars.size() < 8 && !warnedChars.contains(ch)) { 118 | warnedChars.add(ch); 119 | } 120 | } 121 | 122 | /** {@inheritDoc} */ 123 | public String toString() { 124 | StringBuffer sbuf = new StringBuffer(super.toString()); 125 | sbuf.append('{'); 126 | sbuf.append(getFullName()); 127 | sbuf.append('}'); 128 | return sbuf.toString(); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/io/Charsets.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.io; 19 | 20 | import java.nio.charset.Charset; 21 | import java.util.Collections; 22 | import java.util.SortedMap; 23 | import java.util.TreeMap; 24 | 25 | /** 26 | * Charsets required of every implementation of the Java platform. 27 | * 28 | * From the Java documentation 29 | * Standard charsets: 30 | *

31 | * Every implementation of the Java platform is required to support the following character encodings. Consult 32 | * the release documentation for your implementation to see if any other encodings are supported. Consult the release 33 | * documentation for your implementation to see if any other encodings are supported. 34 | *

35 | * 36 | *
    37 | *
  • US-ASCII
    38 | * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.
  • 39 | *
  • ISO-8859-1
    40 | * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
  • 41 | *
  • UTF-8
    42 | * Eight-bit Unicode Transformation Format.
  • 43 | *
  • UTF-16BE
    44 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
  • 45 | *
  • UTF-16LE
    46 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
  • 47 | *
  • UTF-16
    48 | * Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order 49 | * accepted on input, big-endian used on output.)
  • 50 | *
51 | * 52 | * @see Standard charsets 53 | */ 54 | public class Charsets { 55 | 56 | // 57 | // This class should only contain Charset instances for required encodings. This guarantees that it will load 58 | // correctly and without delay on all Java platforms. 59 | // 60 | 61 | /** 62 | * Constructs a sorted map from canonical charset names to charset objects required of every implementation of the 63 | * Java platform. 64 | *

65 | * From the Java documentation 66 | * Standard charsets: 67 | *

68 | * 69 | * @return An immutable, case-insensitive map from canonical charset names to charset objects. 70 | * @see Charset#availableCharsets() 71 | */ 72 | public static SortedMap requiredCharsets() { 73 | // maybe cache? 74 | // TODO Re-implement on Java 7 to use java.nio.charset.StandardCharsets 75 | final TreeMap m = new TreeMap(String.CASE_INSENSITIVE_ORDER); 76 | m.put(ISO_8859_1.name(), ISO_8859_1); 77 | m.put(US_ASCII.name(), US_ASCII); 78 | m.put(UTF_16.name(), UTF_16); 79 | m.put(UTF_16BE.name(), UTF_16BE); 80 | m.put(UTF_16LE.name(), UTF_16LE); 81 | m.put(UTF_8.name(), UTF_8); 82 | return Collections.unmodifiableSortedMap(m); 83 | } 84 | 85 | /** 86 | * Returns the given Charset or the default Charset if the given Charset is null. 87 | * 88 | * @param charset 89 | * A charset or null. 90 | * @return the given Charset or the default Charset if the given Charset is null 91 | */ 92 | public static Charset toCharset(final Charset charset) { 93 | return charset == null ? Charset.defaultCharset() : charset; 94 | } 95 | 96 | /** 97 | * Returns a Charset for the named charset. If the name is null, return the default Charset. 98 | * 99 | * @param charset 100 | * The name of the requested charset, may be null. 101 | * @return a Charset for the named charset 102 | * @throws java.nio.charset.UnsupportedCharsetException 103 | * If the named charset is unavailable 104 | */ 105 | public static Charset toCharset(final String charset) { 106 | return charset == null ? Charset.defaultCharset() : Charset.forName(charset); 107 | } 108 | 109 | /** 110 | * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1. 111 | *

112 | * Every implementation of the Java platform is required to support this character encoding. 113 | *

114 | * 115 | * @see Standard charsets 116 | */ 117 | public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); 118 | 119 | /** 120 | *

121 | * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set. 122 | *

123 | *

124 | * Every implementation of the Java platform is required to support this character encoding. 125 | *

126 | * 127 | * @see Standard charsets 128 | */ 129 | public static final Charset US_ASCII = Charset.forName("US-ASCII"); 130 | 131 | /** 132 | *

133 | * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark 134 | * (either order accepted on input, big-endian used on output) 135 | *

136 | *

137 | * Every implementation of the Java platform is required to support this character encoding. 138 | *

139 | * 140 | * @see Standard charsets 141 | */ 142 | public static final Charset UTF_16 = Charset.forName("UTF-16"); 143 | 144 | /** 145 | *

146 | * Sixteen-bit Unicode Transformation Format, big-endian byte order. 147 | *

148 | *

149 | * Every implementation of the Java platform is required to support this character encoding. 150 | *

151 | * 152 | * @see Standard charsets 153 | */ 154 | public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); 155 | 156 | /** 157 | *

158 | * Sixteen-bit Unicode Transformation Format, little-endian byte order. 159 | *

160 | *

161 | * Every implementation of the Java platform is required to support this character encoding. 162 | *

163 | * 164 | * @see Standard charsets 165 | */ 166 | public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); 167 | 168 | /** 169 | *

170 | * Eight-bit Unicode Transformation Format. 171 | *

172 | *

173 | * Every implementation of the Java platform is required to support this character encoding. 174 | *

175 | * 176 | * @see Standard charsets 177 | */ 178 | public static final Charset UTF_8 = Charset.forName("UTF-8"); 179 | 180 | } -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/io/ClosedInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.io; 19 | 20 | import java.io.InputStream; 21 | 22 | import static com.jaredrummler.fontreader.io.IOUtils.EOF; 23 | 24 | /** 25 | * Closed input stream. This stream returns EOF to all attempts to read 26 | * something from the stream. 27 | *

28 | * Typically uses of this class include testing for corner cases in methods 29 | * that accept input streams and acting as a sentinel value instead of a 30 | * {@code null} input stream. 31 | */ 32 | public class ClosedInputStream extends InputStream { 33 | 34 | /** 35 | * A singleton. 36 | */ 37 | public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); 38 | 39 | /** 40 | * Returns -1 to indicate that the stream is closed. 41 | * 42 | * @return always -1 43 | */ 44 | @Override public int read() { 45 | return EOF; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/io/LineIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.io; 19 | 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.Reader; 23 | import java.util.Iterator; 24 | import java.util.NoSuchElementException; 25 | 26 | /** 27 | * An Iterator over the lines in a Reader. 28 | *

29 | * LineIterator holds a reference to an open Reader. 30 | * When you have finished with the iterator you should close the reader 31 | * to free internal resources. This can be done by closing the reader directly, 32 | * or by calling the {@link #close()} or {@link #closeQuietly(LineIterator)} 33 | * method on the iterator. 34 | *

35 | * The recommended usage pattern is: 36 | *

 37 |  * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
 38 |  * try {
 39 |  *   while (it.hasNext()) {
 40 |  *     String line = it.nextLine();
 41 |  *     // do something with line
 42 |  *   }
 43 |  * } finally {
 44 |  *   it.close();
 45 |  * }
 46 |  * 
47 | */ 48 | public class LineIterator implements Iterator { 49 | 50 | // N.B. This class deliberately does not implement Iterable, see https://issues.apache.org/jira/browse/IO-181 51 | 52 | /** The reader that is being read. */ 53 | private final BufferedReader bufferedReader; 54 | /** The current line. */ 55 | private String cachedLine; 56 | /** A flag indicating if the iterator has been fully read. */ 57 | private boolean finished = false; 58 | 59 | /** 60 | * Constructs an iterator of the lines for a Reader. 61 | * 62 | * @param reader 63 | * the Reader to read from, not null 64 | * @throws IllegalArgumentException 65 | * if the reader is null 66 | */ 67 | public LineIterator(final Reader reader) throws IllegalArgumentException { 68 | if (reader == null) { 69 | throw new IllegalArgumentException("Reader must not be null"); 70 | } 71 | if (reader instanceof BufferedReader) { 72 | bufferedReader = (BufferedReader) reader; 73 | } else { 74 | bufferedReader = new BufferedReader(reader); 75 | } 76 | } 77 | 78 | //----------------------------------------------------------------------- 79 | 80 | /** 81 | * Indicates whether the Reader has more lines. 82 | * If there is an IOException then {@link #close()} will 83 | * be called on this instance. 84 | * 85 | * @return {@code true} if the Reader has more lines 86 | * @throws IllegalStateException 87 | * if an IO exception occurs 88 | */ 89 | public boolean hasNext() { 90 | if (cachedLine != null) { 91 | return true; 92 | } else if (finished) { 93 | return false; 94 | } else { 95 | try { 96 | while (true) { 97 | final String line = bufferedReader.readLine(); 98 | if (line == null) { 99 | finished = true; 100 | return false; 101 | } else if (isValidLine(line)) { 102 | cachedLine = line; 103 | return true; 104 | } 105 | } 106 | } catch (final IOException ioe) { 107 | close(); 108 | throw new IllegalStateException(ioe); 109 | } 110 | } 111 | } 112 | 113 | /** 114 | * Overridable method to validate each line that is returned. 115 | * This implementation always returns true. 116 | * 117 | * @param line 118 | * the line that is to be validated 119 | * @return true if valid, false to remove from the iterator 120 | */ 121 | protected boolean isValidLine(final String line) { 122 | return true; 123 | } 124 | 125 | /** 126 | * Returns the next line in the wrapped Reader. 127 | * 128 | * @return the next line from the input 129 | * @throws NoSuchElementException 130 | * if there is no line to return 131 | */ 132 | public String next() { 133 | return nextLine(); 134 | } 135 | 136 | /** 137 | * Returns the next line in the wrapped Reader. 138 | * 139 | * @return the next line from the input 140 | * @throws NoSuchElementException 141 | * if there is no line to return 142 | */ 143 | public String nextLine() { 144 | if (!hasNext()) { 145 | throw new NoSuchElementException("No more lines"); 146 | } 147 | final String currentLine = cachedLine; 148 | cachedLine = null; 149 | return currentLine; 150 | } 151 | 152 | /** 153 | * Closes the underlying Reader quietly. 154 | * This method is useful if you only want to process the first few 155 | * lines of a larger file. If you do not close the iterator 156 | * then the Reader remains open. 157 | * This method can safely be called multiple times. 158 | */ 159 | public void close() { 160 | finished = true; 161 | IOUtils.closeQuietly(bufferedReader); 162 | cachedLine = null; 163 | } 164 | 165 | /** 166 | * Unsupported. 167 | * 168 | * @throws UnsupportedOperationException 169 | * always 170 | */ 171 | public void remove() { 172 | throw new UnsupportedOperationException("Remove unsupported on LineIterator"); 173 | } 174 | 175 | //----------------------------------------------------------------------- 176 | 177 | /** 178 | * Closes the iterator, handling null and ignoring exceptions. 179 | * 180 | * @param iterator 181 | * the iterator to close 182 | */ 183 | public static void closeQuietly(final LineIterator iterator) { 184 | if (iterator != null) { 185 | iterator.close(); 186 | } 187 | } 188 | 189 | } -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/io/StringBuilderWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.io; 19 | 20 | import java.io.Serializable; 21 | import java.io.Writer; 22 | 23 | /** 24 | * {@link Writer} implementation that outputs to a {@link StringBuilder}. 25 | *

26 | * NOTE: This implementation, as an alternative to 27 | * java.io.StringWriter, provides an un-synchronized 28 | * (i.e. for use in a single thread) implementation for better performance. 29 | * For safe usage with multiple {@link Thread}s then 30 | * java.io.StringWriter should be used. 31 | */ 32 | public class StringBuilderWriter extends Writer implements Serializable { 33 | 34 | private static final long serialVersionUID = -146927496096066153L; 35 | private final StringBuilder builder; 36 | 37 | /** 38 | * Constructs a new {@link StringBuilder} instance with default capacity. 39 | */ 40 | public StringBuilderWriter() { 41 | this.builder = new StringBuilder(); 42 | } 43 | 44 | /** 45 | * Constructs a new {@link StringBuilder} instance with the specified capacity. 46 | * 47 | * @param capacity 48 | * The initial capacity of the underlying {@link StringBuilder} 49 | */ 50 | public StringBuilderWriter(final int capacity) { 51 | this.builder = new StringBuilder(capacity); 52 | } 53 | 54 | /** 55 | * Constructs a new instance with the specified {@link StringBuilder}. 56 | * 57 | *

If {@code builder} is null a new instance with default capacity will be created.

58 | * 59 | * @param builder 60 | * The String builder. May be null. 61 | */ 62 | public StringBuilderWriter(final StringBuilder builder) { 63 | this.builder = builder != null ? builder : new StringBuilder(); 64 | } 65 | 66 | /** 67 | * Appends a single character to this Writer. 68 | * 69 | * @param value 70 | * The character to append 71 | * @return This writer instance 72 | */ 73 | @Override 74 | public Writer append(final char value) { 75 | builder.append(value); 76 | return this; 77 | } 78 | 79 | /** 80 | * Appends a character sequence to this Writer. 81 | * 82 | * @param value 83 | * The character to append 84 | * @return This writer instance 85 | */ 86 | @Override 87 | public Writer append(final CharSequence value) { 88 | builder.append(value); 89 | return this; 90 | } 91 | 92 | /** 93 | * Appends a portion of a character sequence to the {@link StringBuilder}. 94 | * 95 | * @param value 96 | * The character to append 97 | * @param start 98 | * The index of the first character 99 | * @param end 100 | * The index of the last character + 1 101 | * @return This writer instance 102 | */ 103 | @Override 104 | public Writer append(final CharSequence value, final int start, final int end) { 105 | builder.append(value, start, end); 106 | return this; 107 | } 108 | 109 | /** 110 | * Closing this writer has no effect. 111 | */ 112 | @Override 113 | public void close() { 114 | // no-op 115 | } 116 | 117 | /** 118 | * Flushing this writer has no effect. 119 | */ 120 | @Override 121 | public void flush() { 122 | // no-op 123 | } 124 | 125 | /** 126 | * Writes a String to the {@link StringBuilder}. 127 | * 128 | * @param value 129 | * The value to write 130 | */ 131 | @Override 132 | public void write(final String value) { 133 | if (value != null) { 134 | builder.append(value); 135 | } 136 | } 137 | 138 | /** 139 | * Writes a portion of a character array to the {@link StringBuilder}. 140 | * 141 | * @param value 142 | * The value to write 143 | * @param offset 144 | * The index of the first character 145 | * @param length 146 | * The number of characters to write 147 | */ 148 | @Override 149 | public void write(final char[] value, final int offset, final int length) { 150 | if (value != null) { 151 | builder.append(value, offset, length); 152 | } 153 | } 154 | 155 | /** 156 | * Returns the underlying builder. 157 | * 158 | * @return The underlying builder 159 | */ 160 | public StringBuilder getBuilder() { 161 | return builder; 162 | } 163 | 164 | /** 165 | * Returns {@link StringBuilder#toString()}. 166 | * 167 | * @return The contents of the String builder. 168 | */ 169 | @Override 170 | public String toString() { 171 | return builder.toString(); 172 | } 173 | 174 | } -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/OFDirTabEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.io.IOException; 21 | import java.io.UnsupportedEncodingException; 22 | import java.util.Arrays; 23 | 24 | /** 25 | * This class represents an entry to a TrueType font's Dir Tab. 26 | */ 27 | public class OFDirTabEntry { 28 | 29 | private byte[] tag = new byte[4]; 30 | private long checksum; 31 | private long offset; 32 | private long length; 33 | 34 | public OFDirTabEntry() { 35 | } 36 | 37 | public OFDirTabEntry(long offset, long length) { 38 | this.offset = offset; 39 | this.length = length; 40 | } 41 | 42 | /** 43 | * Read Dir Tab. 44 | * 45 | * @param in 46 | * font file reader 47 | * @return tag name 48 | * @throws IOException 49 | * upon I/O exception 50 | */ 51 | public String read(FontFileReader in) throws IOException { 52 | tag[0] = in.readTTFByte(); 53 | tag[1] = in.readTTFByte(); 54 | tag[2] = in.readTTFByte(); 55 | tag[3] = in.readTTFByte(); 56 | 57 | checksum = in.readTTFLong(); 58 | offset = in.readTTFULong(); 59 | length = in.readTTFULong(); 60 | 61 | return getTagString(); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return "Read dir tab [" + Arrays.toString(tag) + "]" 67 | + " offset: " + offset 68 | + " length: " + length 69 | + " name: " + getTagString(); 70 | } 71 | 72 | /** 73 | * Returns the checksum. 74 | * 75 | * @return int 76 | */ 77 | public long getChecksum() { 78 | return checksum; 79 | } 80 | 81 | /** 82 | * Returns the length. 83 | * 84 | * @return long 85 | */ 86 | public long getLength() { 87 | return length; 88 | } 89 | 90 | /** 91 | * Returns the offset. 92 | * 93 | * @return long 94 | */ 95 | public long getOffset() { 96 | return offset; 97 | } 98 | 99 | /** 100 | * Returns the tag bytes. 101 | * 102 | * @return byte[] 103 | */ 104 | public byte[] getTag() { 105 | return tag; 106 | } 107 | 108 | /** 109 | * Returns the tag bytes. 110 | * 111 | * @return byte[] 112 | */ 113 | public String getTagString() { 114 | try { 115 | return new String(tag, "ISO-8859-1"); 116 | } catch (UnsupportedEncodingException e) { 117 | return this.toString(); // Should never happen. 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/OFMtxEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.util.List; 21 | 22 | /** 23 | * This class represents a TrueType Mtx Entry. 24 | */ 25 | public class OFMtxEntry { 26 | 27 | private int wx; 28 | private int lsb; 29 | private String name = ""; 30 | private int index; 31 | private List unicodeIndex = new java.util.ArrayList(); 32 | private int[] boundingBox = new int[4]; 33 | private long offset; 34 | private byte found; 35 | 36 | /** 37 | * Returns a String representation of this object. 38 | * 39 | * @param t 40 | * TTFFile to use for unit conversion 41 | * @return String String representation 42 | */ 43 | public String toString(TTFFile t) { 44 | return "Glyph " + name + " index: " + getIndexAsString() + " bbox [" 45 | + t.convertTTFUnit2PDFUnit(boundingBox[0]) + " " 46 | + t.convertTTFUnit2PDFUnit(boundingBox[1]) + " " 47 | + t.convertTTFUnit2PDFUnit(boundingBox[2]) + " " 48 | + t.convertTTFUnit2PDFUnit(boundingBox[3]) + "] wx: " 49 | + t.convertTTFUnit2PDFUnit(wx); 50 | } 51 | 52 | /** 53 | * Returns the boundingBox. 54 | * 55 | * @return int[] 56 | */ 57 | public int[] getBoundingBox() { 58 | return boundingBox; 59 | } 60 | 61 | /** 62 | * Sets the boundingBox. 63 | * 64 | * @param boundingBox 65 | * The boundingBox to set 66 | */ 67 | public void setBoundingBox(int[] boundingBox) { 68 | this.boundingBox = boundingBox; 69 | } 70 | 71 | /** 72 | * Returns the found. 73 | * 74 | * @return byte 75 | */ 76 | public byte getFound() { 77 | return found; 78 | } 79 | 80 | /** 81 | * Returns the index. 82 | * 83 | * @return int 84 | */ 85 | public int getIndex() { 86 | return index; 87 | } 88 | 89 | /** 90 | * Determines whether this index represents a reserved character. 91 | * 92 | * @return True if it is reserved 93 | */ 94 | public boolean isIndexReserved() { 95 | return (getIndex() >= 32768) && (getIndex() <= 65535); 96 | } 97 | 98 | /** 99 | * Returns a String representation of the index taking into account if 100 | * the index is in the reserved range. 101 | * 102 | * @return index as String 103 | */ 104 | public String getIndexAsString() { 105 | if (isIndexReserved()) { 106 | return Integer.toString(getIndex()) + " (reserved)"; 107 | } else { 108 | return Integer.toString(getIndex()); 109 | } 110 | } 111 | 112 | /** 113 | * Returns the lsb. 114 | * 115 | * @return int 116 | */ 117 | public int getLsb() { 118 | return lsb; 119 | } 120 | 121 | /** 122 | * Returns the name. 123 | * 124 | * @return String 125 | */ 126 | public String getName() { 127 | return name; 128 | } 129 | 130 | /** 131 | * Returns the offset. 132 | * 133 | * @return long 134 | */ 135 | public long getOffset() { 136 | return offset; 137 | } 138 | 139 | /** 140 | * Returns the unicodeIndex. 141 | * 142 | * @return List 143 | */ 144 | public List getUnicodeIndex() { 145 | return unicodeIndex; 146 | } 147 | 148 | /** 149 | * Returns the wx. 150 | * 151 | * @return int 152 | */ 153 | public int getWx() { 154 | return wx; 155 | } 156 | 157 | /** 158 | * Sets the found. 159 | * 160 | * @param found 161 | * The found to set 162 | */ 163 | public void setFound(byte found) { 164 | this.found = found; 165 | } 166 | 167 | /** 168 | * Sets the index. 169 | * 170 | * @param index 171 | * The index to set 172 | */ 173 | public void setIndex(int index) { 174 | this.index = index; 175 | } 176 | 177 | /** 178 | * Sets the lsb. 179 | * 180 | * @param lsb 181 | * The lsb to set 182 | */ 183 | public void setLsb(int lsb) { 184 | this.lsb = lsb; 185 | } 186 | 187 | /** 188 | * Sets the name. 189 | * 190 | * @param name 191 | * The name to set 192 | */ 193 | public void setName(String name) { 194 | this.name = name; 195 | } 196 | 197 | /** 198 | * Sets the offset. 199 | * 200 | * @param offset 201 | * The offset to set 202 | */ 203 | public void setOffset(long offset) { 204 | this.offset = offset; 205 | } 206 | 207 | /** 208 | * Sets the wx. 209 | * 210 | * @param wx 211 | * The wx to set 212 | */ 213 | public void setWx(int wx) { 214 | this.wx = wx; 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/OFTableName.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | /** 21 | * Represents table names as found in a TrueType font's Table Directory. 22 | * TrueType fonts may have custom tables so we cannot use an enum. 23 | */ 24 | public final class OFTableName { 25 | 26 | /** The first table in a TrueType font file containing metadata about other tables. */ 27 | public static final OFTableName TABLE_DIRECTORY = new OFTableName("tableDirectory"); 28 | 29 | /** Baseline data */ 30 | public static final OFTableName BASE = new OFTableName("BASE"); 31 | 32 | /** CFF data/ */ 33 | public static final OFTableName CFF = new OFTableName("CFF "); 34 | 35 | /** Embedded bitmap data. */ 36 | public static final OFTableName EBDT = new OFTableName("EBDT"); 37 | 38 | /** Embedded bitmap location data. */ 39 | public static final OFTableName EBLC = new OFTableName("EBLC"); 40 | 41 | /** Embedded bitmap scaling data. */ 42 | public static final OFTableName EBSC = new OFTableName("EBSC"); 43 | 44 | /** A FontForge specific table. */ 45 | public static final OFTableName FFTM = new OFTableName("FFTM"); 46 | 47 | /** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ 48 | public static final OFTableName GDEF = new OFTableName("GDEF"); 49 | 50 | /** Provides kerning information, mark-to-base, etc. for opentype fonts. */ 51 | public static final OFTableName GPOS = new OFTableName("GPOS"); 52 | 53 | /** Provides ligature information, swash, etc. for opentype fonts. */ 54 | public static final OFTableName GSUB = new OFTableName("GSUB"); 55 | 56 | /** Linear threshold table. */ 57 | public static final OFTableName LTSH = new OFTableName("LTSH"); 58 | 59 | /** OS/2 and Windows specific metrics. */ 60 | public static final OFTableName OS2 = new OFTableName("OS/2"); 61 | 62 | /** PCL 5 data. */ 63 | public static final OFTableName PCLT = new OFTableName("PCLT"); 64 | 65 | /** Vertical Device Metrics table. */ 66 | public static final OFTableName VDMX = new OFTableName("VDMX"); 67 | 68 | /** Character to glyph mapping. */ 69 | public static final OFTableName CMAP = new OFTableName("cmap"); 70 | 71 | /** Control Value Table. */ 72 | public static final OFTableName CVT = new OFTableName("cvt "); 73 | 74 | /** Font program. */ 75 | public static final OFTableName FPGM = new OFTableName("fpgm"); 76 | 77 | /** Grid-fitting and scan conversion procedure (grayscale). */ 78 | public static final OFTableName GASP = new OFTableName("gasp"); 79 | 80 | /** Glyph data. */ 81 | public static final OFTableName GLYF = new OFTableName("glyf"); 82 | 83 | /** Horizontal device metrics. */ 84 | public static final OFTableName HDMX = new OFTableName("hdmx"); 85 | 86 | /** Font header. */ 87 | public static final OFTableName HEAD = new OFTableName("head"); 88 | 89 | /** Horizontal header. */ 90 | public static final OFTableName HHEA = new OFTableName("hhea"); 91 | 92 | /** Horizontal metrics. */ 93 | public static final OFTableName HMTX = new OFTableName("hmtx"); 94 | 95 | /** Kerning. */ 96 | public static final OFTableName KERN = new OFTableName("kern"); 97 | 98 | /** Index to location. */ 99 | public static final OFTableName LOCA = new OFTableName("loca"); 100 | 101 | /** Maximum profile. */ 102 | public static final OFTableName MAXP = new OFTableName("maxp"); 103 | 104 | /** Naming table. */ 105 | public static final OFTableName NAME = new OFTableName("name"); 106 | 107 | /** PostScript information. */ 108 | public static final OFTableName POST = new OFTableName("post"); 109 | 110 | /** CVT Program. */ 111 | public static final OFTableName PREP = new OFTableName("prep"); 112 | 113 | /** Vertical Metrics header. */ 114 | public static final OFTableName VHEA = new OFTableName("vhea"); 115 | 116 | /** Vertical Metrics. */ 117 | public static final OFTableName VMTX = new OFTableName("vmtx"); 118 | 119 | private final String name; 120 | 121 | private OFTableName(String name) { 122 | this.name = name; 123 | } 124 | 125 | /** 126 | * Returns the name of the table as it should be in the Directory Table. 127 | */ 128 | public String getName() { 129 | return name; 130 | } 131 | 132 | /** 133 | * Returns an instance of this class corresponding to the given string representation. 134 | * 135 | * @param tableName 136 | * table name as in the Table Directory 137 | * @return TTFTableName 138 | */ 139 | public static OFTableName getValue(String tableName) { 140 | if (tableName != null) { 141 | return new OFTableName(tableName); 142 | } 143 | throw new IllegalArgumentException("A TrueType font table name must not be null"); 144 | } 145 | 146 | @Override 147 | public int hashCode() { 148 | return name.hashCode(); 149 | } 150 | 151 | @Override 152 | public boolean equals(Object o) { 153 | if (o == this) { 154 | return true; 155 | } 156 | if (!(o instanceof OFTableName)) { 157 | return false; 158 | } 159 | OFTableName to = (OFTableName) o; 160 | return this.name.equals(to.getName()); 161 | } 162 | 163 | @Override 164 | public String toString() { 165 | return name; 166 | } 167 | 168 | } 169 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/TTFFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | 25 | /** 26 | * Reads a TrueType file or a TrueType Collection. 27 | * The TrueType spec can be found at the Microsoft. 28 | * Typography site: http://www.microsoft.com/truetype/ 29 | */ 30 | public class TTFFile extends OpenFont { 31 | 32 | /** 33 | * Reads a TTF file 34 | * 35 | * @param file 36 | * The font file 37 | * @return The TrueType file 38 | * @throws IOException 39 | * if an IO error occurs 40 | */ 41 | public static TTFFile open(File file) throws IOException { 42 | return open(new FileInputStream(file)); 43 | } 44 | 45 | /** 46 | * Reads a TTF file from an InputStream 47 | * 48 | * @param is 49 | * InputStream to read from 50 | * @return The TrueType file 51 | * @throws IOException 52 | * if an IO error occurs 53 | */ 54 | public static TTFFile open(InputStream is) throws IOException { 55 | TTFFile ttfFile = new TTFFile(); 56 | ttfFile.readFont(new FontFileReader(is)); 57 | return ttfFile; 58 | } 59 | 60 | public TTFFile() { 61 | this(true, false); 62 | } 63 | 64 | /** 65 | * Constructor 66 | * 67 | * @param useKerning 68 | * true if kerning data should be loaded 69 | * @param useAdvanced 70 | * true if advanced typographic tables should be loaded 71 | */ 72 | public TTFFile(boolean useKerning, boolean useAdvanced) { 73 | super(useKerning, useAdvanced); 74 | } 75 | 76 | /** 77 | * Read the "name" table. 78 | * 79 | * @throws IOException 80 | * In case of a I/O problem 81 | */ 82 | protected void readName() throws IOException { 83 | seekTab(fontFile, OFTableName.NAME, 2); 84 | int i = fontFile.getCurrentPos(); 85 | int n = fontFile.readTTFUShort(); 86 | int j = fontFile.readTTFUShort() + i - 2; 87 | i += 2 * 2; 88 | 89 | while (n-- > 0) { 90 | fontFile.seekSet(i); 91 | final int platformID = fontFile.readTTFUShort(); 92 | final int encodingID = fontFile.readTTFUShort(); 93 | final int languageID = fontFile.readTTFUShort(); 94 | 95 | int k = fontFile.readTTFUShort(); 96 | int l = fontFile.readTTFUShort(); 97 | 98 | if (((platformID == 1 || platformID == 3) 99 | && (encodingID == 0 || encodingID == 1))) { 100 | fontFile.seekSet(j + fontFile.readTTFUShort()); 101 | String txt; 102 | if (platformID == 3) { 103 | txt = fontFile.readTTFString(l, encodingID); 104 | } else { 105 | txt = fontFile.readTTFString(l); 106 | } 107 | 108 | switch (k) { 109 | case 0: 110 | if (notice.length() == 0) { 111 | notice = txt; 112 | } 113 | break; 114 | case 1: //Font Family Name 115 | case 16: //Preferred Family 116 | familyNames.add(txt); 117 | break; 118 | case 2: 119 | if (subFamilyName.length() == 0) { 120 | subFamilyName = txt; 121 | } 122 | break; 123 | case 4: 124 | if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) { 125 | fullName = txt; 126 | } 127 | break; 128 | case 6: 129 | if (postScriptName.length() == 0) { 130 | postScriptName = txt; 131 | } 132 | break; 133 | default: 134 | break; 135 | } 136 | } 137 | i += 6 * 2; 138 | } 139 | } 140 | 141 | /** 142 | * Read the "glyf" table to find the bounding boxes. 143 | * 144 | * @throws IOException 145 | * In case of a I/O problem 146 | */ 147 | private void readGlyf() throws IOException { 148 | OFDirTabEntry dirTab = dirTabs.get(OFTableName.GLYF); 149 | if (dirTab == null) { 150 | throw new IOException("glyf table not found, cannot continue"); 151 | } 152 | for (int i = 0; i < (numberOfGlyphs - 1); i++) { 153 | if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { 154 | fontFile.seekSet(dirTab.getOffset() + mtxTab[i].getOffset()); 155 | fontFile.skip(2); 156 | final int[] bbox = { 157 | fontFile.readTTFShort(), 158 | fontFile.readTTFShort(), 159 | fontFile.readTTFShort(), 160 | fontFile.readTTFShort()}; 161 | mtxTab[i].setBoundingBox(bbox); 162 | } else { 163 | mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox()); 164 | } 165 | } 166 | 167 | long n = (dirTabs.get(OFTableName.GLYF)).getOffset(); 168 | for (int i = 0; i < numberOfGlyphs; i++) { 169 | if ((i + 1) >= mtxTab.length 170 | || mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { 171 | fontFile.seekSet(n + mtxTab[i].getOffset()); 172 | fontFile.skip(2); 173 | final int[] bbox = { 174 | fontFile.readTTFShort(), 175 | fontFile.readTTFShort(), 176 | fontFile.readTTFShort(), 177 | fontFile.readTTFShort()}; 178 | mtxTab[i].setBoundingBox(bbox); 179 | } else { 180 | final int bbox0 = mtxTab[0].getBoundingBox()[0]; 181 | final int[] bbox = {bbox0, bbox0, bbox0, bbox0}; 182 | mtxTab[i].setBoundingBox(bbox); 183 | } 184 | } 185 | } 186 | 187 | @Override protected void updateBBoxAndOffset() throws IOException { 188 | readIndexToLocation(); 189 | readGlyf(); 190 | } 191 | 192 | /** 193 | * Read the "loca" table. 194 | * 195 | * @throws IOException 196 | * In case of a I/O problem 197 | */ 198 | protected final void readIndexToLocation() 199 | throws IOException { 200 | if (!seekTab(fontFile, OFTableName.LOCA, 0)) { 201 | throw new IOException("'loca' table not found, happens when the font file doesn't" 202 | + " contain TrueType outlines (trying to read an OpenType CFF font maybe?)"); 203 | } 204 | for (int i = 0; i < numberOfGlyphs; i++) { 205 | mtxTab[i].setOffset(locaFormat == 1 ? fontFile.readTTFULong() 206 | : (fontFile.readTTFUShort() << 1)); 207 | } 208 | lastLoca = (locaFormat == 1 ? fontFile.readTTFULong() 209 | : (fontFile.readTTFUShort() << 1)); 210 | } 211 | 212 | /** 213 | * Gets the last location of the glyf table 214 | * 215 | * @return The last location as a long 216 | */ 217 | public long getLastGlyfLocation() { 218 | return lastLoca; 219 | } 220 | 221 | @Override protected void initializeFont(FontFileReader in) throws IOException { 222 | fontFile = in; 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/TTFGlyphOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * An interface for writing individual glyphs from the glyf table of a TrueType font to an output stream. 24 | */ 25 | public interface TTFGlyphOutputStream { 26 | 27 | /** 28 | * Begins the streaming of glyphs. 29 | */ 30 | void startGlyphStream() throws IOException; 31 | 32 | /** 33 | * Streams an individual glyph from the given byte array. 34 | * 35 | * @param glyphData 36 | * the source of the glyph data to stream from 37 | * @param offset 38 | * the position in the glyph data where the glyph starts 39 | * @param size 40 | * the size of the glyph data in bytes 41 | */ 42 | void streamGlyph(byte[] glyphData, int offset, int size) throws IOException; 43 | 44 | /** 45 | * Ends the streaming of glyphs. 46 | */ 47 | void endGlyphStream() throws IOException; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/TTFOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * An interface for writing a TrueType font to an output stream. 24 | */ 25 | public interface TTFOutputStream { 26 | 27 | /** 28 | * Starts writing the font. 29 | */ 30 | void startFontStream() throws IOException; 31 | 32 | /** 33 | * Returns an object for streaming TrueType tables. 34 | */ 35 | TTFTableOutputStream getTableOutputStream(); 36 | 37 | /** 38 | * Returns an object for streaming TrueType glyphs in the glyf table. 39 | */ 40 | TTFGlyphOutputStream getGlyphOutputStream(); 41 | 42 | /** 43 | * Ends writing the font. 44 | */ 45 | void endFontStream() throws IOException; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/truetype/TTFTableOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.truetype; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * An interface for writing a TrueType table to an output stream. 24 | */ 25 | public interface TTFTableOutputStream { 26 | 27 | /** 28 | * Streams a table from the given byte array. 29 | * 30 | * @param ttfData 31 | * the source of the table to stream from 32 | * @param offset 33 | * the position in the byte array where the table starts 34 | * @param size 35 | * the size of the table in bytes 36 | */ 37 | void streamTable(byte[] ttfData, int offset, int size) throws IOException; 38 | } 39 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/util/GlyphTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.util; 19 | 20 | /** 21 | *

Interface for testing glyph properties according to glyph identifier.

22 | * 23 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

24 | */ 25 | public interface GlyphTester { 26 | 27 | /** 28 | * Perform a test on a glyph identifier. 29 | * 30 | * @param gi 31 | * glyph identififer 32 | * @param flags 33 | * that apply to lookup in scope 34 | * @return true if test is satisfied 35 | */ 36 | boolean test(int gi, int flags); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /lib-truetypeparser/src/main/java/com/jaredrummler/fontreader/util/ScriptContextTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.fontreader.util; 19 | 20 | import com.jaredrummler.fontreader.complexscripts.fonts.GlyphContextTester; 21 | 22 | /** 23 | *

Interface for providing script specific context testers.

24 | * 25 | *

This work was originally authored by Glenn Adams (gadams@apache.org).

26 | */ 27 | public interface ScriptContextTester { 28 | 29 | /** 30 | * Obtain a glyph context tester for the specified feature. 31 | * 32 | * @param feature 33 | * a feature identifier 34 | * @return a glyph context tester or null if none available for the specified feature 35 | */ 36 | GlyphContextTester getTester(String feature); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.jaredrummler.truetype.sample" 9 | minSdkVersion 14 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile 'com.android.support:appcompat-v7:24.2.1' 24 | compile 'com.android.support:design:24.2.1' 25 | compile project(':lib-truetypeparser') 26 | } 27 | -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 22 | 23 | 24 | 25 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /sample/src/main/assets/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/assets/font.ttf -------------------------------------------------------------------------------- /sample/src/main/java/com/jaredrummler/truetype/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Jared Rummler 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package com.jaredrummler.truetype.sample; 19 | 20 | import android.os.AsyncTask; 21 | import android.os.Bundle; 22 | import android.support.design.widget.FloatingActionButton; 23 | import android.support.v7.app.AlertDialog; 24 | import android.support.v7.app.AppCompatActivity; 25 | import android.support.v7.widget.Toolbar; 26 | import android.text.Html; 27 | import android.view.Menu; 28 | import android.view.MenuItem; 29 | import android.view.View; 30 | 31 | import com.jaredrummler.fontreader.truetype.TTFFile; 32 | 33 | import java.io.IOException; 34 | import java.util.ArrayList; 35 | import java.util.Arrays; 36 | import java.util.List; 37 | 38 | public class MainActivity extends AppCompatActivity { 39 | 40 | @Override protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 44 | setSupportActionBar(toolbar); 45 | 46 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 47 | fab.setOnClickListener(new View.OnClickListener() { 48 | 49 | @Override public void onClick(View view) { 50 | showFontInfo("font.ttf"); 51 | } 52 | }); 53 | } 54 | 55 | @Override public boolean onCreateOptionsMenu(Menu menu) { 56 | // Inflate the menu; this adds items to the action bar if it is present. 57 | getMenuInflater().inflate(R.menu.menu_main, menu); 58 | return true; 59 | } 60 | 61 | @Override public boolean onOptionsItemSelected(MenuItem item) { 62 | // Handle action bar item clicks here. The action bar will 63 | // automatically handle clicks on the Home/Up button, so long 64 | // as you specify a parent activity in AndroidManifest.xml. 65 | int id = item.getItemId(); 66 | 67 | //noinspection SimplifiableIfStatement 68 | if (id == R.id.action_settings) { 69 | return true; 70 | } 71 | 72 | return super.onOptionsItemSelected(item); 73 | } 74 | 75 | private void showFontInfo(String asset) { 76 | new AsyncTask>() { 77 | 78 | @Override protected List doInBackground(String... params) { 79 | List properties = new ArrayList<>(); 80 | 81 | try { 82 | TTFFile ttfFile = TTFFile.open(getAssets().open(params[0])); 83 | 84 | properties.add(new String[]{"NAME", ttfFile.getFullName()}); 85 | properties.add(new String[]{"POST SCRIPT NAME", ttfFile.getPostScriptName()}); 86 | properties.add(new String[]{"FAMILIES", Arrays.toString(ttfFile.getFamilyNames().toArray())}); 87 | properties.add(new String[]{"SUB FAMILY", ttfFile.getSubFamilyName()}); 88 | properties.add(new String[]{"WEIGHT", String.valueOf(ttfFile.getWeightClass())}); 89 | properties.add(new String[]{"NOTICE", ttfFile.getCopyrightNotice()}); 90 | 91 | } catch (IOException e) { 92 | e.printStackTrace(); 93 | } 94 | 95 | return properties; 96 | } 97 | 98 | @Override protected void onPostExecute(List properties) { 99 | if (isFinishing()) { 100 | return; 101 | } 102 | StringBuilder html = new StringBuilder(); 103 | for (String[] property : properties) { 104 | html.append("") 105 | .append(property[0]) 106 | .append(":") 107 | .append(' ') 108 | .append(property[1]) 109 | .append("

"); 110 | } 111 | new AlertDialog.Builder(MainActivity.this) 112 | .setTitle("Font properties") 113 | .setMessage(Html.fromHtml(html.toString())) 114 | .setPositiveButton(android.R.string.ok, null) 115 | .show(); 116 | } 117 | 118 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, asset); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable/ic_font_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 27 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 27 | 28 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 32 | 33 | 37 | 38 | -------------------------------------------------------------------------------- /sample/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaredrummler/TrueTypeParser/5c5f71e3dc2375df567b44b723cf717bd1a79033/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | > 19 | 20 | 26 | 27 | -------------------------------------------------------------------------------- /sample/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 22 | 64dp 23 | 24 | -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | #3F51B5 21 | #303F9F 22 | #FF4081 23 | 24 | -------------------------------------------------------------------------------- /sample/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 16dp 21 | 16dp 22 | 16dp 23 | 24 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | TrueType Parser 20 | Settings 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 32 | 33 |