1 /* 2 * Copyright (c) 2013, 2014, 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 com.sun.javafx.font.coretext; 27 28 import com.sun.javafx.font.CompositeFontResource; 29 import com.sun.javafx.font.CompositeStrike; 30 import com.sun.javafx.font.FontStrike; 31 import com.sun.javafx.font.PGFont; 32 import com.sun.javafx.font.PrismFontFactory; 33 import com.sun.javafx.text.GlyphLayout; 34 import com.sun.javafx.text.TextRun; 35 36 class CTGlyphLayout extends GlyphLayout { 37 38 private long createCTLine(long fontRef, char[] chars, boolean rtl, 39 int start, int length) { 40 /* Use CoreText to analize the run */ 41 long alloc = OS.kCFAllocatorDefault(); 42 long textRef = OS.CFStringCreateWithCharacters(alloc, chars, start, length); 43 long lineRef = 0; 44 if (textRef != 0) { 45 long attributes = OS.CFDictionaryCreateMutable(alloc, 4, 46 OS.kCFTypeDictionaryKeyCallBacks(), 47 OS.kCFTypeDictionaryValueCallBacks()); 48 if (attributes != 0) { 49 OS.CFDictionaryAddValue(attributes, OS.kCTFontAttributeName(), fontRef); 50 if (rtl) { 51 long paragraphStyleRef = OS.CTParagraphStyleCreate(OS.kCTWritingDirectionRightToLeft); 52 if (paragraphStyleRef != 0) { 53 OS.CFDictionaryAddValue(attributes, OS.kCTParagraphStyleAttributeName(), paragraphStyleRef); 54 OS.CFRelease(paragraphStyleRef); 55 } 56 } 57 /* Note that by default CoreText will apply kerning depending on the font*/ 58 long attString = OS.CFAttributedStringCreate(alloc, textRef, attributes); 59 if (attString != 0) { 60 lineRef = OS.CTLineCreateWithAttributedString(attString); 61 OS.CFRelease(attString); 62 } 63 OS.CFRelease(attributes); 64 } 65 OS.CFRelease(textRef); 66 } 67 return lineRef; 68 } 69 70 private int getFontSlot(long runRef, CompositeFontResource fr, String name, int slot) { 71 long runAttrs = OS.CTRunGetAttributes(runRef); 72 if (runAttrs == 0) return -1; 73 long actualFont = OS.CFDictionaryGetValue(runAttrs, OS.kCTFontAttributeName()); 74 if (actualFont == 0) return -1; 75 76 /* Use the display name from the kCTFontDisplayNameAttribute attribute 77 * instead of CTFontCopyDisplayName() to avoid localized names*/ 78 String fontName = OS.CTFontCopyAttributeDisplayName(actualFont); 79 if (fontName == null) return -1; 80 if (!fontName.equalsIgnoreCase(name)) { 81 if (fr == null) return -1; 82 slot = fr.getSlotForFont(fontName); 83 if (PrismFontFactory.debugFonts) { 84 System.err.println("\tFallback font= "+ fontName + " slot=" + slot); 85 } 86 } 87 return slot; 88 } 89 90 public void layout(TextRun run, PGFont font, FontStrike strike, char[] text) { 91 92 int baseSlot = 0; 93 CompositeFontResource composite = null; 94 if (strike instanceof CompositeStrike) { 95 composite = (CompositeFontResource)strike.getFontResource(); 96 baseSlot = getInitialSlot(composite); 97 strike = ((CompositeStrike)strike).getStrikeSlot(baseSlot); 98 } 99 float size = strike.getSize(); 100 String fontName = strike.getFontResource().getFullName(); 101 long fontRef = ((CTFontStrike)strike).getFontRef(); 102 if (fontRef == 0) return; 103 boolean rtl = (run.getLevel() & 1) != 0; 104 long lineRef = createCTLine(fontRef, text, rtl, run.getStart(), run.getLength()); 105 if (lineRef == 0) return; 106 long runs = OS.CTLineGetGlyphRuns(lineRef); 107 if (runs != 0) { 108 int glyphCount = (int)OS.CTLineGetGlyphCount(lineRef); 109 int[] glyphs = new int[glyphCount]; 110 float[] positions = new float[glyphCount * 2 + 2]; 111 int[] indices = new int[glyphCount]; 112 long runCount = OS.CFArrayGetCount(runs); 113 int glyphStart = 0, posStart = 0, indicesStart = 0; 114 for (int i = 0; i < runCount; i++) { 115 long runRef = OS.CFArrayGetValueAtIndex(runs, i); 116 if (runRef == 0) continue; 117 int slot = getFontSlot(runRef, composite, fontName, baseSlot); 118 if (slot != -1) { 119 glyphStart += OS.CTRunGetGlyphs(runRef, slot << 24, glyphStart, glyphs); 120 } else { 121 glyphStart += OS.CTRunGetGlyphCount(runRef); 122 } 123 if (size > 0) { 124 posStart += OS.CTRunGetPositions(runRef, posStart, positions); 125 } 126 indicesStart += OS.CTRunGetStringIndices(runRef, indicesStart, indices); 127 128 } 129 if (size > 0) { 130 positions[posStart] = (float)OS.CTLineGetTypographicBounds(lineRef); 131 } 132 run.shape(glyphCount, glyphs, positions, indices); 133 } 134 OS.CFRelease(lineRef); 135 } 136 }