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

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

/*
*
*	File: GenericFormatter.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 com.adobe.agl.lang.UCharacter;
import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.CharUtil;
import com.adobe.fontengine.font.FontData;
import com.adobe.fontengine.font.FontLoadingException;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.font.opentype.OTSelector;
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.font.type1.Type1Font;
import com.adobe.fontengine.inlineformatting.AttributedRun;
import com.adobe.fontengine.inlineformatting.DigitCase;
import com.adobe.fontengine.inlineformatting.DigitWidth;
import com.adobe.fontengine.inlineformatting.ElementAttribute;
import com.adobe.fontengine.inlineformatting.FontStyle;
import com.adobe.fontengine.inlineformatting.InterElementAttribute;
import com.adobe.fontengine.inlineformatting.LigatureLevel;
import com.adobe.fontengine.inlineformatting.TypographicCase;

class GenericFormatter extends BaseFormatter {
  

  protected int setGlyphs (AttributedRun run, int start, int limit, FontData fontData) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {

    while (start < limit) {
      if (run. getElementStyle (start, ElementAttribute.isGlyph) == Boolean.TRUE) {
        start++;
        continue; }
      
      int usv = run.elementAt (start);
      
      if (usv == 0x200D /* ZWJ */) {
        run.remove (start);
        limit--; 
        run.setInterElementStyleBefore (start,
            InterElementAttribute.ligatureLevel,
            LigatureLevel.EXOTIC);
        continue; }
      
      if (usv == 0x200C /* ZWNJ */) {
        run.remove (start);
        limit--; 
        run.setInterElementStyleBefore (start,
            InterElementAttribute.ligatureLevel,
            LigatureLevel.NONE);
        continue; }
      
      if (CharUtil.isControl (usv) && ! fontData.isSymbolic ()) {
        run.remove (start);
        limit--; 
        continue; }
      
      if (((Integer)run.getElementStyle (start, ElementAttribute.bidiLevel)).intValue () % 2 == 1) {      
        usv = UCharacter.getMirror (usv); }
      
      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
        int gid = fontData.getGlyphForChar (usv);
        run.replace (start, gid);
        run.setElementStyle (start, ElementAttribute.isGlyph, Boolean.TRUE);
        start++; 
        continue; }
      
      { 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) {
              run.replace (start, graphemeLimit, gid);
              run.setElementStyle (start, ElementAttribute.isGlyph, Boolean.TRUE);
              limit -= (graphemeLimit - start - 1); 
              start++; 
              continue; }}}
        
        for (int i = start; i < graphemeLimit; i++) {
          run.replace (i, gids [i - start]);
          run.setElementStyle (start, ElementAttribute.isGlyph, Boolean.TRUE); }
        start = graphemeLimit; }}
    
    return limit;
  }

  //---------------------------------------------------------- OT formatting ---
  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
    
    Integer bidiLevel = (Integer) run.getElementStyle (start, ElementAttribute.bidiLevel);
    int scriptTag = getOTScriptTag ((Integer) run.getElementStyle (start, InFontFormatter.scriptAttribute));
    int langTag = getOTLanguageTag ((ULocale) run.getElementStyle (start, ElementAttribute.locale));
    
    // Map characters to glyphs; simply skip existing glyphs
    limit = setGlyphs (run, start, limit, otFont);
    
    // Adjust the glyphs by GSUB
    if (otFont.gsub != null) {
    	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
    	if (bidiLevel.intValue () % 2 == 1) {
    		limit = otFont.gsub.applyLookups (gsubLookups [2], run, start, limit, OTSelectors.everywhere, otFont.gdef); } //rtla

    	limit = otFont.gsub.applyLookups (gsubLookups [6], run, start, limit, italSelector, otFont.gdef); // ital

    	limit = otFont.gsub.applyLookups (gsubLookups [7], run, start, limit, titlSelector, otFont.gdef); // titl
    	limit = otFont.gsub.applyLookups (gsubLookups [8], run, start, limit, caseSelector, otFont.gdef); // case
    	limit = otFont.gsub.applyLookups (gsubLookups [9], run, start, limit, lnumSelector, otFont.gdef); // lnum
    	limit = otFont.gsub.applyLookups (gsubLookups [10], run, start, limit, onumSelector, otFont.gdef); // onum
    	limit = otFont.gsub.applyLookups (gsubLookups [18], run, start, limit, pnumSelector, otFont.gdef); // pnum
    	limit = otFont.gsub.applyLookups (gsubLookups [19], run, start, limit, tnumSelector, otFont.gdef); // tnum
    	limit = otFont.gsub.applyLookups (gsubLookups [11], run, start, limit, c2scSelector, otFont.gdef); // c2sc
    	limit = otFont.gsub.applyLookups (gsubLookups [12], run, start, limit, smcpSelector, otFont.gdef); // smcp
    	limit = otFont.gsub.applyLookups (gsubLookups [13], run, start, limit, c2pcSelector, otFont.gdef); // c2pc
    	limit = otFont.gsub.applyLookups (gsubLookups [14], run, start, limit, pcapSelector, otFont.gdef); // pcap
    	limit = otFont.gsub.applyLookups (gsubLookups [15], run, start, limit, unicSelector, otFont.gdef); // unic

    	limit = otFont.gsub.applyLookups (gsubLookups [3], run, start, limit, OTSelectors.minimumLigatures, otFont.gdef); // rlig     
    	limit = otFont.gsub.applyLookups (gsubLookups [4], run, start, limit, OTSelectors.commonLigatures, otFont.gdef); // liga
    	limit = otFont.gsub.applyLookups (gsubLookups [5], run, start, limit, OTSelectors.commonLigatures, otFont.gdef); // clig
    	limit = otFont.gsub.applyLookups (gsubLookups [16], run, start, limit, OTSelectors.uncommonLigatures, otFont.gdef); // dlig
    	limit = otFont.gsub.applyLookups (gsubLookups [17], run, start, limit, OTSelectors.exoticLigatures, otFont.gdef); } // hlig

    // Position the glyphs by advance
    posFromAdvanceWidth (run, otFont, start, limit);

    // Adjust the positions by GPOS
    if (otFont.gpos != null) 
    {
    	int[][] gposLookups = LookupsCache.resolveFeatureTag (otFont.gpos, scriptTag, langTag, gposFeatures);

    	if (shouldKern)
    	{
    		if (gposLookups[0].length != 0)
    		{
    			limit = otFont.gpos.applyLookups (gposLookups [0], run, start, limit, OTSelectors.everywhere, otFont.gdef); // kern
    		} else {
    			applyKernTable(otFont, run, start, limit);
    		}
    	}
    	limit = otFont.gpos.applyLookups (gposLookups [3], run, start, limit, cpspSelector, otFont.gdef); // cpsp
    	limit = otFont.gpos.applyLookups (gposLookups [1], run, start, limit, OTSelectors.everywhere, otFont.gdef);   // mark
    	limit = otFont.gpos.applyLookups (gposLookups [2], run, start, limit, OTSelectors.everywhere, otFont.gdef);  // mkmk
    }
    else if (shouldKern) 
    {
    	applyKernTable(otFont, run, start, limit);
    }

    return limit;
  }
  
  private static final int[] gsubFeatures = {
      Tag.feature_ccmp, // 0
      Tag.feature_locl, // 1
      Tag.feature_rtla, // 2
      Tag.feature_rlig, // 3
      Tag.feature_liga, // 4
      Tag.feature_clig, // 5
      Tag.feature_ital, // 6
      Tag.feature_titl, // 7
      Tag.feature_case, // 8
      Tag.feature_lnum, // 9
      Tag.feature_onum, // 10
      Tag.feature_c2sc, // 11
      Tag.feature_smcp, // 12
      Tag.feature_c2pc, // 13
      Tag.feature_pcap, // 14
      Tag.feature_unic, // 15
      Tag.feature_dlig, // 16
      Tag.feature_hlig, // 17
      Tag.feature_pnum, // 18
      Tag.feature_tnum, // 19
  };
    
  private static final int[] gposFeatures = {
      Tag.feature_kern, // 0
      Tag.feature_mark, // 1
      Tag.feature_mkmk, // 2
      Tag.feature_cpsp, // 3
  };
  

  private static final OTSelector italSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.fontStyle);
      return (v == FontStyle.ITALIC || v == FontStyle.OBLIQUE);
    }
  };
    
  private static final OTSelector titlSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.TITLE);
    }
  };
    
  private static final OTSelector caseSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.TITLE || v == TypographicCase.CAPS);
    }
  };
      
  private static final OTSelector c2scSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.SMALLCAPS);
    }
  };
  
  private static final OTSelector smcpSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.SMALLCAPS || v == TypographicCase.CAPS_AND_SMALLCAPS);
    }
  };
  
  private static final OTSelector c2pcSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.PETITECAPS);
    }
  };
  
  private static final OTSelector pcapSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.PETITECAPS);
    }
  };
  
  private static final OTSelector unicSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.UNICASE);
    }
  };
  
  private static final OTSelector cpspSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.typographicCase);
      return (v == TypographicCase.TITLE || v == TypographicCase.CAPS);
    }
  };
  
  private static final OTSelector lnumSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.digitCase);
      if (v == DigitCase.FROM_TYPOGRAPHIC_CASE) {
        v = run.getElementStyle (position, ElementAttribute.typographicCase);
        return (v == TypographicCase.TITLE || v == TypographicCase.CAPS); }
      else {
        return (v == DigitCase.LINING); }
    }
  };
    
  private static final OTSelector onumSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.digitCase);
      if (v == DigitCase.FROM_TYPOGRAPHIC_CASE) {
        v = run.getElementStyle (position, ElementAttribute.typographicCase);
        return (   v == TypographicCase.TEXT 
                || v == TypographicCase.CAPS_AND_SMALLCAPS 
                || v == TypographicCase.SMALLCAPS
                || v == TypographicCase.PETITECAPS 
                || v == TypographicCase.UNICASE); }
      else {
        return (v == DigitCase.OLD_STYLE); }
    }
  };
  
  private static final OTSelector tnumSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.digitWidth);
      return v == DigitWidth.TABULAR;
    }
  };
  
  private static final OTSelector pnumSelector = new OTSelector () {
    public boolean isApplied (AttributedRun run, int position) {
      Object v = run.getElementStyle (position, ElementAttribute.digitWidth);
      return v == DigitWidth.PROPORTIONAL;
    }
  };
  
  //---------------------------------------------------------- TT formatting ---
        
  protected boolean canFormatTT() {
	  return true;
  }
  
  protected int formatTT (OpenTypeFont otFont, AttributedRun run, int start, int limit, boolean shouldKern)
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    
    // Map characters to glyphs; simply skip existing glyphs
    limit = setGlyphs (run, start, limit, otFont);
    
    // Position the glyphs by advance
    posFromAdvanceWidth (run, otFont, start, limit);
    
    if (shouldKern)
    {
    	applyKernTable(otFont, run, start, limit);
    }
    return limit;
  }

  //---------------------------------------------------------- T1 formatting ---
  protected boolean canFormatT1() {
	  return true;
  }
  
  protected int formatT1 (Type1Font t1Font, AttributedRun run, int start, int limit, boolean shouldKern) 
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {

    limit = setGlyphs (run, start, limit, t1Font);

    posFromAdvanceWidth (run, t1Font, start, limit);
    
    if (shouldKern)
    {
    	for (int i = start; i < limit - 1; i++) {
    		double kernValue = t1Font.getKernValue (run.elementAt (i), run.elementAt (i+1));
    		run.adjustPlacementAndAdvance (i, 0, 0, kernValue, 0); }
    }
    return limit;
  }
  
  //----------------------------------------------------- Generic formatting ---
  protected boolean canFormatGeneric() {
	  return true;
  }
  
  protected int formatGeneric (FontData fontData, AttributedRun run, int start, int limit, boolean shouldKern)
      throws InvalidFontException, UnsupportedFontException, FontLoadingException {
    
    limit = setGlyphs (run, start, limit, fontData);
    
    posFromAdvanceWidth (run, fontData, start, limit);
    
    return limit;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy