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

com.adobe.fontengine.inlineformatting.infontformatting.BaseFormatter Maven / Gradle / Ivy

/*
 * File: BaseFormatter.java
 * 
 *	ADOBE CONFIDENTIAL
 *	___________________
 *
 *	Copyright 2004-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 java.util.HashMap;
import java.util.Map;

import com.adobe.agl.lang.UScript;
import com.adobe.agl.util.LocaleData;
import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.CharUtil;
import com.adobe.fontengine.font.Font;
import com.adobe.fontengine.font.FontData;
import com.adobe.fontengine.font.FontImpl;
import com.adobe.fontengine.font.FontLoadingException;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.InvalidGlyphException;
import com.adobe.fontengine.font.Rect;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.opentype.OpenTypeFont;
import com.adobe.fontengine.font.opentype.Tag;
import com.adobe.fontengine.font.type1.Type1Font;
import com.adobe.fontengine.inlineformatting.AttributedRun;
import com.adobe.fontengine.inlineformatting.ElementAttribute;

public class BaseFormatter {

  public int firstPass (AttributedRun run, int start, int limit) {
    return limit;
  }
  
  public int canRenderWithNotdef (AttributedRun run, int start, int limit)
  throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    
    int usv = run.elementAt (start);
    
    if (CharUtil.isControl (usv)) {
      return 1; }
    
    if (   ! CharUtil.isBase (usv) 
        || start + 1 == limit
        || run.getElementStyle (start + 1, ElementAttribute.isGlyph) == Boolean.TRUE
        || ! CharUtil.isCombining (run.elementAt (start + 1))) {
      // common case: a single character, the only solution is to map it
      return 1; }
    
    int graphemeLimit = start + 1;
    while (   graphemeLimit < limit 
        && run.getElementStyle (graphemeLimit, ElementAttribute.isGlyph) != Boolean.TRUE
        && CharUtil.isCombining (run.elementAt (graphemeLimit))) {
      graphemeLimit++; }  
    
    return graphemeLimit - start;
  }

  
  public int canRenderWithFont (FontData fontData, AttributedRun run, int start, int limit)
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
	  
	  if (shouldFormatOT(fontData)){
		  if (!canFormatOT())
			  return 0;
	  } else if (shouldFormatTT(fontData)) {
		  if (!canFormatTT())
			  return 0;
	  } else if (shouldFormatT1(fontData)) {
		  if (!canFormatT1())
			  return 0;
	  } else {
		  if (!canFormatGeneric())
			  return 0;
	  }
    
    int usv = run.elementAt (start);
    
    if (CharUtil.isControl (usv) && ! fontData.isSymbolic ()) {
      return 1; }
    
    if (   ! CharUtil.isBase (usv) 
        || start + 1 == limit
        || run.getElementStyle (start + 1, ElementAttribute.isGlyph) == Boolean.TRUE
        || ! CharUtil.isCombining (run.elementAt (start + 1))) {
      // common case: a single character, the only solution is to map it
      int gid = fontData.getGlyphForChar (usv);
      return (gid == 0) ? 0 : 1; }
    
    int graphemeLimit = start + 1;
    while (   graphemeLimit < limit 
        && run.getElementStyle (graphemeLimit, ElementAttribute.isGlyph) != Boolean.TRUE
        && CharUtil.isCombining (run.elementAt (graphemeLimit))) {
      graphemeLimit++; }
    
    boolean directMappingHasNotdef = false;
    int[] usvs = new int [graphemeLimit - start];
    int[] gids = new int [graphemeLimit - start];
    
    for (int i = start; i < graphemeLimit; i++) {
      usvs [i - start] = run.elementAt (i);
      int gid = fontData.getGlyphForChar (usvs [i - start]);
      if (gid == 0) {
        directMappingHasNotdef = true; }
      gids [i - start] = gid; }
    
    if (directMappingHasNotdef) {
      int usvc = CharUtil.compose (usvs, 0, graphemeLimit - start);
      if (usvc != -1) {
        int gid = fontData.getGlyphForChar (usvc);
        if (gid != 0) {
          return graphemeLimit - start; }}
      
      return 0; }
    
    else {
      return graphemeLimit - start; }
  }
  
  //---------------------------------------------------------------- format ---
  
  //---------------------------------------------------Format OT
  /**
   * Given a font, should OpenType layout be used?
   */
  protected boolean shouldFormatOT(FontData fontData) {
	  if (fontData instanceof OpenTypeFont) {
	        OpenTypeFont otFont = (OpenTypeFont) fontData;
	        return (otFont.gpos != null || otFont.gsub != null);
	  }
	  return false;
  }
	  
  /**
   * Does this formatter implement OpenType layout?
   */
  protected boolean canFormatOT() {
	  return false;
  }
 
  protected int formatOT (OpenTypeFont otFont, AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    throw new UnsupportedFontException ();
  }
  
  //--------------------------------------------------Format TT
  /**
   * Given a font, should legacy truetype layout be used?
   */
  protected boolean shouldFormatTT(FontData fontData)
  {
	  if (fontData instanceof OpenTypeFont) {
	        OpenTypeFont otFont = (OpenTypeFont) fontData;
	        return (otFont.gpos == null && otFont.gsub == null);
	  }
	  return false;
  }
  
  /**
   * Does this formatter implement legacy truetype layout?
   */
  protected boolean canFormatTT() {
	  return false;
  }
  
  protected int formatTT (OpenTypeFont otFont, AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    throw new UnsupportedFontException ();
  }

  //------------------------------------------------Format T1
  /**
   * Given a font, should Type1 layout be used?
   */
  protected boolean shouldFormatT1(FontData fontData)
  {
	  return (fontData instanceof Type1Font);
  }
  
  /**
   * Does this formatter implement Type1 layout?
   */
  protected boolean canFormatT1() {
	  return false;
  }
  
  protected int formatT1 (Type1Font t1Font, AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    throw new UnsupportedFontException ();
  }

  //----------------------------------------------Format Generic
  /**
   * Given a font, should generic layout be used?
   */
  protected boolean shouldFormatGeneric(FontData fontData)
  {
	  return (!(fontData instanceof Type1Font || fontData instanceof OpenTypeFont));
  }
  
  /**
   * Does this formatter implement generic layout?
   */
  protected boolean canFormatGeneric() {
	  return false;
  }
  
  protected int formatGeneric (FontData fontData, AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    throw new UnsupportedFontException ();
  }

  
  public int format (AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
        
    while (start < limit) {
      int fontLimit = run.getSubrunLimit (start, limit, InFontFormatter.fontAtts);
      int newFontLimit;
     
      Font font = (Font) run.getElementStyle (start, ElementAttribute.font);
      FontData fontData = ((FontImpl) font).getFontData();
      
      
      if (shouldFormatOT(fontData)) {
          newFontLimit = formatOT ((OpenTypeFont)fontData, run, start, fontLimit, shouldKern); }
       else if (shouldFormatTT(fontData)) {
          newFontLimit = formatTT ((OpenTypeFont)fontData, run, start, fontLimit, shouldKern); }
      
      else if (shouldFormatT1(fontData)) {
        Type1Font t1Font = (Type1Font) fontData;
        newFontLimit = formatT1 (t1Font, run, start, fontLimit, shouldKern); }
      
      else {
        newFontLimit = formatGeneric (fontData, run, start, fontLimit, shouldKern); } 
      
      start = newFontLimit;
      limit += (newFontLimit - fontLimit); }
    
    return limit;
  }

  //---------------------------------------------------------------------------
  public void posFromAdvanceWidth (AttributedRun run, FontData fontData, int first, int limit)
      throws InvalidFontException, UnsupportedFontException, InvalidGlyphException {
    
    run.startWorkingWithPositions (first, limit);
    
    for (int i = first; i < limit; i++) {
    	// ensure that we have no virtual glyphs at this point
    	int gid = run.elementAt (i);
    	if (gid > fontData.getNumGlyphs ()) {
    		throw new InvalidFontException ("gid " + gid
    				+ " is not a valid gid (numGlyphs = " + fontData.getNumGlyphs() + ")"); }
    	double ascent=0;
    	double descent = 0;
    	Rect bbox =fontData.getCoolTypeGlyphBBox(gid);

    	ascent = bbox.ymax;
    	descent = bbox.ymin;
    	run.setElementPlacementAndAdvance (i, 0, 0,
    			fontData.getHorizontalAdvance (gid), 0); 
    	run.setElementAscentAndDescent(i, ascent,descent);
    }
  }

  protected void applyKernTable(OpenTypeFont otFont, AttributedRun run, int start, int limit) 
  throws InvalidFontException, UnsupportedFontException
  {
	  if (otFont.kern == null)
	  {
		  return;
	  }

	  for (int i = start; i < limit - 1; i++) 
	  {
		  int[] kernVector = otFont.kern.getKernVector (run.elementAt (i), run.elementAt (i+1));
		  run.adjustPlacementAndAdvance (i, 0, 0, kernVector [0], kernVector [1]); 
	  }	 
  }

  private final static Map /**/ otScriptMap;
  static {
    otScriptMap = new HashMap /**/ ();
    
    // These pairs come straight from the OT 1.4 spec.
    
    otScriptMap.put (new Integer (UScript.ARABIC),              new Integer (Tag.script_arab));
    otScriptMap.put (new Integer (UScript.ARMENIAN),            new Integer (Tag.script_armn));
    otScriptMap.put (new Integer (UScript.BENGALI),             new Integer (Tag.script_beng));
    otScriptMap.put (new Integer (UScript.BOPOMOFO),            new Integer (Tag.script_bopo));
    otScriptMap.put (new Integer (UScript.BRAILLE),             new Integer (Tag.script_brai));
    otScriptMap.put (new Integer (UScript.CANADIAN_ABORIGINAL), new Integer (Tag.script_cans));
    otScriptMap.put (new Integer (UScript.CHEROKEE),            new Integer (Tag.script_cher));
    otScriptMap.put (new Integer (UScript.CYRILLIC),            new Integer (Tag.script_cyrl));
    otScriptMap.put (new Integer (UScript.DEVANAGARI),          new Integer (Tag.script_deva));
    otScriptMap.put (new Integer (UScript.ETHIOPIC),            new Integer (Tag.script_ethi));
    otScriptMap.put (new Integer (UScript.GEORGIAN),            new Integer (Tag.script_geor));
    otScriptMap.put (new Integer (UScript.GREEK),               new Integer (Tag.script_grek));
    otScriptMap.put (new Integer (UScript.GUJARATI),            new Integer (Tag.script_gujr));
    otScriptMap.put (new Integer (UScript.GURMUKHI),            new Integer (Tag.script_guru));
    otScriptMap.put (new Integer (UScript.HAN),                 new Integer (Tag.script_hani));
    otScriptMap.put (new Integer (UScript.HANGUL),              new Integer (Tag.script_hang));
    otScriptMap.put (new Integer (UScript.HEBREW),              new Integer (Tag.script_hebr));
    otScriptMap.put (new Integer (UScript.HIRAGANA),            new Integer (Tag.script_kana));
    otScriptMap.put (new Integer (UScript.KANNADA),             new Integer (Tag.script_knda));
    otScriptMap.put (new Integer (UScript.KATAKANA),            new Integer (Tag.script_kana));
    otScriptMap.put (new Integer (UScript.KHMER),               new Integer (Tag.script_khmr));
    otScriptMap.put (new Integer (UScript.LAO),                 new Integer (Tag.script_lao));
    otScriptMap.put (new Integer (UScript.LATIN),               new Integer (Tag.script_latn));
    otScriptMap.put (new Integer (UScript.MALAYALAM),           new Integer (Tag.script_mlym));
    otScriptMap.put (new Integer (UScript.MONGOLIAN),           new Integer (Tag.script_mong));
    otScriptMap.put (new Integer (UScript.MYANMAR),             new Integer (Tag.script_mymr));
    otScriptMap.put (new Integer (UScript.OGHAM),               new Integer (Tag.script_ogam));
    otScriptMap.put (new Integer (UScript.ORIYA),               new Integer (Tag.script_orya));
    otScriptMap.put (new Integer (UScript.RUNIC),               new Integer (Tag.script_runr));
    otScriptMap.put (new Integer (UScript.SINHALA),             new Integer (Tag.script_sinh));
    otScriptMap.put (new Integer (UScript.SYRIAC),              new Integer (Tag.script_syrc));
    otScriptMap.put (new Integer (UScript.TAMIL),               new Integer (Tag.script_taml));
    otScriptMap.put (new Integer (UScript.TELUGU),              new Integer (Tag.script_telu));
    otScriptMap.put (new Integer (UScript.THAANA),              new Integer (Tag.script_thaa));
    otScriptMap.put (new Integer (UScript.THAI),                new Integer (Tag.script_thai));
    otScriptMap.put (new Integer (UScript.TIBETAN),             new Integer (Tag.script_tibt));
    otScriptMap.put (new Integer (UScript.YI),                  new Integer (Tag.script_yi));


    // This is not listed explicitly in the OT spec, but is obviously needed:
    
    otScriptMap.put (new Integer (UScript.KATAKANA_OR_HIRAGANA), new Integer (Tag.script_kana));

    // [Watson 1110147]
    // The OT spec lists the OT script 'byzm' for Byzantine Music,
    // but there is no such script in Unicode: the characters in the 
    // Byzantine Musical Symbol block have the script Zyyy (Common). 
    // So those characters will be treated by the DFLT script if they
    // have not be resolved to another script.
    // As a side note, the characters in the Musical Symbol block also
    // have the script Zyyy, but there is no OpenType tag for those.
     
    // [Watson 1110152]
    // The OT spec also lists a tag 'jamo'. This does not really correspond to
    // a script, but rather to a block. Furthermore, constrasting that block
    // with the Hangul syllable block is very probablematic, as all the hangul
    // syllables have canonical decompositions into the jamos!
    
    // [Watson 1110141]
    // The OT spec does not provide tags for the following scripts:
    // Buhid
    // Cypriot
    // Deseret
    // Hanunoo
    // Old Italic
    // Limbu
    // Linear_B
    // Osmanya
    // Shavian
    // Tagbanwa
    // Tai_Le
    // Tagalog
    // Ugaritic
  }
    
  /** Return the OpenType script tag to use for a given Unicode script. */
  static int getOTScriptTag (Integer uscript) {
    Integer i = (Integer) otScriptMap.get (uscript);
    if (i != null) {
      return i.intValue (); }
    else {
      return Tag.script_DFLT; }
  }
  

  static int getOTLanguageTag (ULocale locale) {
  	int langTag = LocaleData.getOpenTypeData (locale).getLanguageTag ();
  	if (langTag == 0) {
  		langTag = Tag.language_ENG;
  		/*System.err.println ("defaulting to ENG for " + locale);*/ }
    
    return langTag;
  }  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy