jdk/src/solaris/classes/sun/font/XRGlyphCacheEntry.java
author simonis
Mon, 06 May 2013 12:57:42 -0700
changeset 17404 47af135a3e95
parent 6374 e214162c907e
child 22584 eed64ee05369
permissions -rw-r--r--
7191872: Xrender: No text displayed using 64 bit JDK on solaris11-sparc Reviewed-by: prr, ceisserer

/*
 * Copyright (c) 2010, 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;

import java.io.*;

/**
 * Stores glyph-related data, used in the pure-java glyphcache.
 *
 * @author Clemens Eisserer
 */

public class XRGlyphCacheEntry {
    long glyphInfoPtr;

    int lastUsed;
    boolean pinned;

    int xOff;
    int yOff;

    int glyphSet;

    public XRGlyphCacheEntry(long glyphInfoPtr, GlyphList gl) {
        this.glyphInfoPtr = glyphInfoPtr;

        /* TODO: Does it make sence to cache results? */
        xOff = (int) Math.round(getXAdvance());
        yOff = (int) Math.round(getYAdvance());
    }

    public int getXOff() {
        return xOff;
    }

    public int getYOff() {
        return yOff;
    }

    public void setGlyphSet(int glyphSet) {
        this.glyphSet = glyphSet;
    }

    public int getGlyphSet() {
        return glyphSet;
    }

    public static int getGlyphID(long glyphInfoPtr) {
        // We need to access the GlyphID with Unsafe.getAddress() because the
        // corresponding field in the underlying C data-structure is of type
        // 'void*' (see field 'cellInfo' of struct 'GlyphInfo'
        // in src/share/native/sun/font/fontscalerdefs.h).
        // On 64-bit Big-endian architectures it would be wrong to access this
        // field with Unsafe.getInt().
        return (int) StrikeCache.unsafe.getAddress(glyphInfoPtr +
                                                   StrikeCache.cacheCellOffset);
    }

    public static void setGlyphID(long glyphInfoPtr, int id) {
        // We need to access the GlyphID with Unsafe.putAddress() because the
        // corresponding field in the underlying C data-structure is of type
        // 'void*' (see field 'cellInfo' of struct 'GlyphInfo' in
        // src/share/native/sun/font/fontscalerdefs.h).
        // On 64-bit Big-endian architectures it would be wrong to write this
        // field with Unsafe.putInt() because it is also accessed from native
        // code as a 'long'.
        // See Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative()
        // in src/solaris/native/sun/java2d/x11/XRBackendNative.c
        StrikeCache.unsafe.putAddress(glyphInfoPtr +
                                      StrikeCache.cacheCellOffset, (long)id);
    }

    public int getGlyphID() {
        return getGlyphID(glyphInfoPtr);
    }

    public void setGlyphID(int id) {
        setGlyphID(glyphInfoPtr, id);
    }

    public float getXAdvance() {
        return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.xAdvanceOffset);
    }

    public float getYAdvance() {
        return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.yAdvanceOffset);
    }

    public int getSourceRowBytes() {
        return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.rowBytesOffset);
    }

    public int getWidth() {
        return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.widthOffset);
    }

    public int getHeight() {
        return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.heightOffset);
    }

    public void writePixelData(ByteArrayOutputStream os, boolean uploadAsLCD) {
        long pixelDataAddress =
            StrikeCache.unsafe.getAddress(glyphInfoPtr +
                                          StrikeCache.pixelDataOffset);
        if (pixelDataAddress == 0L) {
            return;
        }

        int width = getWidth();
        int height = getHeight();
        int rowBytes = getSourceRowBytes();
        int paddedWidth = getPaddedWidth(uploadAsLCD);

        if (!uploadAsLCD) {
            for (int line = 0; line < height; line++) {
                for(int x = 0; x < paddedWidth; x++) {
                    if(x < width) {
                        os.write(StrikeCache.unsafe.getByte(pixelDataAddress + (line * rowBytes + x)));
                    }else {
                         /*pad to multiple of 4 bytes per line*/
                         os.write(0);
                    }
                }
            }
        } else {
            for (int line = 0; line < height; line++) {
                int rowStart = line * rowBytes;
                int rowBytesWidth = width * 3;
                int srcpix = 0;
                while (srcpix < rowBytesWidth) {
                    os.write(StrikeCache.unsafe.getByte
                          (pixelDataAddress + (rowStart + srcpix + 2)));
                    os.write(StrikeCache.unsafe.getByte
                          (pixelDataAddress + (rowStart + srcpix + 1)));
                    os.write(StrikeCache.unsafe.getByte
                          (pixelDataAddress + (rowStart + srcpix + 0)));
                    os.write(255);
                    srcpix += 3;
                }
            }
        }
    }

    public float getTopLeftXOffset() {
        return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.topLeftXOffset);
    }

    public float getTopLeftYOffset() {
        return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.topLeftYOffset);
    }

    public long getGlyphInfoPtr() {
        return glyphInfoPtr;
    }

    public boolean isGrayscale(boolean listContainsLCDGlyphs) {
        return getSourceRowBytes() == getWidth() && !(getWidth() == 0 && getHeight() == 0 && listContainsLCDGlyphs);
    }

    public int getPaddedWidth(boolean listContainsLCDGlyphs) {
        int width = getWidth();
        return isGrayscale(listContainsLCDGlyphs) ? (int) Math.ceil(width / 4.0) * 4 : width;
    }

    public int getDestinationRowBytes(boolean listContainsLCDGlyphs) {
        boolean grayscale = isGrayscale(listContainsLCDGlyphs);
        return grayscale ? getPaddedWidth(grayscale) : getWidth() * 4;
    }

    public int getGlyphDataLenth(boolean listContainsLCDGlyphs) {
        return getDestinationRowBytes(listContainsLCDGlyphs) * getHeight();
    }

    public void setPinned() {
        pinned = true;
    }

    public void setUnpinned() {
        pinned = false;
    }

    public int getLastUsed() {
        return lastUsed;
    }

    public void setLastUsed(int lastUsed) {
        this.lastUsed = lastUsed;
    }

    public int getPixelCnt() {
        return getWidth() * getHeight();
    }

    public boolean isPinned() {
        return pinned;
    }
}