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

org.apache.fop.area.inline.WordArea Maven / Gradle / Ivy

Go to download

Apache FOP (Formatting Objects Processor) is the world's first print formatter driven by XSL formatting objects (XSL-FO) and the world's first output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PCL, PS, AFP, TIFF, PNG, SVG, XML (area tree representation), Print, AWT and TXT. The primary output target is PDF.

There is a newer version: 2.9
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.
 */

/* $Id: WordArea.java 1761026 2016-09-16 12:50:43Z ssteiner $ */

package org.apache.fop.area.inline;

import java.util.Arrays;
import java.util.List;

import org.apache.fop.complexscripts.bidi.InlineRun;
import org.apache.fop.complexscripts.util.CharMirror;

/**
 * A string of characters without spaces
 */
public class WordArea extends InlineArea {

    private static final long serialVersionUID = 6444644662158970942L;

    /** The text for this word area */
    protected String word;

    /** An array of width for adjusting the individual letters (optional) */
    protected int[] letterAdjust;

    /**
     * An array of resolved bidirectional levels corresponding to each character
     * in word (optional)
     */
    protected int[] levels;

    /**
     * An array of glyph positioning adjustments to apply to each glyph 'char' in word (optional)
     */
    protected int[][] gposAdjustments;

    /**
     * A flag indicating whether the content of word is reversed in relation to
     * its original logical order.
     */
    protected boolean reversed;

    /**
     * Create a word area
     * @param blockProgressionOffset the offset for this area
     * @param level the bidirectional embedding level (or -1 if not defined) for word as a group
     * @param word the word string
     * @param letterAdjust the letter adjust array (may be null)
     * @param levels array of per-character (glyph) bidirectional levels,
     * in case word area is heterogenously leveled
     * @param gposAdjustments array of general position adjustments or null if none apply
     * @param reversed true if word is known to be reversed at construction time
     */
    public WordArea(
        int blockProgressionOffset, int level, String word, int[] letterAdjust, int[] levels,
          int[][] gposAdjustments, boolean reversed) {
        super(blockProgressionOffset, level);
        int length = (word != null) ? word.length() : 0;
        this.word = word;
        this.letterAdjust = maybeAdjustLength(letterAdjust, length);
        this.levels = maybePopulateLevels(levels, level, length);
        this.gposAdjustments = maybeAdjustLength(gposAdjustments, length);
        this.reversed = reversed;
    }

    /**
     * Create a word area
     * @param blockProgressionOffset the offset for this area
     * @param level the bidirectional embedding level (or -1 if not defined) for word as a group
     * @param word the word string
     * @param letterAdjust the letter adjust array (may be null)
     * @param levels array of per-character (glyph) bidirectional levels,
     * in case word area is heterogenously leveled
     * @param gposAdjustments array of general position adjustments or null if none apply
     */
    public WordArea(
        int blockProgressionOffset, int level, String word, int[] letterAdjust, int[] levels,
          int[][] gposAdjustments) {
        this (blockProgressionOffset, level, word, letterAdjust, levels, gposAdjustments, false);
    }

    /** @return Returns the word. */
    public String getWord() {
        return word;
    }

    /** @return the array of letter adjust widths */
    public int[] getLetterAdjustArray() {
        return this.letterAdjust;
    }

    /**
     * Obtain per-character (glyph) bidi levels.
     * @return a (possibly empty) array of levels or null (if none resolved)
     */
    public int[] getBidiLevels() {
        return levels;
    }

