171 lines · 5.9 KB · Java
RawDownload
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ /* * * (C) Copyright IBM Corp. 2003 - All Rights Reserved */ package sun.font; /** * Iterates over runs of fonts in a CompositeFont, optionally taking script runs into account. */public final class FontRunIterator {    CompositeFont font;    char[] text;    int start;    int limit;     CompositeGlyphMapper mapper; // handy cache     int slot = -1;    int pos;     public void init(CompositeFont font, char[] text, int start, int limit) {        if (font == null || text == null || start < 0 || limit < start || limit > text.length) {            throw new IllegalArgumentException();        }         this.font = font;        this.text = text;        this.start = start;        this.limit = limit;         this.mapper = (CompositeGlyphMapper)font.getMapper();        this.slot = -1;        this.pos = start;    }     public PhysicalFont getFont() {        return slot == -1 ? null : font.getSlotFont(slot);    }     public int getGlyphMask() {        return slot << 24;    }     public int getPos() {        return pos;    }     /*     * characters that are in the 'common' script become part of the     * surrounding script run.  we want to fetch these from the same font     * used to get surrounding characters, where possible.  but we don't     * want to force non-common characters to come from other than their     * standard font.     *     * what we really want to do is this:     * 1) fetch a code point from the text.     * 2) get its 'native' script code     * 3) determine its 'resolved' script code     * 4) if its native script is COMMON, and its resolved script is the same as the previous     *    code point's, then see if the previous font supports this code point.  if so, use it.     * 5) otherwise resolve the font as usual     * 6) break the run when either the physical font or the resolved script changes.     *     * problems: we optimize latin-1 and cjk text assuming a fixed     * width for each character.  since latin-1 digits and punctuation     * are common, following this algorithm they will change to match     * the fonts used for the preceeding text, and potentially change metrics.     *     * this also seems to have the potential for changing arbitrary runs of text, e.g.     * any number of digits and spaces can change depending on the preceeding (or following!)     * non-COMMON character's font assignment.  this is not good.     *     * since the goal is to enable layout to be performed using as few physical fonts as     * possible, and the primary cause of switching fonts is to handle spaces, perhaps     * we should just special-case spaces and assign them from the current font, whatever     * it may be.     *     * One could also argue that the job of the composite font is to assign physical fonts     * to text runs, however it wishes.  we don't necessarily have to provide script info     * to let it do this.  it can determine based on whatever.  so having a special 'next'     * function that takes script (and limit) is redundant.  It can fetch the script again     * if need be.     *     * both this and the script iterator are turning char sequences into code point     * sequences.  maybe it would be better to feed a single code point into each iterator-- push     * the data instead of pull it?     */     public boolean next(int script, int lim) {        if (pos == lim) {            return false;        }         int ch = nextCodePoint(lim);        int sl = mapper.charToGlyph(ch) & CompositeGlyphMapper.SLOTMASK;        slot = sl >>> 24;        while ((ch = nextCodePoint(lim)) != DONE && (mapper.charToGlyph(ch) & CompositeGlyphMapper.SLOTMASK) == sl);        pushback(ch);         return true;    }     public boolean next() {        return next(Script.COMMON, limit);    }     static final int SURROGATE_START = 0x10000;    static final int LEAD_START = 0xd800;    static final int LEAD_LIMIT = 0xdc00;    static final int TAIL_START = 0xdc00;    static final int TAIL_LIMIT = 0xe000;    static final int LEAD_SURROGATE_SHIFT = 10;    static final int SURROGATE_OFFSET = SURROGATE_START - (LEAD_START << LEAD_SURROGATE_SHIFT) - TAIL_START;     static final int DONE = -1;     final int nextCodePoint() {        return nextCodePoint(limit);    }     final int nextCodePoint(int lim) {        if (pos >= lim) {            return DONE;        }        int ch = text[pos++];        if (ch >= LEAD_START && ch < LEAD_LIMIT && pos < lim) {            int nch = text[pos];            if (nch >= TAIL_START && nch < TAIL_LIMIT) {                ++pos;                ch = (ch << LEAD_SURROGATE_SHIFT) + nch + SURROGATE_OFFSET;            }        }        return ch;    }     final void pushback(int ch) {        if (ch >= 0) {            if (ch >= 0x10000) {                pos -= 2;            } else {                pos -= 1;            }        }    }}