1 /*
   2  * Copyright (c) 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 com.sun.javafx.font.coretext;
  27 
  28 import com.sun.javafx.font.FontStrikeDesc;
  29 import com.sun.javafx.font.PrismFontFile;
  30 import com.sun.javafx.font.PrismFontStrike;
  31 import com.sun.javafx.geom.Path2D;
  32 import com.sun.javafx.geom.transform.BaseTransform;
  33 
  34 class CTFontFile extends PrismFontFile {
  35 
  36     /* Transform used for outline and bounds */
  37     private final static CGAffineTransform tx = new CGAffineTransform();
  38     static {
  39         tx.a = 1;   /* scale x */
  40         tx.d = -1;  /* scale y */
  41     }
  42 
  43     CTFontFile(String name, String filename, int fIndex, boolean register,
  44                boolean embedded, boolean copy, boolean tracked) throws Exception {
  45         super(name, filename, fIndex, register, embedded, copy, tracked);
  46     }
  47 
  48     public static boolean registerFont(String fontfile) {
  49         if (fontfile == null) return false;
  50         long alloc = OS.kCFAllocatorDefault();
  51         boolean result = false;
  52         long fileRef = OS.CFStringCreate(fontfile);
  53         if (fileRef != 0) {
  54             int pathStyle = OS.kCFURLPOSIXPathStyle;
  55             long urlRef = OS.CFURLCreateWithFileSystemPath(alloc, fileRef, pathStyle, false);
  56             if (urlRef != 0) {
  57                 int scope = OS.kCTFontManagerScopeProcess;
  58                 result = OS.CTFontManagerRegisterFontsForURL(urlRef, scope, 0);
  59                 OS.CFRelease(urlRef);
  60             }
  61             OS.CFRelease(fileRef);
  62         }
  63         return result;
  64     }
  65 
  66     CGRect getBBox(int gc, float size) {
  67         CTFontStrike strike = (CTFontStrike)getStrike(size, BaseTransform.IDENTITY_TRANSFORM);
  68         long fontRef = strike.getFontRef();
  69         if (fontRef == 0) return null;
  70         long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, tx);
  71         if (pathRef == 0) return null;
  72         CGRect rect = OS.CGPathGetPathBoundingBox(pathRef);
  73         OS.CGPathRelease(pathRef);
  74         return rect;
  75     }
  76 
  77     Path2D getGlyphOutline(int gc, float size) {
  78         CTFontStrike strike = (CTFontStrike)getStrike(size, BaseTransform.IDENTITY_TRANSFORM);
  79         long fontRef = strike.getFontRef();
  80         if (fontRef == 0) return null;
  81         long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, tx);
  82         if (pathRef == 0) return null;
  83         Path2D path = OS.CGPathApply(pathRef);
  84         OS.CGPathRelease(pathRef);
  85         return path;
  86     }
  87 
  88     @Override protected int[] createGlyphBoundingBox(int gc) {
  89         float size = 12;
  90         CTFontStrike strike = (CTFontStrike)getStrike(size,
  91                                                       BaseTransform.IDENTITY_TRANSFORM);
  92 
  93         long fontRef = strike.getFontRef();
  94         if (fontRef == 0) return null;
  95         int[] bb = new int[4];
  96 
  97         /* For some reason CTFontGetBoundingRectsForGlyphs has poor performance.
  98          * The fix is to use the 'loca' and the 'glyf' tables to determine
  99          * the glyph bounding box (same as T2K). This implementation
 100          * uses native code to read these tables since they can be large.
 101          * In case it fails, or the font doesn't have a glyph table
 102          * (CFF fonts), then the bounds of the glyph outline is used instead.
 103          */
 104         if (!isCFF()) {
 105             short format = getIndexToLocFormat();
 106             if (OS.CTFontGetBoundingRectForGlyphUsingTables(fontRef, (short)gc, format, bb)) {
 107                 return bb;
 108             }
 109         }
 110         /* Note: not using tx here as the bounds need to be y up */
 111         long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, null);
 112         if (pathRef == 0) return null;
 113         CGRect rect = OS.CGPathGetPathBoundingBox(pathRef);
 114         OS.CGPathRelease(pathRef);
 115         float scale = getUnitsPerEm() / size;
 116         bb[0] = (int)(Math.round(rect.origin.x * scale));
 117         bb[1] = (int)(Math.round(rect.origin.y * scale));
 118         bb[2] = (int)(Math.round((rect.origin.x + rect.size.width) * scale));
 119         bb[3] = (int)(Math.round((rect.origin.y + rect.size.height) * scale));
 120         return bb;
 121     }
 122 
 123     @Override
 124     protected PrismFontStrike<CTFontFile> createStrike(float size,
 125             BaseTransform transform, int aaMode, FontStrikeDesc desc) {
 126         return new CTFontStrike(this, size, transform, aaMode, desc);
 127     }
 128 
 129 }