    /**
     * 

Obtain per-character (glyph) bidi levels over a specified subsequence.

*

If word has been reversed, then the subsequence is over the reversed word.

* @param start starting (inclusive) index of subsequence * @param end ending (exclusive) index of subsequence * @return a (possibly null) array of per-character (glyph) levels over the specified * sequence */ public int[] getBidiLevels(int start, int end) { assert start <= end; if (this.levels != null) { int n = end - start; int[] levels = new int [ n ]; System.arraycopy(this.levels, start + 0, levels, 0, n); return levels; } else { return null; } } /** *

Obtain per-character (glyph) level at a specified index position.

*

If word has been reversed, then the position is relative to the reversed word.

* @param position the index of the (possibly reversed) character from which to obtain the * level * @return a resolved bidirectional level or, if not specified, then -1 */ public int bidiLevelAt(int position) { if (position > word.length()) { throw new IndexOutOfBoundsException(); } else if (levels != null) { return levels [ position ]; } else { return -1; } } @Override public List collectInlineRuns(List runs) { assert runs != null; InlineRun r; int[] levels = getBidiLevels(); if ((levels != null) && (levels.length > 0)) { r = new InlineRun(this, levels); } else { r = new InlineRun(this, getBidiLevel(), word.length()); } runs.add(r); return runs; } /** * Obtain per-character (glyph) position adjustments. * @return a (possibly empty) array of adjustments, each having four elements, or null * if no adjustments apply */ public int[][] getGlyphPositionAdjustments() { return gposAdjustments; } /** *

Obtain per-character (glyph) position adjustments at a specified index position.

*

If word has been reversed, then the position is relative to the reversed word.

* @param position the index of the (possibly reversed) character from which to obtain the * level * @return an array of adjustments or null if none applies */ public int[] glyphPositionAdjustmentsAt(int position) { if (position > word.length()) { throw new IndexOutOfBoundsException(); } else if (gposAdjustments != null) { return gposAdjustments [ position ]; } else { return null; } } /** *

Reverse characters and corresponding per-character levels and glyph position * adjustments.

* @param mirror if true, then perform mirroring if mirrorred characters */ public void reverse(boolean mirror) { if (word.length() > 0) { word = ((new StringBuffer(word)) .reverse()) .toString(); if (levels != null) { reverse(levels); } if (gposAdjustments != null) { reverse(gposAdjustments); } reversed = !reversed; if (mirror) { word = CharMirror.mirror(word); } } } /** *

Perform mirroring on mirrorable characters.

*/ public void mirror() { if (word.length() > 0) { word = CharMirror.mirror(word); } } /** *

Determined if word has been reversed (in relation to original logical order).

*

If a word is reversed, then both its characters (glyphs) and corresponding per-character * levels are in reverse order.

*

Note: this information is used in order to process non-spacing marks during rendering as * well as provide hints for caret direction.

* @return true if word is reversed */ public boolean isReversed() { return reversed; } /* * If int[] array is not of specified length, then create * a new copy of the first length entries. */ private static int[] maybeAdjustLength(int[] ia, int length) { if (ia != null) { if (ia.length == length) { return ia; } else { int[] iaNew = new int [ length ]; for (int i = 0, n = ia.length; i < n; i++) { if (i < length) { iaNew [ i ] = ia [ i ]; } else { break; } } return iaNew; } } else { return ia; } } /* * If int[][] matrix is not of specified length, then create * a new shallow copy of the first length entries. */ private static int[][] maybeAdjustLength(int[][] im, int length) { if (im != null) { if (im.length == length) { return im; } else { int[][] imNew = new int [ length ][]; for (int i = 0, n = im.length; i < n; i++) { if (i < length) { imNew [ i ] = im [ i ]; } else { break; } } return imNew; } } else { return im; } } private static int[] maybePopulateLevels(int[] levels, int level, int count) { if ((levels == null) && (level >= 0)) { levels = new int[count]; Arrays.fill(levels, level); } return maybeAdjustLength(levels, count); } private static void reverse(int[] a) { for (int i = 0, n = a.length, m = n / 2; i < m; i++) { int k = n - i - 1; int t = a [ k ]; a [ k ] = a [ i ]; a [ i ] = t; } } private static void reverse(int[][] aa) { for (int i = 0, n = aa.length, m = n / 2; i < m; i++) { int k = n - i - 1; int[] t = aa [ k ]; aa [ k ] = aa [ i ]; aa [ i ] = t; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy