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