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 sun.awt.*; 29 import sun.java2d.SunGraphics2D; 30 import sun.java2d.pipe.GlyphListPipe; 31 import sun.java2d.xr.*; 32 33 /** 34 * A delegate pipe of SG2D for drawing any text to a XRender surface 35 * 36 * @author Clemens Eisserer 37 */ 38 public class XRTextRenderer extends GlyphListPipe { 39 40 XRGlyphCache glyphCache; 41 XRCompositeManager maskBuffer; 42 XRBackend backend; 43 44 GrowableEltArray eltList; 45 46 public XRTextRenderer(XRCompositeManager buffer) { 47 glyphCache = new XRGlyphCache(buffer); 48 maskBuffer = buffer; 49 backend = buffer.getBackend(); 50 eltList = new GrowableEltArray(64); 51 } 52 53 protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { 54 if (gl.getNumGlyphs() == 0) { 55 return; 56 } 57 58 try { 59 SunToolkit.awtLock(); 60 61 XRSurfaceData x11sd = (XRSurfaceData) sg2d.surfaceData; 62 x11sd.validateAsDestination(null, sg2d.getCompClip()); 63 x11sd.maskBuffer.validateCompositeState(sg2d.composite, sg2d.transform, sg2d.paint, sg2d); 64 65 float advX = gl.getX(); 66 float advY = gl.getY(); 67 int oldPosX = 0, oldPosY = 0; 68 69 if (gl.isSubPixPos()) { 70 advX += 0.1666667f; 71 advY += 0.1666667f; 72 } else { 73 advX += 0.5f; 74 advY += 0.5f; 75 } 76 77 XRGlyphCacheEntry[] cachedGlyphs = glyphCache.cacheGlyphs(gl); 78 boolean containsLCDGlyphs = false; 79 int activeGlyphSet = cachedGlyphs[0].getGlyphSet(); 80 81 int eltIndex = -1; 82 gl.getBounds(); 83 float[] positions = gl.getPositions(); 84 for (int i = 0; i < gl.getNumGlyphs(); i++) { 85 gl.setGlyphIndex(i); 86 XRGlyphCacheEntry cacheEntry = cachedGlyphs[i]; 87 88 eltList.getGlyphs().addInt(cacheEntry.getGlyphID()); 89 int glyphSet = cacheEntry.getGlyphSet(); 90 91 containsLCDGlyphs |= (glyphSet == glyphCache.lcdGlyphSet); 92 93 int posX = 0, posY = 0; 94 if (gl.usePositions() 95 || (cacheEntry.getXAdvance() != ((float) cacheEntry.getXOff()) || cacheEntry.getYAdvance() != ((float) cacheEntry.getYOff())) 96 || eltIndex < 0 || glyphSet != activeGlyphSet) { 97 98 eltIndex = eltList.getNextIndex(); 99 eltList.setCharCnt(eltIndex, 1); 100 activeGlyphSet = glyphSet; 101 eltList.setGlyphSet(eltIndex, glyphSet); 102 103 if (gl.usePositions()) { 104 // /*In this case advX only stores rounding errors*/ 105 float x = positions[i * 2] + advX; 106 float y = positions[i * 2 + 1] + advY; 107 posX = (int) Math.floor(x); 108 posY = (int) Math.floor(y); 109 advX -= cacheEntry.getXOff(); 110 advY -= cacheEntry.getYOff(); 111 } else { 112 /* 113 * Calculate next glyph's position in the case of 114 * relative positioning. In XRender we can only position 115 * glyphs using integer coordinates, therefor we sum all 116 * the advances up as float, and convert them to integer 117 * later. This way rounding-error can be corrected, and 118 * is required to be consistent with the software loops. 119 */ 120 posX = (int) Math.floor(advX); 121 posY = (int) Math.floor(advY); 122 123 // Advance of ELT = difference between stored 124 // relative 125 // positioning information and required float. 126 advX += (cacheEntry.getXAdvance() - cacheEntry.getXOff()); 127 advY += (cacheEntry.getYAdvance() - cacheEntry.getYOff()); 128 } 129 /* 130 * Offset of the current glyph is the difference to the last 131 * glyph and this one 132 */ 133 eltList.setXOff(eltIndex, (posX - oldPosX)); 134 eltList.setYOff(eltIndex, (posY - oldPosY)); 135 136 oldPosX = posX; 137 oldPosY = posY; 138 139 } else { 140 eltList.setCharCnt(eltIndex, eltList.getCharCnt(eltIndex) + 1); 141 } 142 } 143 144 int maskFormat = containsLCDGlyphs ? XRUtils.PictStandardARGB32 : XRUtils.PictStandardA8; 145 maskBuffer.compositeText(x11sd.picture, 0, maskFormat, eltList); 146 147 eltList.clear(); 148 } finally { 149 SunToolkit.awtUnlock(); 150 } 151 } 152 }