123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- /* $Id$ */
-
- package org.apache.fop.complexscripts.fonts;
-
- import java.nio.IntBuffer;
- import java.util.ArrayList;
- import java.util.List;
-
- import org.apache.fop.complexscripts.util.GlyphSequence;
- import org.apache.fop.complexscripts.util.ScriptContextTester;
-
- // CSOFF: LineLengthCheck
-
- /**
- * <p>The <code>GlyphSubstitutionState</code> implements an state object used during glyph substitution
- * processing.</p>
- *
- * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
- */
-
- public class GlyphSubstitutionState extends GlyphProcessingState {
-
- /** alternates index */
- private int[] alternatesIndex;
- /** current output glyph sequence */
- private IntBuffer ogb;
- /** current output glyph to character associations */
- private List oal;
- /** character association predications */
- private boolean predications;
-
- /**
- * Construct default (reset) glyph substitution state.
- */
- public GlyphSubstitutionState() {
- }
-
- /**
- * Construct glyph substitution state.
- * @param gs input glyph sequence
- * @param script script identifier
- * @param language language identifier
- * @param feature feature identifier
- * @param sct script context tester (or null)
- */
- public GlyphSubstitutionState(GlyphSequence gs, String script, String language, String feature, ScriptContextTester sct) {
- super(gs, script, language, feature, sct);
- this.ogb = IntBuffer.allocate(gs.getGlyphCount());
- this.oal = new ArrayList(gs.getGlyphCount());
- this.predications = gs.getPredications();
- }
-
- /**
- * Construct glyph substitution state using an existing state object using shallow copy
- * except as follows: input glyph sequence is copied deep except for its characters array.
- * @param ss existing positioning state to copy from
- */
- public GlyphSubstitutionState(GlyphSubstitutionState ss) {
- super(ss);
- this.ogb = IntBuffer.allocate(indexLast);
- this.oal = new ArrayList(indexLast);
- }
-
- /**
- * Reset glyph substitution state.
- * @param gs input glyph sequence
- * @param script script identifier
- * @param language language identifier
- * @param feature feature identifier
- * @param sct script context tester (or null)
- */
- public GlyphSubstitutionState reset(GlyphSequence gs, String script, String language, String feature, ScriptContextTester sct) {
- super.reset(gs, script, language, feature, sct);
- this.alternatesIndex = null;
- this.ogb = IntBuffer.allocate(gs.getGlyphCount());
- this.oal = new ArrayList(gs.getGlyphCount());
- this.predications = gs.getPredications();
- return this;
- }
-
- /**
- * Set alternates indices.
- * @param alternates array of alternates indices ordered by coverage index
- */
- public void setAlternates(int[] alternates) {
- this.alternatesIndex = alternates;
- }
-
- /**
- * Obtain alternates index associated with specified coverage index. An alternates
- * index is used to select among stylistic alternates of a glyph at a particular
- * coverage index. This information must be provided by the document itself (in the
- * form of an extension attribute value), since a font has no way to determine which
- * alternate the user desires.
- * @param ci coverage index
- * @return an alternates index
- */
- public int getAlternatesIndex(int ci) {
- if (alternatesIndex == null) {
- return 0;
- } else if ((ci < 0) || (ci > alternatesIndex.length)) {
- return 0;
- } else {
- return alternatesIndex [ ci ];
- }
- }
-
- /**
- * Put (write) glyph into glyph output buffer.
- * @param glyph to write
- * @param a character association that applies to glyph
- * @param predication a predication value to add to association A if predications enabled
- */
- public void putGlyph(int glyph, GlyphSequence.CharAssociation a, Object predication) {
- if (!ogb.hasRemaining()) {
- ogb = growBuffer(ogb);
- }
- ogb.put(glyph);
- if (predications && (predication != null)) {
- a.setPredication(feature, predication);
- }
- oal.add(a);
- }
-
- /**
- * Put (write) array of glyphs into glyph output buffer.
- * @param glyphs to write
- * @param associations array of character associations that apply to glyphs
- * @param predication optional predicaion object to be associated with glyphs' associations
- */
- public void putGlyphs(int[] glyphs, GlyphSequence.CharAssociation[] associations, Object predication) {
- assert glyphs != null;
- assert associations != null;
- assert associations.length >= glyphs.length;
- for (int i = 0, n = glyphs.length; i < n; i++) {
- putGlyph(glyphs [ i ], associations [ i ], predication);
- }
- }
-
- /**
- * Obtain output glyph sequence.
- * @return newly constructed glyph sequence comprised of original
- * characters, output glyphs, and output associations
- */
- public GlyphSequence getOutput() {
- int position = ogb.position();
- if (position > 0) {
- ogb.limit(position);
- ogb.rewind();
- return new GlyphSequence(igs.getCharacters(), ogb, oal);
- } else {
- return igs;
- }
- }
-
- /**
- * Apply substitution subtable to current state at current position (only),
- * resulting in the consumption of zero or more input glyphs, and possibly
- * replacing the current input glyphs starting at the current position, in
- * which case it is possible that indexLast is altered to be either less than
- * or greater than its value prior to this application.
- * @param st the glyph substitution subtable to apply
- * @return true if subtable applied, or false if it did not (e.g., its
- * input coverage table did not match current input context)
- */
- public boolean apply(GlyphSubstitutionSubtable st) {
- assert st != null;
- updateSubtableState(st);
- boolean applied = st.substitute(this);
- return applied;
- }
-
- /**
- * Apply a sequence of matched rule lookups to the <code>nig</code> input glyphs
- * starting at the current position. If lookups are non-null and non-empty, then
- * all input glyphs specified by <code>nig</code> are consumed irregardless of
- * whether any specified lookup applied.
- * @param lookups array of matched lookups (or null)
- * @param nig number of glyphs in input sequence, starting at current position, to which
- * the lookups are to apply, and to be consumed once the application has finished
- * @return true if lookups are non-null and non-empty; otherwise, false
- */
- public boolean apply(GlyphTable.RuleLookup[] lookups, int nig) {
- // int nbg = index;
- int nlg = indexLast - (index + nig);
- int nog = 0;
- if ((lookups != null) && (lookups.length > 0)) {
- // apply each rule lookup to extracted input glyph array
- for (int i = 0, n = lookups.length; i < n; i++) {
- GlyphTable.RuleLookup l = lookups [ i ];
- if (l != null) {
- GlyphTable.LookupTable lt = l.getLookup();
- if (lt != null) {
- // perform substitution on a copy of previous state
- GlyphSubstitutionState ss = new GlyphSubstitutionState(this);
- // apply lookup table substitutions
- GlyphSequence gs = lt.substitute(ss, l.getSequenceIndex());
- // replace current input sequence starting at current position with result
- if (replaceInput(0, -1, gs)) {
- nog = gs.getGlyphCount() - nlg;
- }
- }
- }
- }
- // output glyphs and associations
- putGlyphs(getGlyphs(0, nog, false, null, null, null), getAssociations(0, nog, false, null, null, null), null);
- // consume replaced input glyphs
- consume(nog);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Apply default application semantices; namely, consume one input glyph,
- * writing that glyph (and its association) to the output glyphs (and associations).
- */
- public void applyDefault() {
- super.applyDefault();
- int gi = getGlyph();
- if (gi != 65535) {
- putGlyph(gi, getAssociation(), null);
- }
- }
-
- private static IntBuffer growBuffer(IntBuffer ib) {
- int capacity = ib.capacity();
- int capacityNew = capacity * 2;
- IntBuffer ibNew = IntBuffer.allocate(capacityNew);
- ib.rewind();
- return ibNew.put(ib);
- }
-
- }
|