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.DisposerRecord;
  29 import com.sun.javafx.font.FontResource;
  30 import com.sun.javafx.font.FontStrikeDesc;
  31 import com.sun.javafx.font.Glyph;
  32 import com.sun.javafx.font.PrismFontFactory;
  33 import com.sun.javafx.font.PrismFontStrike;
  34 import com.sun.javafx.geom.Path2D;
  35 import com.sun.javafx.geom.Point2D;
  36 import com.sun.javafx.geom.transform.BaseTransform;
  37 
  38 class CTFontStrike extends PrismFontStrike<CTFontFile> {
  39 
  40     private long fontRef;
  41     CGAffineTransform matrix;
  42     /* CoreText uses different precision for subpixel text according
  43      * to the font size. By observation, font sizes smaller than 12
  44      * have 4 subpixel positions. Between 12 and 17 it decreases to 3.
  45      * Between 18 and 33 it is only 2. Above 33 it rounds all positions
  46      * to integral values.
  47      */
  48     static final float SUBPIXEL4_SIZE = 12;
  49     static final float SUBPIXEL3_SIZE = 18;
  50     static final float SUBPIXEL2_SIZE = 34;
  51     private static final boolean SUBPIXEL;
  52     static {
  53         int mode = PrismFontFactory.getFontFactory().getSubPixelMode();
  54         SUBPIXEL =  (mode & PrismFontFactory.SUB_PIXEL_ON) != 0;
  55     }
  56 
  57     CTFontStrike(CTFontFile fontResource, float size,
  58                  BaseTransform graphicsTransform, int aaMode,
  59                  FontStrikeDesc desc) {
  60         super(fontResource, size, graphicsTransform, aaMode, desc);
  61         float maxDim = PrismFontFactory.getFontSizeLimit();
  62         if (graphicsTransform.isTranslateOrIdentity()) {
  63             drawShapes = size > maxDim;
  64         } else {
  65             BaseTransform tx2d = getTransform();
  66             matrix = new CGAffineTransform();
  67             matrix.a = tx2d.getMxx();
  68             matrix.b = -tx2d.getMyx(); /*Inverted coordinates system */
  69             matrix.c = -tx2d.getMxy(); /*Inverted coordinates system */
  70             matrix.d = tx2d.getMyy();
  71 
  72             if (Math.abs(matrix.a * size) > maxDim ||
  73                 Math.abs(matrix.b * size) > maxDim ||
  74                 Math.abs(matrix.c * size) > maxDim ||
  75                 Math.abs(matrix.d * size) > maxDim)
  76             {
  77               drawShapes = true;
  78             }
  79         }
  80 
  81         long psNameRef = OS.CFStringCreate(fontResource.getPSName());
  82         if (psNameRef != 0) {
  83             long fileNameRef = OS.CFStringCreate(fontResource.getFileName());
  84             if (fileNameRef != 0) {
  85                 fontRef = OS.CTFontCreate(fileNameRef, psNameRef, size, matrix);
  86                 OS.CFRelease(fileNameRef);
  87             }
  88             OS.CFRelease(psNameRef);
  89         }
  90         if (fontRef == 0) {
  91             if (PrismFontFactory.debugFonts) {
  92                 System.err.println("Failed to create CTFont for " + this);
  93             }
  94         }
  95     }
  96 
  97     long getFontRef() {
  98         return fontRef;
  99     }
 100 
 101     @Override protected DisposerRecord createDisposer(FontStrikeDesc desc) {
 102         CTFontFile fontResource = getFontResource();
 103         return new CTStrikeDisposer(fontResource, desc, fontRef);
 104     }
 105 
 106     @Override protected Glyph createGlyph(int glyphCode) {
 107         return new CTGlyph(this, glyphCode, drawShapes);
 108     }
 109 
 110     @Override
 111     public int getQuantizedPosition(Point2D point) {
 112         if (SUBPIXEL && matrix == null) {
 113             /* Prism only produces 3 position, so for sizes smaller than 12 use
 114              * Coretext for LCD and grayscale text
 115              */
 116             if (getSize() < SUBPIXEL4_SIZE) {
 117                 float subPixelX = point.x;
 118                 point.x = (int) point.x;
 119                 subPixelX -= point.x;
 120                 point.y = (float) Math.round(point.y);
 121                 if (subPixelX >= 0.75f) return 3;
 122                 if (subPixelX >= 0.50f) return 2;
 123                 if (subPixelX >= 0.25f) return 1;
 124                 return 0;
 125             }
 126             if (getAAMode() == FontResource.AA_GREYSCALE) {
 127                 if (getSize() < SUBPIXEL3_SIZE) {
 128                     float subPixelX = point.x;
 129                     point.x = (int) point.x;
 130                     subPixelX -= point.x;
 131                     point.y = (float) Math.round(point.y);
 132                     if (subPixelX >= 0.66f) return 2;
 133                     if (subPixelX >= 0.33f) return 1;
 134                     return 0;
 135                 }
 136                 if (getSize() < SUBPIXEL2_SIZE) {
 137                     float subPixelX = point.x;
 138                     point.x = (int) point.x;
 139                     subPixelX -= point.x;
 140                     point.y = (float) Math.round(point.y);
 141                     if (subPixelX >= 0.5f) return 1;
 142                 }
 143                 return 0;
 144             }
 145         }
 146         return super.getQuantizedPosition(point);
 147     }
 148 
 149     float getSubPixelPosition(int index) {
 150         if (index == 0) return 0;
 151         float size = getSize();
 152         if (size < SUBPIXEL4_SIZE) {
 153             if (index == 3) return 0.75f;
 154             if (index == 2) return 0.50f;
 155             if (index == 1) return 0.25f;
 156             return 0;
 157         }
 158         if (getAAMode() == FontResource.AA_LCD) return 0;
 159         if (size < SUBPIXEL3_SIZE) {
 160             if (index == 2) return 0.66f;
 161             if (index == 1) return 0.33f;
 162             return 0;
 163         }
 164         if (size < SUBPIXEL2_SIZE) {
 165             if (index == 1) return 0.50f;
 166         }
 167         return 0;
 168     }
 169 
 170     boolean isSubPixelGlyph() {
 171         return SUBPIXEL && matrix == null;
 172     }
 173 
 174     @Override protected Path2D createGlyphOutline(int glyphCode) {
 175         CTFontFile fontResource = getFontResource();
 176         return fontResource.getGlyphOutline(glyphCode, getSize());
 177     }
 178 
 179     CGRect getBBox(int glyphCode) {
 180         CTFontFile fontResource = getFontResource();
 181         return fontResource.getBBox(glyphCode, getSize());
 182     }
 183 }