blob: 08c533860e6536c422a0b159c3f6455560337fbf [file] [log] [blame]
/*
* 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 org.apache.fop.complexscripts.util.GlyphSequence;
import org.apache.fop.complexscripts.util.ScriptContextTester;
// CSOFF: LineLengthCheck
/**
* <p>The <code>GlyphPositioningState</code> implements an state object used during glyph positioning
* processing.</p>
*
* <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
*/
public class GlyphPositioningState extends GlyphProcessingState {
/** font size */
private int fontSize;
/** default advancements */
private int[] widths;
/** current adjustments */
private int[][] adjustments;
/** if true, then some adjustment was applied */
private boolean adjusted;
/**
* Construct default (reset) glyph positioning state.
*/
public GlyphPositioningState() {
}
/**
* Construct glyph positioning state.
* @param gs input glyph sequence
* @param script script identifier
* @param language language identifier
* @param feature feature identifier
* @param fontSize font size (in micropoints)
* @param widths array of design advancements (in glyph index order)
* @param adjustments positioning adjustments to which positioning is applied
* @param sct script context tester (or null)
*/
public GlyphPositioningState(GlyphSequence gs, String script, String language, String feature, int fontSize, int[] widths, int[][] adjustments, ScriptContextTester sct) {
super(gs, script, language, feature, sct);
this.fontSize = fontSize;
this.widths = widths;
this.adjustments = adjustments;
}
/**
* Construct glyph positioning state using an existing state object using shallow copy
* except as follows: input glyph sequence is copied deep except for its characters array.
* @param ps existing positioning state to copy from
*/
public GlyphPositioningState(GlyphPositioningState ps) {
super(ps);
this.fontSize = ps.fontSize;
this.widths = ps.widths;
this.adjustments = ps.adjustments;
}
/**
* Reset glyph positioning state.
* @param gs input glyph sequence
* @param script script identifier
* @param language language identifier
* @param feature feature identifier
* @param fontSize font size (in micropoints)
* @param widths array of design advancements (in glyph index order)
* @param adjustments positioning adjustments to which positioning is applied
* @param sct script context tester (or null)
*/
public GlyphPositioningState reset(GlyphSequence gs, String script, String language, String feature, int fontSize, int[] widths, int[][] adjustments, ScriptContextTester sct) {
super.reset(gs, script, language, feature, sct);
this.fontSize = fontSize;
this.widths = widths;
this.adjustments = adjustments;
this.adjusted = false;
return this;
}
/**
* Obtain design advancement (width) of glyph at specified index.
* @param gi glyph index
* @return design advancement, or zero if glyph index is not present
*/
public int getWidth(int gi) {
if ((widths != null) && (gi < widths.length)) {
return widths [ gi ];
} else {
return 0;
}
}
/**
* Perform adjustments at current position index.
* @param v value containing adjustments
* @return true if a non-zero adjustment was made
*/
public boolean adjust(GlyphPositioningTable.Value v) {
return adjust(v, 0);
}
/**
* Perform adjustments at specified offset from current position index.
* @param v value containing adjustments
* @param offset from current position index
* @return true if a non-zero adjustment was made
*/
public boolean adjust(GlyphPositioningTable.Value v, int offset) {
assert v != null;
if ((index + offset) < indexLast) {
return v.adjust(adjustments [ index + offset ], fontSize);
} else {
throw new IndexOutOfBoundsException();
}
}
/**
* Obtain current adjustments at current position index.
* @return array of adjustments (int[4]) at current position
*/
public int[] getAdjustment() {
return getAdjustment(0);
}
/**
* Obtain current adjustments at specified offset from current position index.
* @param offset from current position index
* @return array of adjustments (int[4]) at specified offset
* @throws IndexOutOfBoundsException if offset is invalid
*/
public int[] getAdjustment(int offset) throws IndexOutOfBoundsException {
if ((index + offset) < indexLast) {
return adjustments [ index + offset ];
} else {
throw new IndexOutOfBoundsException();
}
}
/**
* Apply positioning subtable to current state at current position (only),
* resulting in the consumption of zero or more input glyphs.
* @param st the glyph positioning 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(GlyphPositioningSubtable st) {
assert st != null;
updateSubtableState(st);
boolean applied = st.position(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) {
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 positioning on a copy of previous state
GlyphPositioningState ps = new GlyphPositioningState(this);
// apply lookup table positioning
if (lt.position(ps, l.getSequenceIndex())) {
setAdjusted(true);
}
}
}
}
consume(nig);
return true;
} else {
return false;
}
}
/**
* Apply default application semantices; namely, consume one input glyph.
*/
public void applyDefault() {
super.applyDefault();
}
/**
* Set adjusted state, used to record effect of non-zero adjustment.
* @param adjusted true if to set adjusted state, otherwise false to
* clear adjusted state
*/
public void setAdjusted(boolean adjusted) {
this.adjusted = adjusted;
}
/**
* Get adjusted state.
* @return adjusted true if some non-zero adjustment occurred and
* was recorded by {@link #setAdjusted}; otherwise, false.
*/
public boolean getAdjusted() {
return adjusted;
}
}