alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (CompositeGlyphMapper.java)

This example Java source code file (CompositeGlyphMapper.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

blocksz, chartoglyphmapper, compositeglyphmapper, empty, glyphmask, hi_surrogate_end, hi_surrogate_start, invisible_glyph_id, lo_surrogate_end, lo_surrogate_start, maxunicode, nblocks, slotmask, uninitialized_glyph

The CompositeGlyphMapper.java Java example source code

/*
 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
 * 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.
 */

package sun.font;

/* remember that the API requires a Font use a
 * consistent glyph id. for a code point, and this is a
 * problem if a particular strike uses native scaler sometimes
 * and T2K others. That needs to be dealt with somewhere, but
 * here we can just always get the same glyph code without
 * needing a strike.
 *
 * The C implementation would cache the results of anything up
 * to the maximum surrogate pair code point.
 * This implementation will not cache as much, since the storage
 * requirements are not justifiable. Even so it still can use up
 * to 216*256*4 bytes of storage per composite font. If an app
 * calls canDisplay on this range for all 20 composite fonts that's
 * over 1Mb of cached data. May need to employ WeakReferences if
 * this appears to cause problems.
 */

public final class CompositeGlyphMapper extends CharToGlyphMapper {

    public static final int SLOTMASK =  0xff000000;
    public static final int GLYPHMASK = 0x00ffffff;

    public static final int NBLOCKS = 216;
    public static final int BLOCKSZ = 256;
    public static final int MAXUNICODE = NBLOCKS*BLOCKSZ;


    CompositeFont font;
    CharToGlyphMapper slotMappers[];
    int[][] glyphMaps;
    private boolean hasExcludes;

    public CompositeGlyphMapper(CompositeFont compFont) {
        font = compFont;
        initMapper();
        /* This is often false which saves the overhead of a
         * per-mapped char method call.
         */
        hasExcludes = compFont.exclusionRanges != null &&
                      compFont.maxIndices != null;
    }

    public final int compositeGlyphCode(int slot, int glyphCode) {
        return (slot << 24 | (glyphCode & GLYPHMASK));
    }

    private final void initMapper() {
        if (missingGlyph == CharToGlyphMapper.UNINITIALIZED_GLYPH) {
            if (glyphMaps == null) {
                glyphMaps = new int[NBLOCKS][];
            }
            slotMappers = new CharToGlyphMapper[font.numSlots];
            /* This requires that slot 0 is never empty. */
            missingGlyph = font.getSlotFont(0).getMissingGlyphCode();
            missingGlyph = compositeGlyphCode(0, missingGlyph);
        }
    }

    private int getCachedGlyphCode(int unicode) {
        if (unicode >= MAXUNICODE) {
            return UNINITIALIZED_GLYPH; // don't cache surrogates
        }
        int[] gmap;
        if ((gmap = glyphMaps[unicode >> 8]) == null) {
            return UNINITIALIZED_GLYPH;
        }
        return gmap[unicode & 0xff];
    }

    private void setCachedGlyphCode(int unicode, int glyphCode) {
        if (unicode >= MAXUNICODE) {
            return;     // don't cache surrogates
        }
        int index0 = unicode >> 8;
        if (glyphMaps[index0] == null) {
            glyphMaps[index0] = new int[BLOCKSZ];
            for (int i=0;i<BLOCKSZ;i++) {
                glyphMaps[index0][i] = UNINITIALIZED_GLYPH;
            }
        }
        glyphMaps[index0][unicode & 0xff] = glyphCode;
    }

    private final CharToGlyphMapper getSlotMapper(int slot) {
        CharToGlyphMapper mapper = slotMappers[slot];
        if (mapper == null) {
            mapper = font.getSlotFont(slot).getMapper();
            slotMappers[slot] = mapper;
        }
        return mapper;
    }

    private final int convertToGlyph(int unicode) {

        for (int slot = 0; slot < font.numSlots; slot++) {
            if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
                CharToGlyphMapper mapper = getSlotMapper(slot);
                int glyphCode = mapper.charToGlyph(unicode);
                if (glyphCode != mapper.getMissingGlyphCode()) {
                    glyphCode = compositeGlyphCode(slot, glyphCode);
                    setCachedGlyphCode(unicode, glyphCode);
                    return glyphCode;
                }
            }
        }
        return missingGlyph;
    }

    public int getNumGlyphs() {
        int numGlyphs = 0;
        /* The number of glyphs in a composite is affected by
         * exclusion ranges and duplicates (ie the same code point is
         * mapped by two different fonts) and also whether or not to
         * count fallback fonts. A nearly correct answer would be very
         * expensive to generate. A rough ballpark answer would
         * just count the glyphs in all the slots. However this would
         * initialize mappers for all slots when they aren't necessarily
         * needed. For now just use the first slot as JDK 1.4 did.
         */
        for (int slot=0; slot<1 /*font.numSlots*/; slot++) {
           CharToGlyphMapper mapper = slotMappers[slot];
           if (mapper == null) {
               mapper = font.getSlotFont(slot).getMapper();
               slotMappers[slot] = mapper;
           }
           numGlyphs += mapper.getNumGlyphs();
        }
        return numGlyphs;
    }

    public int charToGlyph(int unicode) {

        int glyphCode = getCachedGlyphCode(unicode);
        if (glyphCode == UNINITIALIZED_GLYPH) {
            glyphCode = convertToGlyph(unicode);
        }
        return glyphCode;
    }

    public int charToGlyph(int unicode, int prefSlot) {
        if (prefSlot >= 0) {
            CharToGlyphMapper mapper = getSlotMapper(prefSlot);
            int glyphCode = mapper.charToGlyph(unicode);
            if (glyphCode != mapper.getMissingGlyphCode()) {
                return compositeGlyphCode(prefSlot, glyphCode);
            }
        }
        return charToGlyph(unicode);
    }

    public int charToGlyph(char unicode) {

        int glyphCode  = getCachedGlyphCode(unicode);
        if (glyphCode == UNINITIALIZED_GLYPH) {
            glyphCode = convertToGlyph(unicode);
        }
        return glyphCode;
    }

    /* This variant checks if shaping is needed and immediately
     * returns true if it does. A caller of this method should be expecting
     * to check the return type because it needs to know how to handle
     * the character data for display.
     */
    public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {

        for (int i=0; i<count; i++) {
            int code = unicodes[i]; // char is unsigned.

            if (code >= HI_SURROGATE_START &&
                code <= HI_SURROGATE_END && i < count - 1) {
                char low = unicodes[i + 1];

                if (low >= LO_SURROGATE_START &&
                    low <= LO_SURROGATE_END) {
                    code = (code - HI_SURROGATE_START) *
                        0x400 + low - LO_SURROGATE_START + 0x10000;
                    glyphs[i + 1] = INVISIBLE_GLYPH_ID;
                }
            }

            int gc = glyphs[i] = getCachedGlyphCode(code);
            if (gc == UNINITIALIZED_GLYPH) {
                glyphs[i] = convertToGlyph(code);
            }

            if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
                continue;
            }
            else if (FontUtilities.isComplexCharCode(code)) {
                return true;
            }
            else if (code >= 0x10000) {
                i += 1; // Empty glyph slot after surrogate
                continue;
            }
        }

        return false;
    }

    /* The conversion is not very efficient - looping as it does, converting
     * one char at a time. However the cache should fill very rapidly.
     */
    public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
        for (int i=0; i<count; i++) {
            int code = unicodes[i]; // char is unsigned.

            if (code >= HI_SURROGATE_START &&
                code <= HI_SURROGATE_END && i < count - 1) {
                char low = unicodes[i + 1];

                if (low >= LO_SURROGATE_START &&
                    low <= LO_SURROGATE_END) {
                    code = (code - HI_SURROGATE_START) *
                        0x400 + low - LO_SURROGATE_START + 0x10000;

                    int gc = glyphs[i] = getCachedGlyphCode(code);
                    if (gc == UNINITIALIZED_GLYPH) {
                        glyphs[i] = convertToGlyph(code);
                    }
                    i += 1; // Empty glyph slot after surrogate
                    glyphs[i] = INVISIBLE_GLYPH_ID;
                    continue;
                }
            }

            int gc = glyphs[i] = getCachedGlyphCode(code);
            if (gc == UNINITIALIZED_GLYPH) {
                glyphs[i] = convertToGlyph(code);
            }
        }
    }

    public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
        for (int i=0; i<count; i++) {
            int code = unicodes[i];

            glyphs[i] = getCachedGlyphCode(code);
            if (glyphs[i] == UNINITIALIZED_GLYPH) {
                glyphs[i] = convertToGlyph(code);
            }
        }
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java CompositeGlyphMapper.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.