All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.batik.gvt.text.BidiAttributedCharacterIterator Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*

   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 1831630 2018-05-15 12:56:55Z 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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy