org.apache.batik.gvt.text.BidiAttributedCharacterIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of batik-gvt Show documentation
Show all versions of batik-gvt Show documentation
Batik Graphics Vector Tree (GVT)
/*
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.
*/
package org.apache.batik.gvt.text;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* An attributed character iterator that does the reordering of the characters
* for bidirectional text. It reorders the characters so they are in visual order.
* It also assigns a BIDI_LEVEL attribute to each character which can be used
* to split the reordered ACI into text runs based on direction. ie. characters
* in a text run will all have the same bidi level.
*
* @author Bella Robinson
* @version $Id: BidiAttributedCharacterIterator.java 1804130 2017-08-04 14:41:11Z ssteiner $
*/
public class BidiAttributedCharacterIterator implements AttributedCharacterIterator {
private AttributedCharacterIterator reorderedACI;
private FontRenderContext frc;
private int chunkStart;
private int [] newCharOrder;
private static final Float FLOAT_NAN = Float.NaN;
protected BidiAttributedCharacterIterator
(AttributedCharacterIterator reorderedACI,
FontRenderContext frc,
int chunkStart,
int [] newCharOrder) {
this.reorderedACI = reorderedACI;
this.frc = frc;
this.chunkStart = chunkStart;
this.newCharOrder = newCharOrder;
}
/**
* Constructs a character iterator that represents the visual display order
* of characters within bidirectional text.
*
* @param aci The character iterator containing the characters in logical
* order.
* @param frc The current font render context
*/
public BidiAttributedCharacterIterator(AttributedCharacterIterator aci,
FontRenderContext frc,
int chunkStart) {
this.frc = frc;
this.chunkStart = chunkStart;
aci.first();
int numChars = aci.getEndIndex()-aci.getBeginIndex();
AttributedString as;
// Ideally we would do a 'quick' check on chars and
// attributes to decide if we really need to do bidi or not.
if (false) {
// Believe it or not this is much slower than the else case
// but the two are exactly equivalent (including the stripping
// of null keys/values).
as = new AttributedString(aci);
} else {
StringBuffer strB = new StringBuffer( numChars );
char c = aci.first();
for (int i = 0; i < numChars; i++) {
strB.append(c);
c = aci.next();
}
as = new AttributedString(strB.toString());
int start=aci.getBeginIndex();
int end =aci.getEndIndex();
int index = start;
while (index < end) {
aci.setIndex(index);
Map attrMap = aci.getAttributes();
int extent = aci.getRunLimit();
Map destMap = new HashMap(attrMap.size());
for (Object o : attrMap.entrySet()) {
// Font doesn't like getting attribute sets with
// null keys or values so we strip them here.
Map.Entry e = (Map.Entry) o;
Object key = e.getKey();
if (key == null) continue;
Object value = e.getValue();
if (value == null) continue;
destMap.put(key, value);
}
// System.out.println("Run: " + (index-start) + "->" +
// (extent-start) + " of " + numChars);
as.addAttributes (destMap, index-start, extent-start);
index = extent;
}
}
// We Just want it to do BIDI for us...
// In 1.4 we might be able to use the BIDI class...
TextLayout tl = new TextLayout(as.getIterator(), frc);
int[] charIndices = new int[numChars];
int[] charLevels = new int[numChars];
int runStart = 0;
int currBiDi = tl.getCharacterLevel(0);
charIndices[0] = 0;
charLevels [0] = currBiDi;
int maxBiDi = currBiDi;
for (int i = 1; i < numChars; i++) {
int newBiDi = tl.getCharacterLevel(i);
charIndices[i] = i;
charLevels [i] = newBiDi;
if (newBiDi != currBiDi) {
as.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.BIDI_LEVEL,
currBiDi, runStart, i);
runStart = i;
currBiDi = newBiDi;
if (newBiDi > maxBiDi) maxBiDi = newBiDi;
}
}
as.addAttribute
(GVTAttributedCharacterIterator.TextAttribute.BIDI_LEVEL,
currBiDi, runStart, numChars);
aci = as.getIterator();
if ((runStart == 0) && (currBiDi==0)) {
// This avoids all the mucking about we need to do when
// bidi is actually performed for cases where it
// is not actually needed.
this.reorderedACI = aci;
newCharOrder = new int[numChars];
for (int i=0; i>1)+1;
for (int i = 0; i