
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