All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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