1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id$ */
19 
20 package org.apache.fop.complexscripts.fonts;
21 
22 import org.apache.fop.complexscripts.util.GlyphSequence;
23 import org.apache.fop.complexscripts.util.ScriptContextTester;
24 
25 // CSOFF: LineLengthCheck
26 
27 /**
28  * <p>The <code>GlyphPositioningSubtable</code> implements an abstract base of a glyph subtable,
29  * providing a default implementation of the <code>GlyphPositioning</code> interface.</p>
30  *
31  * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
32  */
33 public abstract class GlyphPositioningSubtable extends GlyphSubtable implements GlyphPositioning {
34 
35     private static final GlyphPositioningState STATE = new GlyphPositioningState();
36 
37     /**
38      * Instantiate a <code>GlyphPositioningSubtable</code>.
39      * @param id subtable identifier
40      * @param sequence subtable sequence
41      * @param flags subtable flags
42      * @param format subtable format
43      * @param coverage subtable coverage table
44      */
GlyphPositioningSubtable(String id, int sequence, int flags, int format, GlyphCoverageTable coverage)45     protected GlyphPositioningSubtable(String id, int sequence, int flags, int format, GlyphCoverageTable coverage) {
46         super(id, sequence, flags, format, coverage);
47     }
48 
49     /** {@inheritDoc} */
getTableType()50     public int getTableType() {
51         return GlyphTable.GLYPH_TABLE_TYPE_POSITIONING;
52     }
53 
54     /** {@inheritDoc} */
getTypeName()55     public String getTypeName() {
56         return GlyphPositioningTable.getLookupTypeName(getType());
57     }
58 
59     /** {@inheritDoc} */
isCompatible(GlyphSubtable subtable)60     public boolean isCompatible(GlyphSubtable subtable) {
61         return subtable instanceof GlyphPositioningSubtable;
62     }
63 
64     /** {@inheritDoc} */
usesReverseScan()65     public boolean usesReverseScan() {
66         return false;
67     }
68 
69     /** {@inheritDoc} */
position(GlyphPositioningState ps)70     public boolean position(GlyphPositioningState ps) {
71         return false;
72     }
73 
74     /**
75      * Apply positioning using specified state and subtable array. For each position in input sequence,
76      * apply subtables in order until some subtable applies or none remain. If no subtable applied or no
77      * input was consumed for a given position, then apply default action (no adjustments and advance).
78      * If <code>sequenceIndex</code> is non-negative, then apply subtables only when current position
79      * matches <code>sequenceIndex</code> in relation to the starting position. Furthermore, upon
80      * successful application at <code>sequenceIndex</code>, then discontinue processing the remaining
81      * @param ps positioning state
82      * @param sta array of subtables to apply
83      * @param sequenceIndex if non negative, then apply subtables only at specified sequence index
84      * @return true if a non-zero adjustment occurred
85      */
position(GlyphPositioningState ps, GlyphPositioningSubtable[] sta, int sequenceIndex)86     public static final boolean position(GlyphPositioningState ps, GlyphPositioningSubtable[] sta, int sequenceIndex) {
87         int sequenceStart = ps.getPosition();
88         boolean appliedOneShot = false;
89         while (ps.hasNext()) {
90             boolean applied = false;
91             if (!appliedOneShot && ps.maybeApplicable()) {
92                 for (int i = 0, n = sta.length; !applied && (i < n); i++) {
93                     if (sequenceIndex < 0) {
94                         applied = ps.apply(sta [ i ]);
95                     } else if (ps.getPosition() == (sequenceStart + sequenceIndex)) {
96                         applied = ps.apply(sta [ i ]);
97                         if (applied) {
98                             appliedOneShot = true;
99                         }
100                     }
101                 }
102             }
103             if (!applied || !ps.didConsume()) {
104                 ps.applyDefault();
105             }
106             ps.next();
107         }
108         return ps.getAdjusted();
109     }
110 
111     /**
112      * Apply positioning.
113      * @param gs input glyph sequence
114      * @param script tag
115      * @param language tag
116      * @param feature tag
117      * @param fontSize the font size
118      * @param sta subtable array
119      * @param widths array
120      * @param adjustments array (receives output adjustments)
121      * @param sct script context tester
122      * @return true if a non-zero adjustment occurred
123      */
position(GlyphSequence gs, String script, String language, String feature, int fontSize, GlyphPositioningSubtable[] sta, int[] widths, int[][] adjustments, ScriptContextTester sct)124     public static final boolean position(GlyphSequence gs, String script, String language, String feature, int fontSize, GlyphPositioningSubtable[] sta, int[] widths, int[][] adjustments, ScriptContextTester sct) {
125         synchronized (STATE) {
126             return position(STATE.reset(gs, script, language, feature, fontSize, widths, adjustments, sct), sta, -1);
127         }
128     }
129 
130 }
131