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 RummlerException 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 | * aThrowable 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 The GlyphClassMapping interface provides glyph identifier to class
22 | * index mapping support.
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 RummlerBase 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 RummlerInterface 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 RummlerThe GlyphCoverageMapping interface provides glyph identifier to coverage
22 | * index mapping support.
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.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 RummlerThe GlyphDefinition interface is a marker interface implemented by a glyph definition
22 | * subtable.
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 RummlerThe GlyphDefinitionSubtable implements an abstract base of a glyph definition subtable,
25 | * providing a default implementation of the GlyphDefinition interface.
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 aGlyphDefinitionSubtable.
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 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.
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 RummlerThe GlyphPositioningState implements an state object used during glyph positioning
26 | * processing.
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 thenig 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 The GlyphPositioningSubtable implements an abstract base of a glyph subtable,
27 | * providing a default implementation of the GlyphPositioning interface.
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 aGlyphPositioningSubtable.
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 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 RummlerOptional 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 RummlerDefault 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
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 The This work was originally authored by Glenn Adams (gadams@apache.org). The This work was originally authored by Glenn Adams (gadams@apache.org). Script tags defined by OTF specification. Note that this set and their
22 | * values do not correspond with ISO 15924 or Unicode Script names. This work was originally authored by Glenn Adams (gadams@apache.org).
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 | *
65 | * From the Java documentation
66 | * Standard charsets:
67 | *
112 | * Every implementation of the Java platform is required to support this character encoding.
113 | *
121 | * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.
122 | *
124 | * Every implementation of the Java platform is required to support this character encoding.
125 | *
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 | *
137 | * Every implementation of the Java platform is required to support this character encoding.
138 | *
146 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.
147 | *
149 | * Every implementation of the Java platform is required to support this character encoding.
150 | *
158 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.
159 | *
161 | * Every implementation of the Java platform is required to support this character encoding.
162 | *
170 | * Eight-bit Unicode Transformation Format.
171 | *
173 | * Every implementation of the Java platform is required to support this character encoding.
174 | *
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
29 | *
35 | * The recommended usage pattern is:
36 | *
26 | * NOTE: This implementation, as an alternative to
27 | * If {@code builder} is null a new instance with default capacity will be created. Interface for testing glyph properties according to glyph identifier. This work was originally authored by Glenn Adams (gadams@apache.org). Interface for providing script specific context testers. This work was originally authored by Glenn Adams (gadams@apache.org).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.GlyphSubstitutionSubtable implements an abstract base of a glyph substitution subtable,
29 | * providing a default implementation of the GlyphSubstitution interface.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
37 | *
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 | * US-ASCII
38 | * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.ISO-8859-1
40 | * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.UTF-8
42 | * Eight-bit Unicode Transformation Format.UTF-16BE
44 | * Sixteen-bit Unicode Transformation Format, big-endian byte order.UTF-16LE
46 | * Sixteen-bit Unicode Transformation Format, little-endian byte order.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.)Reader.
28 | * 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 | *
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 IteratorReader.
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 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 | *
");
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 |