1 /* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.font; 27 28 import java.io.*; 29 30 /** 31 * Stores glyph-related data, used in the pure-java glyphcache. 32 * 33 * @author Clemens Eisserer 34 */ 35 36 public class XRGlyphCacheEntry { 37 long glyphInfoPtr; 38 39 int lastUsed; 40 boolean pinned; 41 42 int xOff; 43 int yOff; 44 45 int glyphSet; 46 47 public XRGlyphCacheEntry(long glyphInfoPtr, GlyphList gl) { 48 this.glyphInfoPtr = glyphInfoPtr; 49 50 /* TODO: Does it make sence to cache results? */ 51 xOff = (int) Math.round(getXAdvance()); 52 yOff = (int) Math.round(getYAdvance()); 53 } 54 55 public int getXOff() { 56 return xOff; 57 } 58 59 public int getYOff() { 60 return yOff; 61 } 62 63 public void setGlyphSet(int glyphSet) { 64 this.glyphSet = glyphSet; 65 } 66 67 public int getGlyphSet() { 68 return glyphSet; 69 } 70 71 public static int getGlyphID(long glyphInfoPtr) { 72 // We need to access the GlyphID with Unsafe.getAddress() because the corresponding field 73 // in the underlying C data-structure is of type 'void*' (see field 'cellInfo' of struct 74 // 'GlyphInfo' in src/share/native/sun/font/fontscalerdefs.h). 75 // On 64-bit Big-endian architectures it would be wrong to access this field with Unsafe.getInt(). 76 return (int) StrikeCache.unsafe.getAddress(glyphInfoPtr + StrikeCache.cacheCellOffset); 77 } 78 79 public static void setGlyphID(long glyphInfoPtr, int id) { 80 // We need to access the GlyphID with Unsafe.putAddress() because the corresponding field 81 // in the underlying C data-structure is of type 'void*' (see field 'cellInfo' of struct 82 // 'GlyphInfo' in src/share/native/sun/font/fontscalerdefs.h). 83 // On 64-bit Big-endian architectures it would be wrong to write this field with Unsafe.putInt() 84 // because it is also accessed from native code as a 'long' (see 85 // Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative() in 86 // src/solaris/native/sun/java2d/x11/XRBackendNative.c) 87 StrikeCache.unsafe.putAddress(glyphInfoPtr + StrikeCache.cacheCellOffset, (long)id); 88 } 89 90 public int getGlyphID() { 91 return getGlyphID(glyphInfoPtr); 92 } 93 94 public void setGlyphID(int id) { 95 setGlyphID(glyphInfoPtr, id); 96 } 97 98 public float getXAdvance() { 99 return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.xAdvanceOffset); 100 } 101 102 public float getYAdvance() { 103 return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.yAdvanceOffset); 104 } 105 106 public int getSourceRowBytes() { 107 return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.rowBytesOffset); 108 } 109 110 public int getWidth() { 111 return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.widthOffset); 112 } 113 114 public int getHeight() { 115 return StrikeCache.unsafe.getShort(glyphInfoPtr + StrikeCache.heightOffset); 116 } 117 118 public void writePixelData(ByteArrayOutputStream os, boolean uploadAsLCD) { 119 long pixelDataAddress = StrikeCache.unsafe.getAddress(glyphInfoPtr + StrikeCache.pixelDataOffset); 120 if (pixelDataAddress == 0L) { 121 return; 122 } 123 124 int width = getWidth(); 125 int height = getHeight(); 126 int rowBytes = getSourceRowBytes(); 127 int paddedWidth = getPaddedWidth(uploadAsLCD); 128 129 if (!uploadAsLCD) { 130 for (int line = 0; line < height; line++) { 131 for(int x = 0; x < paddedWidth; x++) { 132 if(x < width) { 133 os.write(StrikeCache.unsafe.getByte(pixelDataAddress + (line * rowBytes + x))); 134 }else { 135 /*pad to multiple of 4 bytes per line*/ 136 os.write(0); 137 } 138 } 139 } 140 } else { 141 for (int line = 0; line < height; line++) { 142 int rowStart = line * rowBytes; 143 int rowBytesWidth = width * 3; 144 int srcpix = 0; 145 while (srcpix < rowBytesWidth) { 146 os.write(StrikeCache.unsafe.getByte 147 (pixelDataAddress + (rowStart + srcpix + 2))); 148 os.write(StrikeCache.unsafe.getByte 149 (pixelDataAddress + (rowStart + srcpix + 1))); 150 os.write(StrikeCache.unsafe.getByte 151 (pixelDataAddress + (rowStart + srcpix + 0))); 152 os.write(255); 153 srcpix += 3; 154 } 155 } 156 } 157 } 158 159 public float getTopLeftXOffset() { 160 return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.topLeftXOffset); 161 } 162 163 public float getTopLeftYOffset() { 164 return StrikeCache.unsafe.getFloat(glyphInfoPtr + StrikeCache.topLeftYOffset); 165 } 166 167 public long getGlyphInfoPtr() { 168 return glyphInfoPtr; 169 } 170 171 public boolean isGrayscale(boolean listContainsLCDGlyphs) { 172 return getSourceRowBytes() == getWidth() && !(getWidth() == 0 && getHeight() == 0 && listContainsLCDGlyphs); 173 } 174 175 public int getPaddedWidth(boolean listContainsLCDGlyphs) { 176 int width = getWidth(); 177 return isGrayscale(listContainsLCDGlyphs) ? (int) Math.ceil(width / 4.0) * 4 : width; 178 } 179 180 public int getDestinationRowBytes(boolean listContainsLCDGlyphs) { 181 boolean grayscale = isGrayscale(listContainsLCDGlyphs); 182 return grayscale ? getPaddedWidth(grayscale) : getWidth() * 4; 183 } 184 185 public int getGlyphDataLenth(boolean listContainsLCDGlyphs) { 186 return getDestinationRowBytes(listContainsLCDGlyphs) * getHeight(); 187 } 188 189 public void setPinned() { 190 pinned = true; 191 } 192 193 public void setUnpinned() { 194 pinned = false; 195 } 196 197 public int getLastUsed() { 198 return lastUsed; 199 } 200 201 public void setLastUsed(int lastUsed) { 202 this.lastUsed = lastUsed; 203 } 204 205 public int getPixelCnt() { 206 return getWidth() * getHeight(); 207 } 208 209 public boolean isPinned() { 210 return pinned; 211 } 212 }