
com.adobe.fontengine.inlineformatting.infontformatting.TibetanFormatter Maven / Gradle / Ivy
/*
* File: TibetanFormatter.java
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2005 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or
* copyright law. Dissemination of this information or reproduction of this
* material is strictly forbidden unless prior written permission is
* obtained from Adobe Systems Incorporated.
*
*/
package com.adobe.fontengine.inlineformatting.infontformatting;
import com.adobe.agl.lang.UCharacter;
import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.CharUtil;
import com.adobe.fontengine.font.FontLoadingException;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.opentype.OTSelectors;
import com.adobe.fontengine.font.opentype.OpenTypeFont;
import com.adobe.fontengine.font.opentype.Tag;
import com.adobe.fontengine.inlineformatting.AttributedRun;
import com.adobe.fontengine.inlineformatting.ElementAttribute;
public final class TibetanFormatter extends GenericFormatter {
//------------------------------------------------------- OpenType layout ---
public static final int[] u0f73 = new int[] {0x0F71, 0x0F72};
public static final int[] u0f75 = new int[] {0x0F71, 0x0F74};
public static final int[] u0f76 = new int[] {0x0FB2, 0x0F80};
public static final int[] u0f77 = new int[] {0x0FB2, 0x0F71, 0x0F80};
public static final int[] u0f78 = new int[] {0x0FB3, 0x0F80};
public static final int[] u0f79 = new int[] {0x0FB3, 0x0F71, 0x0F80};
public static final int[] u0f81 = new int[] {0x0F71, 0x0F80};
protected int splitComposites (AttributedRun run, int start, int limit) {
while (start < limit) {
int usv = run.elementAt (start);
switch (usv) {
case 0x0F73: {
run.replace (start, u0f73); limit += u0f73.length - 1; start += u0f73.length; break; }
case 0x0F75: {
run.replace (start, u0f75); limit += u0f75.length - 1; start += u0f75.length; break; }
case 0x0F76: {
run.replace (start, u0f76); limit += u0f76.length - 1; start += u0f76.length; break; }
case 0x0F77: {
run.replace (start, u0f77); limit += u0f77.length - 1; start += u0f77.length; break; }
case 0x0F78: {
run.replace (start, u0f78); limit += u0f78.length - 1; start += u0f78.length; break; }
case 0x0F79: {
run.replace (start, u0f79); limit += u0f79.length - 1; start += u0f79.length; break; }
case 0x0F81: {
run.replace (start, u0f81); limit += u0f81.length - 1; start += u0f81.length; break; }
default: {
start++;
break; }}}
return limit;
}
// The ordering of glyphs follows the recommendation at
// .
// This was written by Chris Fynn, who is:
// - an expert on Tibetan
// - the developer of an OT Tibetan font for MS
// - the potential developer for "AdobeTibetan"
//
// The table below gives the relative order of glyphs
// for the corresponding characters. Since we need
// a total order and the URL above gives only a partial
// order, we had to extend it, but there is nothing
// complicated (most of the glyphs not mentioned by
// Chris are given an order of 9). Higher value means
// "later in the glyph stream".
//
// Note that when ordering the glyphs, we do want a stable
// sort, so that for example {sa, subjoined pa, subjoined ya}
// does not exchange the pa and the ya.
protected static final int[] order = new int[] {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0F00
0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, // 0F10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0F20
0, 0, 0, 0, 0, 9, 0, 9, 0, 1, 0, 0, 0, 0, 0, 0, // 0F30
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0F40
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0F50
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0F60
0, 3, 6, 0, 4, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 9, // 0F70
6, 0, 7, 7, 5, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, // 0F80
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0F90
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0FA0
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, // 0FB0
0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0FC0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0FD0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0FE0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; // 0FF0
protected int getOrder (int usv) {
if (usv < 0x0F00 || usv > 0x0FF0) {
// so what should happen for a non-Tibetan mark?
// since we need an ordering not based on combining
// class, there is really nothing defined about
// the proper behavior there.
return 0; }
else {
return order [usv - 0x0F00]; }
}
protected void processOneStack (AttributedRun run, int start, int limit, OpenTypeFont otFont)
throws InvalidFontException, UnsupportedFontException {
// we know that [start, limit[ is a combining sequence
if (limit - start <= 2) {
// simple case with at most one combining character,
// so there is nothing to reorder; this is also
// by far the vast majority of the cases (probably
// more than 95%, if not more)
for (int i = start; i < limit; i++) {
run.replace (i, otFont.getGlyphForChar (run.elementAt (i)));
run.setElementStyle (i, ElementAttribute.isGlyph, Boolean.TRUE); }
return; }
int[] stack = new int [limit - start];
int[] positions = new int [limit - start];
for (int i = start; i < limit; i++) {
stack [i - start] = run.elementAt (i);
positions [i - start] = i; }
// By far the most common case as this point
// is two combining marks, and something like
// four is probably the most we will ever
// see (there are some very large stacks, but
// they occur in very specialized religious texts
// only). So we don't need any fancy sorting.
for (int i = 1; i < stack.length - 1; i++) {
for (int j = stack.length - 1; j > i; j--) {
if (getOrder (stack [j-1]) > getOrder (stack [j])) {
int temp = stack [j];
stack [j] = stack [j - 1];
stack [j - 1] = temp; }}}
for (int i = 0; i < stack.length; i++) {
stack [i] = otFont.getGlyphForChar (stack [i]); }
run.replace (positions, stack);
run.setElementStyle (start, limit, ElementAttribute.isGlyph, Boolean.TRUE);
}
protected int processStacks (AttributedRun run, int start, int limit, OpenTypeFont otFont)
throws InvalidFontException, UnsupportedFontException {
while (start < limit) {
if (run. getElementStyle (start, ElementAttribute.isGlyph) == Boolean.TRUE) {
start++;
continue; }
int usv = run.elementAt (start);
if (CharUtil.isControl (usv)) {
run.remove (start);
limit--;
continue; }
if (((Integer)run.getElementStyle (start, ElementAttribute.bidiLevel)).intValue () % 2 == 1) {
usv = UCharacter.getMirror (usv); }
int stackStart = start;
start++;
while (start < limit && CharUtil.isCombining (run.elementAt (start))) {
start++; }
processOneStack (run, stackStart, start, otFont); }
return limit;
}
//-------------------------------------------------------------- formatOT ---
protected boolean canFormatOT() {
return true;
}
protected int formatOT (OpenTypeFont otFont, AttributedRun run, int start, int limit, boolean shouldKern)
throws InvalidFontException, UnsupportedFontException, FontLoadingException {
// PRE: r.font [first, last] = one font
// r.direction [first, last] = one direction
// charRun is not defective, i.e. does not start in the
// middle of a default grapheme cluster
int scriptTag = getOTScriptTag ((Integer) run.getElementStyle (start, InFontFormatter.scriptAttribute));
int langTag = getOTLanguageTag ((ULocale) run.getElementStyle (start, ElementAttribute.locale));
limit = splitComposites (run, start, limit);
// Map characters to glyphs; simply skip existing glyphs
limit = processStacks (run, start, limit, otFont);
if (otFont.gsub != null) {
// Shape the glyphs
int[][] gsubLookups = LookupsCache.resolveFeatureTag (otFont.gsub, scriptTag, langTag, gsubFeatures);
limit = otFont.gsub.applyLookups (gsubLookups [0], run, start, limit, OTSelectors.everywhere, otFont.gdef); //ccmp
limit = otFont.gsub.applyLookups (gsubLookups [1], run, start, limit, OTSelectors.everywhere, otFont.gdef); //locl
limit = otFont.gsub.applyLookups (gsubLookups [2], run, start, limit, OTSelectors.everywhere, otFont.gdef); //blws
limit = otFont.gsub.applyLookups (gsubLookups [3], run, start, limit, OTSelectors.everywhere, otFont.gdef); } //abvs
// Position the glyphs
posFromAdvanceWidth (run, otFont, start, limit);
if (otFont.gpos != null) {
int[][] gposLookups = LookupsCache.resolveFeatureTag (otFont.gpos, scriptTag, langTag, gposFeatures);
limit = otFont.gpos.applyLookups (gposLookups [0], run, start, limit, OTSelectors.everywhere, otFont.gdef); // blwm
limit = otFont.gpos.applyLookups (gposLookups [1], run, start, limit, OTSelectors.everywhere, otFont.gdef); // abvm
if (shouldKern)
{
if (gposLookups[2].length != 0)
{
limit = otFont.gpos.applyLookups (gposLookups [2], run, start, limit, OTSelectors.everywhere, otFont.gdef); } // kern
} else {
applyKernTable(otFont, run, start, limit);
}
}
return limit;
}
private static final int[] gsubFeatures = {
Tag.feature_ccmp, //0
Tag.feature_locl, //1
Tag.feature_blws, //2
Tag.feature_abvs };//3
private static final int[] gposFeatures = {
Tag.feature_blwm,
Tag.feature_abvm,
Tag.feature_kern};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy