
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