
com.adobe.fontengine.inlineformatting.PDF16PlainTextFormatter Maven / Gradle / Ivy
/*
* File: PDF16PlainTextFormatter.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;
import java.util.Iterator;
import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.CharUtil;
import com.adobe.fontengine.font.Base14;
import com.adobe.fontengine.font.Font;
import com.adobe.fontengine.font.FontData;
import com.adobe.fontengine.font.FontException;
import com.adobe.fontengine.font.FontImpl;
import com.adobe.fontengine.fontmanagement.postscript.PostscriptFontDescription;
import com.adobe.fontengine.inlineformatting.infontformatting.InFontFormatter;
import com.adobe.fontengine.inlineformatting.infontformatting.ZapfDingbatsEncoding;
/**
* Inline formatter for PDF 1.6 plain text form fields.
*
* The client must first pass a run corresponding to a whole paragraph to the
* {@link #preFormat} method. It can then pass fragments of the run to the
* {@link #format(AttributedRun, int, int, boolean)} or {@link #format(AttributedRun, int, int, boolean, boolean)} method.
*/
final public class PDF16PlainTextFormatter
{
private final FallbackFontSet fallbackFontSet;
private PDF16PlainTextFormatter (FallbackFontSet fallbackFontSet) {
// all instances created view getFormatterInstance ()
this.fallbackFontSet = fallbackFontSet;
}
/**
* Create a PDF16PlainTextFormatter for formatting text.
*
*
Concurrency
*
* The PDF16PlainTextFormatter instance that is returned from this
* method is not in general thread safe.
*
* @param fallbackFontSet the fonts to use for character fallback
* @return A PDF16PlainTextFormatter to be used for formatting text
*/
public static PDF16PlainTextFormatter getFormatterInstance (FallbackFontSet fallbackFontSet) {
return new PDF16PlainTextFormatter (fallbackFontSet);
}
/** Interelement attribute to mark comb boundaries.
* The value of this attribute is a {@link Boolean}. The preceding and
* following elements should be in the same comb iff this attribute
* has the value {@link Boolean#FALSE}
*/
final public static InterElementAttribute newComb
= new InterElementAttribute ("newComb");
/**
* Preformat an {@link AttributedRun}.
*
* This method should be called on a portion of an AttributedRun
* corresponding to a whole paragraph, before the {@link #format(AttributedRun, int, int, boolean)}
* or {@link #format(AttributedRun, int, int, boolean, boolean)} method.
*
* @param run an AttributedRun that contains the text to be formatted
* @param start the index in the AttributedRun to start formatting from
* @param limit the index in the AttributedRun at which formatting should cease (one
* more than the last position that formatting should done to)
* @return The new limit of the original range in the AttributedRun after the formatting operation.
*/
public int preFormat (AttributedRun run, int start, int limit)
throws FontException, FormattingException {
limit = InFontFormatter.preFormat (run, start, limit);
return limit;
}
/**
* Format an {@link AttributedRun} by resolving the styling constraints
* to glyphs and positions for those glyphs.
*
* This method should be called after the {@link #preFormat} method.
*
*
* On input:
*
*
* - each element must be a character, i.e. must have the
* {@link ElementAttribute#isGlyph} attribute set to {@link Boolean#FALSE}
*
*
- each element must have {@link ElementAttribute#locale} set
*
*
- each element must have {@link ElementAttribute#bidiLevel} set
*
*
- each element must have {@link ElementAttribute#font} set to the
* desired font
*
*
- each element must have {@link ElementAttribute#pointSize} set to
* the desired point size
*
*
- each character element can have {@link ElementAttribute#fontStyle} set;
* if not set, equivalent to {@link FontStyle#NORMAL}
*
*
- each character element can have {@link ElementAttribute#typographicCase} set;
* if not set, interpreted as {@link TypographicCase#NONE}.
*
*
- each character element can have {@link ElementAttribute#digitCase} set;
* if not set, equivalent to {@link DigitCase#DEFAULT}
*
*
- each character element can have {@link ElementAttribute#digitWidth} set;
* if not set, equivalent to {@link DigitWidth#DEFAULT}
*
*
- each interelement can have {@link InterElementAttribute#ligatureLevel} set;
* if not set, equivalent to {@link LigatureLevel#COMMON}
*
*
*
*
* At some point during formatting,
* {@link AttributedRun#startWorkingWithPositions startWorkingWithPositions}
* will be called on the run.
*
*
* On output:
*
* - each element in the run will be a glyph, i.e.
* {@link ElementAttribute#isGlyph} will be {@link Boolean#TRUE}
*
*
- each element will have a placement and advance vector
*
*
- each element will have {@link ElementAttribute#font} set to the
* actual font to use
*
*
- each element will have {@link ElementAttribute#pointSize} set to
* the actual point size to use
*
*
- if
onComb
is true, then each interelement will have
* the {@link #newComb} attribute set
*
*
* @param run an AttributedRun that contains the text to be formatted
* @param start the index in the AttributedRun to start formatting from
* @param limit the index in the AttributedRun at which formatting should cease (one
* more than the last position that formatting should done to)
* @param onComb true iff the attributed run is displayed in a comb
*
* @return The new limit of the original range in the AttributedRun after the formatting operation.
* @throws FontException
* @throws FormattingException
*/
public int format (AttributedRun run, int start, int limit, boolean onComb)
throws FontException, FormattingException
{
return format(run, start, limit, onComb, true /*kern*/);
}
/**
* Format an {@link AttributedRun} by resolving the styling constraints
* to glyphs and positions for those glyphs.
*
* This method should be called after the {@link #preFormat} method.
*
*
* On input:
*
*
* - each element must be a character, i.e. must have the
* {@link ElementAttribute#isGlyph} attribute set to {@link Boolean#FALSE}
*
*
- each element must have {@link ElementAttribute#locale} set
*
*
- each element must have {@link ElementAttribute#bidiLevel} set
*
*
- each element must have {@link ElementAttribute#font} set to the
* desired font
*
*
- each element must have {@link ElementAttribute#pointSize} set to
* the desired point size
*
*
- each character element can have {@link ElementAttribute#fontStyle} set;
* if not set, equivalent to {@link FontStyle#NORMAL}
*
*
- each character element can have {@link ElementAttribute#typographicCase} set;
* if not set, interpreted as {@link TypographicCase#NONE}.
*
*
- each character element can have {@link ElementAttribute#digitCase} set;
* if not set, equivalent to {@link DigitCase#DEFAULT}
*
*
- each character element can have {@link ElementAttribute#digitWidth} set;
* if not set, equivalent to {@link DigitWidth#DEFAULT}
*
*
- each interelement can have {@link InterElementAttribute#ligatureLevel} set;
* if not set, equivalent to {@link LigatureLevel#COMMON}
*
*
*
*
* At some point during formatting,
* {@link AttributedRun#startWorkingWithPositions startWorkingWithPositions}
* will be called on the run.
*
*
* On output:
*
* - each element in the run will be a glyph, i.e.
* {@link ElementAttribute#isGlyph} will be {@link Boolean#TRUE}
*
*
- each element will have a placement and advance vector
*
*
- each element will have {@link ElementAttribute#font} set to the
* actual font to use
*
*
- each element will have {@link ElementAttribute#pointSize} set to
* the actual point size to use
*
*
- if
onComb
is true, then each interelement will have
* the {@link #newComb} attribute set
*
*
* @param run an AttributedRun that contains the text to be formatted
* @param start the index in the AttributedRun to start formatting from
* @param limit the index in the AttributedRun at which formatting should cease (one
* more than the last position that formatting should done to)
* @param onComb true iff the attributed run is displayed in a comb
* @param shouldKern whether or not kerning should be applied to the glyphs
* @return The new limit of the original range in the AttributedRun after the formatting operation.
* @throws FontException
* @throws FormattingException
*/
public int format (AttributedRun run, int start, int limit, boolean onComb, boolean shouldKern)
throws FontException, FormattingException
{
if (start >= limit) {
return limit; }
Font desiredFont = (Font) run.getElementStyle (start, ElementAttribute.font);
//------------------------------------------------ Adobe Pi Std handling ---
if (desiredFont != null) {
PostscriptFontDescription[] fd = desiredFont.getPostscriptFontDescription ();
for (int i = 0; i < fd.length; i++) {
if ("AdobePiStd".equals (fd [i].getPSName ())) {
ZapfDingbatsEncoding.remap (run, start, limit);
break; }}}
//----------------------------------------------------------- first pass ---
limit = InFontFormatter.firstPass (run, start, limit);
//------------------------------------------------------- font selection ---
ULocale locale = (ULocale) run.getElementStyle (start, ElementAttribute.locale);
if (desiredFont == null) {
Iterator it = fallbackFontSet.getFallbackFonts (locale);
if (it.hasNext ()) {
desiredFont = (Font) it.next (); }
else {
// no font to format and no font in fallback set
// it may be slightly better to go with a font that only contains .notdeff
desiredFont = Base14.courierRegular; }}
FontData desiredFontData = ((FontImpl) desiredFont).getFontData ();
Font tentativeFont = null;
try {
int s = start;
while (s < limit) {
int consumed;
// try the desired font
tentativeFont = desiredFont;
consumed = InFontFormatter.canRenderWithFont (desiredFontData, run, s, limit);
// try the fallback fonts
if (consumed == 0) {
Iterator it = fallbackFontSet.getFallbackFonts (locale);
while (consumed == 0 && it.hasNext ()) {
tentativeFont = (Font) it.next();
consumed = InFontFormatter.canRenderWithFont (((FontImpl) tentativeFont).getFontData (), run, s, limit); }}
// ok, no way to avoid .notdef, just use the desired font
if (consumed == 0) {
tentativeFont = desiredFont;
consumed = InFontFormatter.canRenderWithNotdef (run, s, limit); }
// at this point, c > 0, ensured by canRenderWithNotdef postcondition
run.setElementStyle (s, s + consumed, ElementAttribute.font, tentativeFont);
s += consumed; }}
catch (FontException e) {
e.initFont (tentativeFont);
throw e; }
//--------------------------------------------------------------------------
if (onComb) {
run.setInterElementStyleBefore (start, newComb, Boolean.TRUE);
int graphemeStart = start;
int i = start + 1;
while (i < limit) {
if (! CharUtil.isCombining (run.elementAt (i))) {
run.setInterElementStyleBefore (i, newComb, Boolean.TRUE);
int newI = InFontFormatter.format (run, graphemeStart, i, shouldKern);
limit += (newI - i);
graphemeStart = newI;
i = newI + 1; }
else {
run.setInterElementStyleBefore (i, newComb, Boolean.FALSE);
i++; }}
return InFontFormatter.format (run, graphemeStart, limit, shouldKern); }
else {
return InFontFormatter.format (run, start, limit, shouldKern); }
}
}