151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage java.awt.font;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.IOException;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.ObjectOutputStream;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Arrays;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Comparator;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.EnumSet;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Set;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The <code>NumericShaper</code> class is used to convert Latin-1 (European)
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * digits to other Unicode decimal digits.  Users of this class will
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * primarily be people who wish to present data using
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * national digit shapes, but find it more convenient to represent the
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * data internally using Latin-1 (European) digits.  This does not
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * interpret the deprecated numeric shape selector character (U+206E).
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Instances of <code>NumericShaper</code> are typically applied
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * as attributes to text with the
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * {@link TextAttribute#NUMERIC_SHAPING NUMERIC_SHAPING} attribute
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of the <code>TextAttribute</code> class.
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * For example, this code snippet causes a <code>TextLayout</code> to
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * shape European digits to Arabic in an Arabic context:<br>
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote><pre>
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Map map = new HashMap();
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * map.put(TextAttribute.NUMERIC_SHAPING,
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     NumericShaper.getContextualShaper(NumericShaper.ARABIC));
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FontRenderContext frc = ...;
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * TextLayout layout = new TextLayout(text, map, frc);
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * layout.draw(g2d, x, y);
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </pre></blockquote>
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <br>
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * It is also possible to perform numeric shaping explicitly using instances
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of <code>NumericShaper</code>, as this code snippet demonstrates:<br>
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote><pre>
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * char[] text = ...;
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * // shape all EUROPEAN digits (except zero) to ARABIC digits
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * shaper.shape(text, start, count);
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * // shape European digits to ARABIC digits if preceding text is Arabic, or
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * // shape European digits to TAMIL digits if preceding text is Tamil, or
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * // leave European digits alone if there is no preceding text, or
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * // preceding text is neither Arabic nor Tamil
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * NumericShaper shaper =
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *                                         NumericShaper.TAMIL,
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *                                       NumericShaper.EUROPEAN);
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * shaper.shape(text, start, count);
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </pre></blockquote>
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p><b>Bit mask- and enum-based Unicode ranges</b></p>
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>This class supports two different programming interfaces to
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * represent Unicode ranges for script-specific digits: bit
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * enum-based ones, such as {@link NumericShaper.Range#ARABIC}.
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Multiple ranges can be specified by ORing bit mask-based constants,
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * such as:
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote><pre>
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * NumericShaper.ARABIC | NumericShaper.TAMIL
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </pre></blockquote>
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or creating a {@code Set} with the {@link NumericShaper.Range}
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * constants, such as:
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote><pre>
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * EnumSet.of(NumericShaper.Scirpt.ARABIC, NumericShaper.Range.TAMIL)
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </pre></blockquote>
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The enum-based ranges are a super set of the bit mask-based ones.
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>If the two interfaces are mixed (including serialization),
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Unicode range values are mapped to their counterparts where such
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * mapping is possible, such as {@code NumericShaper.Range.ARABIC}
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * from/to {@code NumericShaper.ARABIC}.  If any unmappable range
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * values are specified, such as {@code NumericShaper.Range.BALINESE},
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * those ranges are ignored.
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p><b>Decimal Digits Precedence</b></p>
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>A Unicode range may have more than one set of decimal digits. If
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * multiple decimal digits sets are specified for the same Unicode
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * range, one of the sets will take precedence as follows.
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <table border=1 cellspacing=3 cellpadding=0 summary="NumericShaper constants precedence.">
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    <tr>
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <th class="TableHeadingColor">Unicode Range</th>
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <th class="TableHeadingColor"><code>NumericShaper</code> Constants</th>
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <th class="TableHeadingColor">Precedence</th>
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    </tr>
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    <tr>
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td rowspan="2">Arabic</td>
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper#ARABIC NumericShaper.ARABIC}<br>
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *           {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}</td>
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}</td>
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    </tr>
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    <tr>
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper.Range#ARABIC}<br>
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *           {@link NumericShaper.Range#EASTERN_ARABIC}</td>
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper.Range#EASTERN_ARABIC}</td>
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    </tr>
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    <tr>
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>Tai Tham</td>
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper.Range#TAI_THAM_HORA}<br>
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *           {@link NumericShaper.Range#TAI_THAM_THAM}</td>
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *       <td>{@link NumericShaper.Range#TAI_THAM_THAM}</td>
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *    </tr>
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </table>
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @since 1.4
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic final class NumericShaper implements java.io.Serializable {
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * A {@code NumericShaper.Range} represents a Unicode range of a
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * script having its own decimal digits. For example, the {@link
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * NumericShaper.Range#THAI} range has the Thai digits, THAI DIGIT
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * ZERO (U+0E50) to THAI DIGIT NINE (U+0E59).
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>The <code>Range</code> enum replaces the traditional bit
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * mask-based values (e.g., {@link NumericShaper#ARABIC}), and
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * supports more Unicode ranges than the bit mask-based ones. For
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * example, the following code using the bit mask:
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote><pre>
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                     NumericShaper.TAMIL,
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                   NumericShaper.EUROPEAN);
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </pre></blockquote>
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * can be written using this enum as:
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote><pre>
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * NumericShaper.getContextualShaper(EnumSet.of(
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                     NumericShaper.Range.ARABIC,
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                     NumericShaper.Range.TAMIL),
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                                   NumericShaper.Range.EUROPEAN);
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </pre></blockquote>
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static enum Range {
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // The order of EUROPEAN to MOGOLIAN must be consistent
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // with the bitmask-based constants.
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Latin (European) range with the Latin (ASCII) digits.
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        EUROPEAN        ('\u0030', '\u0000', '\u0300'),
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Arabic range with the Arabic-Indic digits.
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ARABIC          ('\u0660', '\u0600', '\u0780'),
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Arabic range with the Eastern Arabic-Indic digits.
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        EASTERN_ARABIC  ('\u06f0', '\u0600', '\u0780'),
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Devanagari range with the Devanagari digits.
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        DEVANAGARI      ('\u0966', '\u0900', '\u0980'),
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Bengali range with the Bengali digits.
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BENGALI         ('\u09e6', '\u0980', '\u0a00'),
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Gurmukhi range with the Gurmukhi digits.
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        GURMUKHI        ('\u0a66', '\u0a00', '\u0a80'),
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Gujarati range with the Gujarati digits.
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        GUJARATI        ('\u0ae6', '\u0b00', '\u0b80'),
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Oriya range with the Oriya digits.
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ORIYA           ('\u0b66', '\u0b00', '\u0b80'),
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Tamil range with the Tamil digits.
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TAMIL           ('\u0be6', '\u0b80', '\u0c00'),
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Telugu range with the Telugu digits.
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TELUGU          ('\u0c66', '\u0c00', '\u0c80'),
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Kannada range with the Kannada digits.
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        KANNADA         ('\u0ce6', '\u0c80', '\u0d00'),
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Malayalam range with the Malayalam digits.
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MALAYALAM       ('\u0d66', '\u0d00', '\u0d80'),
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Thai range with the Thai digits.
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        THAI            ('\u0e50', '\u0e00', '\u0e80'),
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Lao range with the Lao digits.
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        LAO             ('\u0ed0', '\u0e80', '\u0f00'),
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Tibetan range with the Tibetan digits.
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TIBETAN         ('\u0f20', '\u0f00', '\u1000'),
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Myanmar range with the Myanmar digits.
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MYANMAR         ('\u1040', '\u1000', '\u1080'),
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Ethiopic range with the Ethiopic digits. Ethiopic
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * does not have a decimal digit 0 so Latin (European) 0 is
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * used.
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ETHIOPIC        ('\u1369', '\u1200', '\u1380') {
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            @Override
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char getNumericBase() { return 1; }
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        },
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Khmer range with the Khmer digits.
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        KHMER           ('\u17e0', '\u1780', '\u1800'),
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Mongolian range with the Mongolian digits.
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MONGOLIAN       ('\u1810', '\u1800', '\u1900'),
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // The order of EUROPEAN to MOGOLIAN must be consistent
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // with the bitmask-based constants.
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The N'Ko range with the N'Ko digits.
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        NKO             ('\u07c0', '\u07c0', '\u0800'),
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Myanmar range with the Myanmar Shan digits.
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MYANMAR_SHAN    ('\u1090', '\u1000', '\u10a0'),
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Limbu range with the Limbu digits.
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        LIMBU           ('\u1946', '\u1900', '\u1950'),
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The New Tai Lue range with the New Tai Lue digits.
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        NEW_TAI_LUE     ('\u19d0', '\u1980', '\u19e0'),
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Balinese range with the Balinese digits.
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        BALINESE        ('\u1b50', '\u1b00', '\u1b80'),
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Sundanese range with the Sundanese digits.
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        SUNDANESE       ('\u1bb0', '\u1b80', '\u1bc0'),
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Lepcha range with the Lepcha digits.
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        LEPCHA          ('\u1c40', '\u1c00', '\u1c50'),
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Ol Chiki range with the Ol Chiki digits.
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        OL_CHIKI        ('\u1c50', '\u1c50', '\u1c80'),
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Vai range with the Vai digits.
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        VAI             ('\ua620', '\ua500', '\ua640'),
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Saurashtra range with the Saurashtra digits.
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        SAURASHTRA      ('\ua8d0', '\ua880', '\ua8e0'),
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Kayah Li range with the Kayah Li digits.
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        KAYAH_LI        ('\ua900', '\ua900', '\ua930'),
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Cham range with the Cham digits.
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CHAM            ('\uaa50', '\uaa00', '\uaa60'),
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Tai Tham Hora range with the Tai Tham Hora digits.
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TAI_THAM_HORA   ('\u1a80', '\u1a20', '\u1ab0'),
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Tai Tham Tham range with the Tai Tham Tham digits.
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TAI_THAM_THAM   ('\u1a90', '\u1a20', '\u1ab0'),
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Javanese range with the Javanese digits.
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        JAVANESE        ('\ua9d0', '\ua980', '\ua9e0'),
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /**
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         * The Meetei Mayek range with the Meetei Mayek digits.
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         */
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MEETEI_MAYEK    ('\uabf0', '\uabc0', '\uac00');
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static int toRangeIndex(Range script) {
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int index = script.ordinal();
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return index < NUM_KEYS ? index : -1;
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static Range indexToRange(int index) {
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return index < NUM_KEYS ? Range.values()[index] : null;
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static int toRangeMask(Set<Range> ranges) {
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int m = 0;
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (Range range : ranges) {
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int index = range.ordinal();
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (index < NUM_KEYS) {
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    m |= 1 << index;
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return m;
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private static Set<Range> maskToRangeSet(int mask) {
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Set<Range> set = EnumSet.noneOf(Range.class);
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Range[] a = Range.values();
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = 0; i < NUM_KEYS; i++) {
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((mask & (1 << i)) != 0) {
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    set.add(a[i]);
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return set;
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // base character of range digits
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final int base;
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Unicode range
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private final int start, // inclusive
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          end;   // exclusive
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private Range(int base, int start, int end) {
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.base = base - ('0' + getNumericBase());
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.start = start;
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.end = end;
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private int getDigitBase() {
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return base;
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char getNumericBase() {
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return 0;
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private boolean inRange(int c) {
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return start <= c && c < end;
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** index of context for contextual shaping - values range from 0 to 18 */
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int key;
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** flag indicating whether to shape contextually (high bit) and which
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  digit ranges to shape (bits 0-18)
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int mask;
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The context {@code Range} for contextual shaping or the {@code
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Range} for non-contextual shaping. {@code null} for the bit
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * mask-based API.
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Range shapingRange;
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * {@code Set<Range>} indicating which Unicode ranges to
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * shape. {@code null} for the bit mask-based API.
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private transient Set<Range> rangeSet;
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * rangeSet.toArray() value. Sorted by Range.base when the number
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * of elements is greater then BSEARCH_THRESHOLD.
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private transient Range[] rangeArray;
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If more than BSEARCH_THRESHOLD ranges are specified, binary search is used.
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int BSEARCH_THRESHOLD = 3;
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final long serialVersionUID = -8022764705923730308L;
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the Latin-1 (European) and extended range, and
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *  Latin-1 (European) decimal base.
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int EUROPEAN = 1<<0;
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the ARABIC range and decimal base. */
41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int ARABIC = 1<<1;
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the ARABIC range and ARABIC_EXTENDED decimal base. */
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int EASTERN_ARABIC = 1<<2;
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the DEVANAGARI range and decimal base. */
41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int DEVANAGARI = 1<<3;
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the BENGALI range and decimal base. */
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int BENGALI = 1<<4;
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the GURMUKHI range and decimal base. */
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int GURMUKHI = 1<<5;
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the GUJARATI range and decimal base. */
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int GUJARATI = 1<<6;
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the ORIYA range and decimal base. */
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int ORIYA = 1<<7;
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the TAMIL range and decimal base. */
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // TAMIL DIGIT ZERO was added in Unicode 4.1
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int TAMIL = 1<<8;
43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the TELUGU range and decimal base. */
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int TELUGU = 1<<9;
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the KANNADA range and decimal base. */
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int KANNADA = 1<<10;
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the MALAYALAM range and decimal base. */
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int MALAYALAM = 1<<11;
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the THAI range and decimal base. */
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int THAI = 1<<12;
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the LAO range and decimal base. */
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int LAO = 1<<13;
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the TIBETAN range and decimal base. */
45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int TIBETAN = 1<<14;
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the MYANMAR range and decimal base. */
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int MYANMAR = 1<<15;
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the ETHIOPIC range and decimal base. */
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int ETHIOPIC = 1<<16;
45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the KHMER range and decimal base. */
46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int KHMER = 1<<17;
46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies the MONGOLIAN range and decimal base. */
46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int MONGOLIAN = 1<<18;
46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Identifies all ranges, for full contextual shaping.
46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>This constant specifies all of the bit mask-based
46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * ranges. Use {@code EmunSet.allOf(NumericShaper.Range.class)} to
47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * specify all of the enum-based ranges.
47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static final int ALL_RANGES = 0x0007ffff;
47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int EUROPEAN_KEY = 0;
47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int ARABIC_KEY = 1;
47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int EASTERN_ARABIC_KEY = 2;
47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int DEVANAGARI_KEY = 3;
47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int BENGALI_KEY = 4;
47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int GURMUKHI_KEY = 5;
48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int GUJARATI_KEY = 6;
48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int ORIYA_KEY = 7;
48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int TAMIL_KEY = 8;
48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int TELUGU_KEY = 9;
48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int KANNADA_KEY = 10;
48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int MALAYALAM_KEY = 11;
48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int THAI_KEY = 12;
48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int LAO_KEY = 13;
48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int TIBETAN_KEY = 14;
48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int MYANMAR_KEY = 15;
49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int ETHIOPIC_KEY = 16;
49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int KHMER_KEY = 17;
49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int MONGOLIAN_KEY = 18;
49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed
49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int CONTEXTUAL_MASK = 1<<31;
49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final char[] bases = {
49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0030' - '\u0030', // EUROPEAN
50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0660' - '\u0030', // ARABIC-INDIC
50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC)
50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0966' - '\u0030', // DEVANAGARI
50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u09e6' - '\u0030', // BENGALI
50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0a66' - '\u0030', // GURMUKHI
50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0ae6' - '\u0030', // GUJARATI
50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0b66' - '\u0030', // ORIYA
50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1
50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0c66' - '\u0030', // TELUGU
50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0ce6' - '\u0030', // KANNADA
51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0d66' - '\u0030', // MALAYALAM
51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0e50' - '\u0030', // THAI
51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0ed0' - '\u0030', // LAO
51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0f20' - '\u0030', // TIBETAN
51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1040' - '\u0030', // MYANMAR
51551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1369' - '\u0031', // ETHIOPIC - no zero
51651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u17e0' - '\u0030', // KHMER
51751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1810' - '\u0030', // MONGOLIAN
51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
51951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // some ranges adjoin or overlap, rethink if we want to do a binary search on this
52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
52251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final char[] contexts = {
52351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended)
52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0600', '\u0780', // ARABIC
52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic
52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0900', '\u0980', // DEVANAGARI
52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0980', '\u0a00', // BENGALI
52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0a00', '\u0a80', // GURMUKHI
52951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0a80', '\u0b00', // GUJARATI
53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0b00', '\u0b80', // ORIYA
53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0b80', '\u0c00', // TAMIL
53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0c00', '\u0c80', // TELUGU
53351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0c80', '\u0d00', // KANNADA
53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0d00', '\u0d80', // MALAYALAM
53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0e00', '\u0e80', // THAI
53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0e80', '\u0f00', // LAO
53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u0f00', '\u1000', // TIBETAN
53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1000', '\u1080', // MYANMAR
53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1200', '\u1380', // ETHIOPIC - note missing zero
54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1780', '\u1800', // KHMER
54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\u1800', '\u1900', // MONGOLIAN
54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        '\uffff',
54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // assume most characters are near each other so probing the cache is infrequent,
54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // and a linear probe is ok.
54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int ctCache = 0;
54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int ctCacheLimit = contexts.length - 2;
55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // warning, synchronize access to this as it modifies state
55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int getContextKey(char c) {
55351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (c < contexts[ctCache]) {
55451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (ctCache > 0 && c < contexts[ctCache]) --ctCache;
55551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else if (c >= contexts[ctCache + 1]) {
55651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (ctCache < ctCacheLimit && c >= contexts[ctCache + 1]) ++ctCache;
55751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
55851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
55951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // if we're not in a known range, then return EUROPEAN as the range key
56051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY;
56151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
56251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
56351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // cache for the NumericShaper.Range version
56451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private transient volatile Range currentRange = Range.EUROPEAN;
56551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
56651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Range rangeForCodePoint(final int codepoint) {
56751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (currentRange.inRange(codepoint)) {
56851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return currentRange;
56951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
57051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
57151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        final Range[] ranges = rangeArray;
57251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ranges.length > BSEARCH_THRESHOLD) {
57351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int lo = 0;
57451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int hi = ranges.length - 1;
57551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (lo <= hi) {
57651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int mid = (lo + hi) / 2;
57751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                Range range = ranges[mid];
57851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (codepoint < range.start) {
57951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    hi = mid - 1;
58051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else if (codepoint >= range.end) {
58151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    lo = mid + 1;
58251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
58351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    currentRange = range;
58451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return range;
58551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
58651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
58751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
58851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = 0; i < ranges.length; i++) {
58951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (ranges[i].inRange(codepoint)) {
59051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return ranges[i];
59151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
59251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
59351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
59451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return Range.EUROPEAN;
59551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
59651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
59751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /*
59851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * A range table of strong directional characters (types L, R, AL).
59951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Even (left) indexes are starts of ranges of non-strong-directional (or undefined)
60051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * characters, odd (right) indexes are starts of ranges of strong directional
60151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * characters.
60251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
60351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int[] strongTable = {
60451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0000, 0x0041,
60551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x005b, 0x0061,
60651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x007b, 0x00aa,
60751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x00ab, 0x00b5,
60851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x00b6, 0x00ba,
60951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x00bb, 0x00c0,
61051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x00d7, 0x00d8,
61151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x00f7, 0x00f8,
61251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x02b9, 0x02bb,
61351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x02c2, 0x02d0,
61451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x02d2, 0x02e0,
61551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x02e5, 0x02ee,
61651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x02ef, 0x0370,
61751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0374, 0x0376,
61851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x037e, 0x0386,
61951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0387, 0x0388,
62051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x03f6, 0x03f7,
62151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0483, 0x048a,
62251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x058a, 0x05be,
62351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x05bf, 0x05c0,
62451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x05c1, 0x05c3,
62551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x05c4, 0x05c6,
62651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x05c7, 0x05d0,
62751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0600, 0x0608,
62851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0609, 0x060b,
62951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x060c, 0x060d,
63051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x060e, 0x061b,
63151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x064b, 0x066d,
63251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0670, 0x0671,
63351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x06d6, 0x06e5,
63451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x06e7, 0x06ee,
63551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x06f0, 0x06fa,
63651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x070f, 0x0710,
63751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0711, 0x0712,
63851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0730, 0x074d,
63951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x07a6, 0x07b1,
64051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x07eb, 0x07f4,
64151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x07f6, 0x07fa,
64251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0816, 0x081a,
64351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x081b, 0x0824,
64451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0825, 0x0828,
64551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0829, 0x0830,
64651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0859, 0x085e,
64751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0900, 0x0903,
64851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x093a, 0x093b,
64951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x093c, 0x093d,
65051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0941, 0x0949,
65151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x094d, 0x094e,
65251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0951, 0x0958,
65351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0962, 0x0964,
65451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0981, 0x0982,
65551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09bc, 0x09bd,
65651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09c1, 0x09c7,
65751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09cd, 0x09ce,
65851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09e2, 0x09e6,
65951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09f2, 0x09f4,
66051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x09fb, 0x0a03,
66151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0a3c, 0x0a3e,
66251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0a41, 0x0a59,
66351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0a70, 0x0a72,
66451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0a75, 0x0a83,
66551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0abc, 0x0abd,
66651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0ac1, 0x0ac9,
66751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0acd, 0x0ad0,
66851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0ae2, 0x0ae6,
66951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0af1, 0x0b02,
67051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b3c, 0x0b3d,
67151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b3f, 0x0b40,
67251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b41, 0x0b47,
67351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b4d, 0x0b57,
67451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b62, 0x0b66,
67551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0b82, 0x0b83,
67651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0bc0, 0x0bc1,
67751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0bcd, 0x0bd0,
67851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0bf3, 0x0c01,
67951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0c3e, 0x0c41,
68051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0c46, 0x0c58,
68151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0c62, 0x0c66,
68251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0c78, 0x0c7f,
68351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0cbc, 0x0cbd,
68451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0ccc, 0x0cd5,
68551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0ce2, 0x0ce6,
68651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0d41, 0x0d46,
68751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0d4d, 0x0d4e,
68851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0d62, 0x0d66,
68951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0dca, 0x0dcf,
69051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0dd2, 0x0dd8,
69151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0e31, 0x0e32,
69251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0e34, 0x0e40,
69351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0e47, 0x0e4f,
69451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0eb1, 0x0eb2,
69551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0eb4, 0x0ebd,
69651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0ec8, 0x0ed0,
69751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f18, 0x0f1a,
69851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f35, 0x0f36,
69951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f37, 0x0f38,
70051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f39, 0x0f3e,
70151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f71, 0x0f7f,
70251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f80, 0x0f85,
70351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f86, 0x0f88,
70451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0f8d, 0x0fbe,
70551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x0fc6, 0x0fc7,
70651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x102d, 0x1031,
70751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1032, 0x1038,
70851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1039, 0x103b,
70951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x103d, 0x103f,
71051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1058, 0x105a,
71151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x105e, 0x1061,
71251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1071, 0x1075,
71351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1082, 0x1083,
71451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1085, 0x1087,
71551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x108d, 0x108e,
71651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x109d, 0x109e,
71751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x135d, 0x1360,
71851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1390, 0x13a0,
71951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1400, 0x1401,
72051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1680, 0x1681,
72151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x169b, 0x16a0,
72251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1712, 0x1720,
72351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1732, 0x1735,
72451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1752, 0x1760,
72551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1772, 0x1780,
72651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17b7, 0x17be,
72751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17c6, 0x17c7,
72851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17c9, 0x17d4,
72951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17db, 0x17dc,
73051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17dd, 0x17e0,
73151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x17f0, 0x1810,
73251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x18a9, 0x18aa,
73351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1920, 0x1923,
73451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1927, 0x1929,
73551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1932, 0x1933,
73651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1939, 0x1946,
73751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x19de, 0x1a00,
73851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a17, 0x1a19,
73951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a56, 0x1a57,
74051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a58, 0x1a61,
74151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a62, 0x1a63,
74251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a65, 0x1a6d,
74351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1a73, 0x1a80,
74451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b00, 0x1b04,
74551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b34, 0x1b35,
74651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b36, 0x1b3b,
74751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b3c, 0x1b3d,
74851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b42, 0x1b43,
74951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b6b, 0x1b74,
75051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1b80, 0x1b82,
75151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1ba2, 0x1ba6,
75251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1ba8, 0x1baa,
75351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1be6, 0x1be7,
75451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1be8, 0x1bea,
75551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1bed, 0x1bee,
75651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1bef, 0x1bf2,
75751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1c2c, 0x1c34,
75851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1c36, 0x1c3b,
75951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1cd0, 0x1cd3,
76051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1cd4, 0x1ce1,
76151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1ce2, 0x1ce9,
76251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1ced, 0x1cee,
76351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1dc0, 0x1e00,
76451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1fbd, 0x1fbe,
76551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1fbf, 0x1fc2,
76651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1fcd, 0x1fd0,
76751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1fdd, 0x1fe0,
76851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1fed, 0x1ff2,
76951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1ffd, 0x200e,
77051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2010, 0x2071,
77151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2074, 0x207f,
77251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2080, 0x2090,
77351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x20a0, 0x2102,
77451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2103, 0x2107,
77551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2108, 0x210a,
77651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2114, 0x2115,
77751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2116, 0x2119,
77851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x211e, 0x2124,
77951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2125, 0x2126,
78051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2127, 0x2128,
78151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2129, 0x212a,
78251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x212e, 0x212f,
78351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x213a, 0x213c,
78451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2140, 0x2145,
78551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x214a, 0x214e,
78651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2150, 0x2160,
78751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2189, 0x2336,
78851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x237b, 0x2395,
78951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2396, 0x249c,
79051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x24ea, 0x26ac,
79151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x26ad, 0x2800,
79251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2900, 0x2c00,
79351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2ce5, 0x2ceb,
79451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2cef, 0x2d00,
79551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2d7f, 0x2d80,
79651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x2de0, 0x3005,
79751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x3008, 0x3021,
79851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x302a, 0x3031,
79951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x3036, 0x3038,
80051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x303d, 0x3041,
80151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x3099, 0x309d,
80251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x30a0, 0x30a1,
80351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x30fb, 0x30fc,
80451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x31c0, 0x31f0,
80551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x321d, 0x3220,
80651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x3250, 0x3260,
80751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x327c, 0x327f,
80851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x32b1, 0x32c0,
80951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x32cc, 0x32d0,
81051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x3377, 0x337b,
81151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x33de, 0x33e0,
81251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x33ff, 0x3400,
81351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x4dc0, 0x4e00,
81451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa490, 0xa4d0,
81551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa60d, 0xa610,
81651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa66f, 0xa680,
81751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa6f0, 0xa6f2,
81851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa700, 0xa722,
81951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa788, 0xa789,
82051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa802, 0xa803,
82151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa806, 0xa807,
82251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa80b, 0xa80c,
82351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa825, 0xa827,
82451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa828, 0xa830,
82551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa838, 0xa840,
82651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa874, 0xa880,
82751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa8c4, 0xa8ce,
82851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa8e0, 0xa8f2,
82951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa926, 0xa92e,
83051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa947, 0xa952,
83151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa980, 0xa983,
83251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa9b3, 0xa9b4,
83351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa9b6, 0xa9ba,
83451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xa9bc, 0xa9bd,
83551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaa29, 0xaa2f,
83651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaa31, 0xaa33,
83751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaa35, 0xaa40,
83851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaa43, 0xaa44,
83951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaa4c, 0xaa4d,
84051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaab0, 0xaab1,
84151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaab2, 0xaab5,
84251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaab7, 0xaab9,
84351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaabe, 0xaac0,
84451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xaac1, 0xaac2,
84551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xabe5, 0xabe6,
84651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xabe8, 0xabe9,
84751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xabed, 0xabf0,
84851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xfb1e, 0xfb1f,
84951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xfb29, 0xfb2a,
85051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xfd3e, 0xfd50,
85151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xfdfd, 0xfe70,
85251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xfeff, 0xff21,
85351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xff3b, 0xff41,
85451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xff5b, 0xff66,
85551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xffe0, 0x10000,
85651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10101, 0x10102,
85751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10140, 0x101d0,
85851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x101fd, 0x10280,
85951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1091f, 0x10920,
86051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10a01, 0x10a10,
86151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10a38, 0x10a40,
86251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10b39, 0x10b40,
86351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10e60, 0x11000,
86451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x11001, 0x11002,
86551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x11038, 0x11047,
86651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x11052, 0x11066,
86751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x11080, 0x11082,
86851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x110b3, 0x110b7,
86951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x110b9, 0x110bb,
87051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d167, 0x1d16a,
87151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d173, 0x1d183,
87251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d185, 0x1d18c,
87351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d1aa, 0x1d1ae,
87451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d200, 0x1d360,
87551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d6db, 0x1d6dc,
87651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d715, 0x1d716,
87751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d74f, 0x1d750,
87851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d789, 0x1d78a,
87951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d7c3, 0x1d7c4,
88051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1d7ce, 0x1f110,
88151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1f300, 0x1f48c,
88251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1f48d, 0x1f524,
88351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x1f525, 0x20000,
88451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0xe0001, 0xf0000,
88551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        0x10fffe, 0x10ffff // sentinel
88651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
88751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
88851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
88951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // use a binary search with a cache
89051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
89151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private transient volatile int stCache = 0;
89251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
89351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean isStrongDirectional(char c) {
89451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int cachedIndex = stCache;
89551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (c < strongTable[cachedIndex]) {
89651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            cachedIndex = search(c, strongTable, 0, cachedIndex);
89751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else if (c >= strongTable[cachedIndex + 1]) {
89851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            cachedIndex = search(c, strongTable, cachedIndex + 1,
89951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                 strongTable.length - cachedIndex - 1);
90051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
90151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean val = (cachedIndex & 0x1) == 1;
90251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        stCache = cachedIndex;
90351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return val;
90451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
90551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
90651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int getKeyFromMask(int mask) {
90751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int key = 0;
90851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (key < NUM_KEYS && ((mask & (1<<key)) == 0)) {
90951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ++key;
91051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
91151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (key == NUM_KEYS || ((mask & ~(1<<key)) != 0)) {
91251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException("invalid shaper: " + Integer.toHexString(mask));
91351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
91451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return key;
91551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
91651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
91751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
91851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a shaper for the provided unicode range.  All
91951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Latin-1 (EUROPEAN) digits are converted
92051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to the corresponding decimal unicode digits.
92151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param singleRange the specified Unicode range
92251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a non-contextual numeric shaper
92351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IllegalArgumentException if the range is not a single range
92451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
92551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getShaper(int singleRange) {
92651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int key = getKeyFromMask(singleRange);
92751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new NumericShaper(key, singleRange);
92851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
92951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
93051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
93151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a shaper for the provided Unicode
93251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range. All Latin-1 (EUROPEAN) digits are converted to the
93351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * corresponding decimal digits of the specified Unicode range.
93451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
93551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param singleRange the Unicode range given by a {@link
93651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                    NumericShaper.Range} constant.
93751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a non-contextual {@code NumericShaper}.
93851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException if {@code singleRange} is {@code null}
93951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
94051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
94151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getShaper(Range singleRange) {
94251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new NumericShaper(singleRange, EnumSet.of(singleRange));
94351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
94451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
94551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
94651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a contextual shaper for the provided unicode range(s).
94751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Latin-1 (EUROPEAN) digits are converted to the decimal digits
94851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * corresponding to the range of the preceding text, if the
94951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range is one of the provided ranges.  Multiple ranges are
95051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * represented by or-ing the values together, such as,
95151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The
95251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * shaper assumes EUROPEAN as the starting context, that is, if
95351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * EUROPEAN digits are encountered before any strong directional
95451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * text in the string, the context is presumed to be EUROPEAN, and
95551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * so the digits will not shape.
95651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param ranges the specified Unicode ranges
95751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a shaper for the specified ranges
95851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
95951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getContextualShaper(int ranges) {
96051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ranges |= CONTEXTUAL_MASK;
96151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new NumericShaper(EUROPEAN_KEY, ranges);
96251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
96351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
96451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
96551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a contextual shaper for the provided Unicode
96651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range(s). The Latin-1 (EUROPEAN) digits are converted to the
96751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * decimal digits corresponding to the range of the preceding
96851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * text, if the range is one of the provided ranges.
96951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
97051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>The shaper assumes EUROPEAN as the starting context, that
97151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * is, if EUROPEAN digits are encountered before any strong
97251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * directional text in the string, the context is presumed to be
97351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * EUROPEAN, and so the digits will not shape.
97451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
97551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param ranges the specified Unicode ranges
97651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a contextual shaper for the specified ranges
97751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException if {@code ranges} is {@code null}.
97851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
97951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
98051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getContextualShaper(Set<Range> ranges) {
98151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges);
98251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        shaper.mask = CONTEXTUAL_MASK;
98351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return shaper;
98451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
98551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
98651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
98751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a contextual shaper for the provided unicode range(s).
98851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Latin-1 (EUROPEAN) digits will be converted to the decimal digits
98951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * corresponding to the range of the preceding text, if the
99051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range is one of the provided ranges.  Multiple ranges are
99151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * represented by or-ing the values together, for example,
99251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The
99351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * shaper uses defaultContext as the starting context.
99451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param ranges the specified Unicode ranges
99551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param defaultContext the starting context, such as
99651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>NumericShaper.EUROPEAN</code>
99751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a shaper for the specified Unicode ranges.
99851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IllegalArgumentException if the specified
99951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>defaultContext</code> is not a single valid range.
100051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
100151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getContextualShaper(int ranges, int defaultContext) {
100251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int key = getKeyFromMask(defaultContext);
100351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ranges |= CONTEXTUAL_MASK;
100451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new NumericShaper(key, ranges);
100551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
100651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
100751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
100851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a contextual shaper for the provided Unicode range(s).
100951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The Latin-1 (EUROPEAN) digits will be converted to the decimal
101051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * digits corresponding to the range of the preceding text, if the
101151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range is one of the provided ranges. The shaper uses {@code
101251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * defaultContext} as the starting context.
101351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
101451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param ranges the specified Unicode ranges
101551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param defaultContext the starting context, such as
101651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                       {@code NumericShaper.Range.EUROPEAN}
101751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a contextual shaper for the specified Unicode ranges.
101851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException
101951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         if {@code ranges} or {@code defaultContext} is {@code null}
102051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
102151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
102251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static NumericShaper getContextualShaper(Set<Range> ranges,
102351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                    Range defaultContext) {
102451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (defaultContext == null) {
102551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException();
102651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
102751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        NumericShaper shaper = new NumericShaper(defaultContext, ranges);
102851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        shaper.mask = CONTEXTUAL_MASK;
102951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return shaper;
103051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
103151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
103251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
103351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private constructor.
103451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
103551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private NumericShaper(int key, int mask) {
103651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.key = key;
103751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.mask = mask;
103851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
103951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
104051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private NumericShaper(Range defaultContext, Set<Range> ranges) {
104151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        shapingRange = defaultContext;
104251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null.
104351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
104451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Give precedance to EASTERN_ARABIC if both ARABIC and
104551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // EASTERN_ARABIC are specified.
104651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet.contains(Range.EASTERN_ARABIC)
104751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            && rangeSet.contains(Range.ARABIC)) {
104851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            rangeSet.remove(Range.ARABIC);
104951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
105051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
105151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // As well as the above case, give precedance to TAI_THAM_THAM if both
105251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // TAI_THAM_HORA and TAI_THAM_THAM are specified.
105351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet.contains(Range.TAI_THAM_THAM)
105451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            && rangeSet.contains(Range.TAI_THAM_HORA)) {
105551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            rangeSet.remove(Range.TAI_THAM_HORA);
105651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
105751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
105851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        rangeArray = rangeSet.toArray(new Range[rangeSet.size()]);
105951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeArray.length > BSEARCH_THRESHOLD) {
106051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // sort rangeArray for binary search
106151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            Arrays.sort(rangeArray,
106251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        new Comparator<Range>() {
106351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            public int compare(Range s1, Range s2) {
106451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1;
106551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            }
106651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        });
106751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
106851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
106951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
107051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
107151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Converts the digits in the text that occur between start and
107251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * start + count.
107351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text an array of characters to convert
107451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start the index into <code>text</code> to start
107551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        converting
107651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param count the number of characters in <code>text</code>
107751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        to convert
107851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IndexOutOfBoundsException if start or start + count is
107951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        out of bounds
108051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException if text is null
108151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
108251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void shape(char[] text, int start, int count) {
108351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        checkParams(text, start, count);
108451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isContextual()) {
108551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (rangeSet == null) {
108651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                shapeContextually(text, start, count, key);
108751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
108851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                shapeContextually(text, start, count, shapingRange);
108951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
109051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
109151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            shapeNonContextually(text, start, count);
109251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
109351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
109451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
109551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
109651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Converts the digits in the text that occur between start and
109751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * start + count, using the provided context.
109851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Context is ignored if the shaper is not a contextual shaper.
109951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text an array of characters
110051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start the index into <code>text</code> to start
110151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        converting
110251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param count the number of characters in <code>text</code>
110351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        to convert
110451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param context the context to which to convert the
110551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        characters, such as <code>NumericShaper.EUROPEAN</code>
110651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IndexOutOfBoundsException if start or start + count is
110751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        out of bounds
110851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException if text is null
110951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IllegalArgumentException if this is a contextual shaper
111051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and the specified <code>context</code> is not a single valid
111151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * range.
111251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
111351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void shape(char[] text, int start, int count, int context) {
111451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        checkParams(text, start, count);
111551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isContextual()) {
111651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int ctxKey = getKeyFromMask(context);
111751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (rangeSet == null) {
111851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                shapeContextually(text, start, count, ctxKey);
111951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
112051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                shapeContextually(text, start, count, Range.values()[ctxKey]);
112151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
112251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
112351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            shapeNonContextually(text, start, count);
112451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
112551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
112651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
112751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
112851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Converts the digits in the text that occur between {@code
112951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * start} and {@code start + count}, using the provided {@code
113051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * context}. {@code Context} is ignored if the shaper is not a
113151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * contextual shaper.
113251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
113351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text  a {@code char} array
113451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start the index into {@code text} to start converting
113551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param count the number of {@code char}s in {@code text}
113651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *              to convert
113751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param context the context to which to convert the characters,
113851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *                such as {@code NumericShaper.Range.EUROPEAN}
113951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IndexOutOfBoundsException
114051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         if {@code start} or {@code start + count} is out of bounds
114151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws NullPointerException
114251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         if {@code text} or {@code context} is null
114351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
114451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
114551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void shape(char[] text, int start, int count, Range context) {
114651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        checkParams(text, start, count);
114751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (context == null) {
114851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException("context is null");
114951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
115051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
115151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isContextual()) {
115251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (rangeSet != null) {
115351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                shapeContextually(text, start, count, context);
115451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
115551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int key = Range.toRangeIndex(context);
115651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (key >= 0) {
115751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    shapeContextually(text, start, count, key);
115851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
115951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    shapeContextually(text, start, count, shapingRange);
116051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
116151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
116251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
116351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            shapeNonContextually(text, start, count);
116451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
116551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
116651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
116751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void checkParams(char[] text, int start, int count) {
116851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (text == null) {
116951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException("text is null");
117051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
117151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((start < 0)
117251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || (start > text.length)
117351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || ((start + count) < 0)
117451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            || ((start + count) > text.length)) {
117551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IndexOutOfBoundsException(
117651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                "bad start or count for text of length " + text.length);
117751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
117851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
117951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
118051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
118151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a <code>boolean</code> indicating whether or not
118251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * this shaper shapes contextually.
118351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return <code>true</code> if this shaper is contextual;
118451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         <code>false</code> otherwise.
118551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
118651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean isContextual() {
118751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (mask & CONTEXTUAL_MASK) != 0;
118851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
118951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
119051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
119151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns an <code>int</code> that ORs together the values for
119251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * all the ranges that will be shaped.
119351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
119451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * For example, to check if a shaper shapes to Arabic, you would use the
119551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * following:
119651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote>
119751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *   <code>if ((shaper.getRanges() & shaper.ARABIC) != 0) { ... </code>
119851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </blockquote>
119951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
120051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>Note that this method supports only the bit mask-based
120151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * ranges. Call {@link #getRangeSet()} for the enum-based ranges.
120251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
120351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the values for all the ranges to be shaped.
120451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
120551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getRanges() {
120651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return mask & ~CONTEXTUAL_MASK;
120751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
120851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
120951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
121051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a {@code Set} representing all the Unicode ranges in
121151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * this {@code NumericShaper} that will be shaped.
121251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
121351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return all the Unicode ranges to be shaped.
121451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
121551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
121651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Set<Range> getRangeSet() {
121751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet != null) {
121851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return EnumSet.copyOf(rangeSet);
121951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
122051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return Range.maskToRangeSet(mask);
122151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
122251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
122351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
122451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Perform non-contextual shaping.
122551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
122651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void shapeNonContextually(char[] text, int start, int count) {
122751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int base;
122851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char minDigit = '0';
122951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (shapingRange != null) {
123051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            base = shapingRange.getDigitBase();
123151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            minDigit += shapingRange.getNumericBase();
123251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
123351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            base = bases[key];
123451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (key == ETHIOPIC_KEY) {
123551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                minDigit++; // Ethiopic doesn't use decimal zero
123651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
123751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
123851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = start, e = start + count; i < e; ++i) {
123951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = text[i];
124051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c >= minDigit && c <= '\u0039') {
124151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                text[i] = (char)(c + base);
124251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
124351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
124451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
124551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
124651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
124751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Perform contextual shaping.
124851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Synchronized to protect caches used in getContextKey.
124951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
125051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) {
125151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
125251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // if we don't support this context, then don't shape
125351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((mask & (1<<ctxKey)) == 0) {
125451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ctxKey = EUROPEAN_KEY;
125551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
125651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int lastkey = ctxKey;
125751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
125851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int base = bases[ctxKey];
125951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero
126051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
126151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (NumericShaper.class) {
126251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = start, e = start + count; i < e; ++i) {
126351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                char c = text[i];
126451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (c >= minDigit && c <= '\u0039') {
126551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    text[i] = (char)(c + base);
126651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
126751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
126851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (isStrongDirectional(c)) {
126951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int newkey = getContextKey(c);
127051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (newkey != lastkey) {
127151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        lastkey = newkey;
127251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
127351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ctxKey = newkey;
127451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (((mask & EASTERN_ARABIC) != 0) &&
127551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                             (ctxKey == ARABIC_KEY ||
127651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                              ctxKey == EASTERN_ARABIC_KEY)) {
127751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            ctxKey = EASTERN_ARABIC_KEY;
127851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else if (((mask & ARABIC) != 0) &&
127951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                             (ctxKey == ARABIC_KEY ||
128051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                              ctxKey == EASTERN_ARABIC_KEY)) {
128151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            ctxKey = ARABIC_KEY;
128251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else if ((mask & (1<<ctxKey)) == 0) {
128351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            ctxKey = EUROPEAN_KEY;
128451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
128551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
128651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        base = bases[ctxKey];
128751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
128851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero
128951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
129051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
129151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
129251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
129351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
129451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
129551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void shapeContextually(char[] text, int start, int count, Range ctxKey) {
129651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // if we don't support the specified context, then don't shape.
129751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (ctxKey == null || !rangeSet.contains(ctxKey)) {
129851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ctxKey = Range.EUROPEAN;
129951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
130051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
130151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Range lastKey = ctxKey;
130251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int base = ctxKey.getDigitBase();
130351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char minDigit = (char)('0' + ctxKey.getNumericBase());
130451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        final int end = start + count;
130551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = start; i < end; ++i) {
130651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = text[i];
130751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c >= minDigit && c <= '9') {
130851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                text[i] = (char)(c + base);
130951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
131051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
131151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (isStrongDirectional(c)) {
131251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ctxKey = rangeForCodePoint(c);
131351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (ctxKey != lastKey) {
131451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    lastKey = ctxKey;
131551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    base = ctxKey.getDigitBase();
131651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    minDigit = (char)('0' + ctxKey.getNumericBase());
131751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
131851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
131951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
132051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
132151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
132251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
132351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a hash code for this shaper.
132451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return this shaper's hash code.
132551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see java.lang.Object#hashCode
132651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
132751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode() {
132851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int hash = mask;
132951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet != null) {
133051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Use the CONTEXTUAL_MASK bit only for the enum-based
133151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // NumericShaper. A deserialized NumericShaper might have
133251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // bit masks.
133351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hash &= CONTEXTUAL_MASK;
133451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hash ^= rangeSet.hashCode();
133551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
133651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return hash;
133751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
133851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
133951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
134051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns {@code true} if the specified object is an instance of
134151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>NumericShaper</code> and shapes identically to this one,
134251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * regardless of the range representations, the bit mask or the
134351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * enum. For example, the following code produces {@code "true"}.
134451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote><pre>
134551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
134651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
134751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * System.out.println(ns1.equals(ns2));
134851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </pre></blockquote>
134951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
135051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param o the specified object to compare to this
135151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          <code>NumericShaper</code>
135251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return <code>true</code> if <code>o</code> is an instance
135351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         of <code>NumericShaper</code> and shapes in the same way;
135451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         <code>false</code> otherwise.
135551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see java.lang.Object#equals(java.lang.Object)
135651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
135751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean equals(Object o) {
135851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (o != null) {
135951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            try {
136051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                NumericShaper rhs = (NumericShaper)o;
136151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (rangeSet != null) {
136251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (rhs.rangeSet != null) {
136351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return isContextual() == rhs.isContextual()
136451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            && rangeSet.equals(rhs.rangeSet)
136551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            && shapingRange == rhs.shapingRange;
136651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
136751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return isContextual() == rhs.isContextual()
136851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        && rangeSet.equals(Range.maskToRangeSet(rhs.mask))
136951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        && shapingRange == Range.indexToRange(rhs.key);
137051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else if (rhs.rangeSet != null) {
137151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Set<Range> rset = Range.maskToRangeSet(mask);
137251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Range srange = Range.indexToRange(key);
137351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return isContextual() == rhs.isContextual()
137451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        && rset.equals(rhs.rangeSet)
137551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        && srange == rhs.shapingRange;
137651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
137751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return rhs.mask == mask && rhs.key == key;
137851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
137951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            catch (ClassCastException e) {
138051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
138151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
138251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return false;
138351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
138451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
138551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
138651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a <code>String</code> that describes this shaper. This method
138751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * is used for debugging purposes only.
138851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a <code>String</code> describing this shaper.
138951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
139051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String toString() {
139151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuilder buf = new StringBuilder(super.toString());
139251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
139351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        buf.append("[contextual:").append(isContextual());
139451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
139551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String[] keyNames = null;
139651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isContextual()) {
139751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buf.append(", context:");
139851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buf.append(shapingRange == null ? Range.values()[key] : shapingRange);
139951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
140051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
140151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet == null) {
140251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buf.append(", range(s): ");
140351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            boolean first = true;
140451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = 0; i < NUM_KEYS; ++i) {
140551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((mask & (1 << i)) != 0) {
140651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (first) {
140751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        first = false;
140851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
140951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buf.append(", ");
141051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
141151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    buf.append(Range.values()[i]);
141251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
141351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
141451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
141551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buf.append(", range set: ").append(rangeSet);
141651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
141751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        buf.append(']');
141851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
141951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return buf.toString();
142051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
142151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
142251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
142351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the index of the high bit in value (assuming le, actually
142451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * power of 2 >= value). value must be positive.
142551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
142651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int getHighBit(int value) {
142751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value <= 0) {
142851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return -32;
142951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
143051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
143151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int bit = 0;
143251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
143351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= 1 << 16) {
143451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value >>= 16;
143551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bit += 16;
143651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
143751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
143851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= 1 << 8) {
143951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value >>= 8;
144051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bit += 8;
144151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
144251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
144351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= 1 << 4) {
144451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value >>= 4;
144551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bit += 4;
144651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
144751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
144851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= 1 << 2) {
144951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value >>= 2;
145051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bit += 2;
145151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
145251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
145351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= 1 << 1) {
145451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            bit += 1;
145551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
145651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
145751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return bit;
145851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
145951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
146051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
146151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * fast binary search over subrange of array.
146251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
146351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static int search(int value, int[] array, int start, int length)
146451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
146551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int power = 1 << getHighBit(length);
146651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int extra = length - power;
146751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int probe = power;
146851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int index = start;
146951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
147051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (value >= array[index + extra]) {
147151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            index += extra;
147251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
147351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
147451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (probe > 1) {
147551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            probe >>= 1;
147651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
147751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (value >= array[index + probe]) {
147851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                index += probe;
147951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
148051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
148151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
148251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return index;
148351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
148451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
148551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
148651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Converts the {@code NumericShaper.Range} enum-based parameters,
148751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * if any, to the bit mask-based counterparts and writes this
148851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * object to the {@code stream}. Any enum constants that have no
148951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * bit mask-based counterparts are ignored in the conversion.
149051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
149151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param stream the output stream to write to
149251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws IOException if an I/O error occurs while writing to {@code stream}
149351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.7
149451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
149551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void writeObject(ObjectOutputStream stream) throws IOException {
149651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (shapingRange != null) {
149751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int index = Range.toRangeIndex(shapingRange);
149851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (index >= 0) {
149951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                key = index;
150051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
150151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
150251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (rangeSet != null) {
150351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            mask |= Range.toRangeMask(rangeSet);
150451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
150551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        stream.defaultWriteObject();
150651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
150751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
1508