123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- /*
- * 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.bidi;
-
- import java.util.Arrays;
- import java.util.List;
- import java.util.Vector;
-
- import org.apache.fop.area.inline.Anchor;
- import org.apache.fop.area.inline.InlineArea;
- import org.apache.fop.area.inline.InlineBlockParent;
- import org.apache.fop.area.inline.InlineParent;
- import org.apache.fop.area.inline.InlineViewport;
- import org.apache.fop.area.inline.Leader;
- import org.apache.fop.area.inline.Space;
- import org.apache.fop.area.inline.SpaceArea;
- import org.apache.fop.area.inline.UnresolvedPageNumber;
- import org.apache.fop.area.inline.WordArea;
- import org.apache.fop.util.CharUtilities;
-
- /**
- * The <code>InlineRun</code> class is a utility class, the instances of which are used
- * to capture a sequence of reordering levels associated with an inline area.
- *
- * <p>This work was originally authored by Glenn Adams (gadams@apache.org).</p>
- */
- public class InlineRun {
- private InlineArea inline;
- private int[] levels;
- private int minLevel;
- private int maxLevel;
- private int reversals;
- /**
- * Primary constructor.
- * @param inline which generated this inline run
- * @param levels levels array
- */
- public InlineRun(InlineArea inline, int[] levels) {
- assert inline != null;
- assert levels != null;
- this.inline = inline;
- this.levels = levels;
- setMinMax(levels);
- }
- /**
- * Alternate constructor.
- * @param inline which generated this inline run
- * @param level for each index
- * @param count of indices
- */
- public InlineRun(InlineArea inline, int level, int count) {
- this (inline, makeLevels(level, count));
- }
- /**
- * Obtain inline area that generated this inline run.
- * @return inline area that generated this inline run.
- */
- public InlineArea getInline() {
- return inline;
- }
- /**
- * Obtain minimum bidi level for this run.
- * @return minimum bidi level
- */
- public int getMinLevel() {
- return minLevel;
- }
- /**
- * Obtain maximum bidi level for this run.
- * @return maximum bidi level
- */
- public int getMaxLevel() {
- return maxLevel;
- }
- private void setMinMax(int[] levels) {
- int mn = Integer.MAX_VALUE;
- int mx = Integer.MIN_VALUE;
- if ((levels != null) && (levels.length > 0)) {
- for (int i = 0, n = levels.length; i < n; i++) {
- int l = levels [ i ];
- if (l < mn) {
- mn = l;
- }
- if (l > mx) {
- mx = l;
- }
- }
- } else {
- mn = mx = -1;
- }
- this.minLevel = mn;
- this.maxLevel = mx;
- }
- /**
- * Determine if this run has homogenous (same valued) bidi levels.
- * @return true if homogenous
- */
- public boolean isHomogenous() {
- return minLevel == maxLevel;
- }
- /**
- * Split this inline run into homogenous runs.
- * @return list of new runs
- */
- public List split() {
- List runs = new Vector();
- for (int i = 0, n = levels.length; i < n; ) {
- int l = levels [ i ];
- int s = i;
- int e = s;
- while (e < n) {
- if (levels [ e ] != l) {
- break;
- } else {
- e++;
- }
- }
- if (s < e) {
- runs.add(new InlineRun(inline, l, e - s));
- }
- i = e;
- }
- assert runs.size() < 2 : "heterogeneous inlines not yet supported!!";
- return runs;
- }
- /**
- * Update a min/max array to correspond with this run's min/max values.
- * @param mm reference to min/max array
- */
- public void updateMinMax(int[] mm) {
- if (minLevel < mm[0]) {
- mm[0] = minLevel;
- }
- if (maxLevel > mm[1]) {
- mm[1] = maxLevel;
- }
- }
- /**
- * Determine if run needs mirroring.
- * @return true if run is homogenous and (positive) odd (i.e., right to left)
- */
- public boolean maybeNeedsMirroring() {
- return (minLevel == maxLevel) && (minLevel > 0) && ((minLevel & 1) != 0);
- }
- /**
- * Reverse run (by incrementing reversal count, not actually reversing).
- */
- public void reverse() {
- reversals++;
- }
- /**
- * Reverse inline area if it is a word area and it requires
- * reversal.
- * @param mirror if true then also mirror characters
- */
- public void maybeReverseWord(boolean mirror) {
- if (inline instanceof WordArea) {
- WordArea w = (WordArea) inline;
- // if not already reversed, then reverse now
- if (!w.isReversed()) {
- if ((reversals & 1) != 0) {
- w.reverse(mirror);
- } else if (mirror && maybeNeedsMirroring()) {
- w.mirror();
- }
- }
- }
- }
- @Override
- public boolean equals(Object o) {
- if (o instanceof InlineRun) {
- InlineRun ir = (InlineRun) o;
- if (ir.inline != inline) {
- return false;
- } else if (ir.minLevel != minLevel) {
- return false;
- } else if (ir.maxLevel != maxLevel) {
- return false;
- } else if ((ir.levels != null) && (levels != null)) {
- if (ir.levels.length != levels.length) {
- return false;
- } else {
- for (int i = 0, n = levels.length; i < n; i++) {
- if (ir.levels[i] != levels[i]) {
- return false;
- }
- }
- return true;
- }
- } else {
- return (ir.levels == null) && (levels == null);
- }
- } else {
- return false;
- }
- }
- @Override
- public int hashCode() {
- int l = (inline != null) ? inline.hashCode() : 0;
- l = (l ^ minLevel) + (l << 19);
- l = (l ^ maxLevel) + (l << 11);
- return l;
- }
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer("RR: { type = \'");
- char c;
- String content = null;
- if (inline instanceof WordArea) {
- c = 'W';
- content = ((WordArea) inline) .getWord();
- } else if (inline instanceof SpaceArea) {
- c = 'S';
- content = ((SpaceArea) inline) .getSpace();
- } else if (inline instanceof Anchor) {
- c = 'A';
- } else if (inline instanceof Leader) {
- c = 'L';
- } else if (inline instanceof Space) {
- c = 'S';
- } else if (inline instanceof UnresolvedPageNumber) {
- c = '#';
- content = ((UnresolvedPageNumber) inline) .getText();
- } else if (inline instanceof InlineBlockParent) {
- c = 'B';
- } else if (inline instanceof InlineViewport) {
- c = 'V';
- } else if (inline instanceof InlineParent) {
- c = 'I';
- } else {
- c = '?';
- }
- sb.append(c);
- sb.append("\', levels = \'");
- sb.append(generateLevels(levels));
- sb.append("\', min = ");
- sb.append(minLevel);
- sb.append(", max = ");
- sb.append(maxLevel);
- sb.append(", reversals = ");
- sb.append(reversals);
- sb.append(", content = <");
- sb.append(CharUtilities.toNCRefs(content));
- sb.append("> }");
- return sb.toString();
- }
- private String generateLevels(int[] levels) {
- StringBuffer lb = new StringBuffer();
- int maxLevel = -1;
- int numLevels = levels.length;
- for (int i = 0; i < numLevels; i++) {
- int l = levels [ i ];
- if (l > maxLevel) {
- maxLevel = l;
- }
- }
- if (maxLevel < 0) {
- // leave level buffer empty
- } else if (maxLevel < 10) {
- // use string of decimal digits
- for (int i = 0; i < numLevels; i++) {
- lb.append((char) ('0' + levels [ i ]));
- }
- } else {
- // use comma separated list
- boolean first = true;
- for (int i = 0; i < numLevels; i++) {
- if (first) {
- first = false;
- } else {
- lb.append(',');
- }
- lb.append(levels [ i ]);
- }
- }
- return lb.toString();
- }
- private static int[] makeLevels(int level, int count) {
- int[] levels = new int [ count > 0 ? count : 1 ];
- Arrays.fill(levels, level);
- return levels;
- }
- }
|