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         long psNameRef = OS.CFStringCreate(fontResource.getPSName());
  81         if (psNameRef != 0) {
  82             fontRef = OS.CTFontCreateWithName(psNameRef, size, matrix);
  83             OS.CFRelease(psNameRef);
  84         }
  85         if (fontRef == 0) {
  86             if (PrismFontFactory.debugFonts) {
  87                 System.err.println("Failed to create CTFont for " + this);
  88             }
  89         }
  90     }
  91 
  92     long getFontRef() {
  93         return fontRef;
  94     }
  95 
  96     @Override protected DisposerRecord createDisposer(FontStrikeDesc desc) {
  97         CTFontFile fontResource = getFontResource();
  98         return new CTStrikeDisposer(fontResource, desc, fontRef);
  99     }
 100 
 101     @Override protected Glyph createGlyph(int glyphCode) {
 102         return new CTGlyph(this, glyphCode, drawShapes);
 103     }
 104 
 105     @Override
 106     public int getQuantizedPosition(Point2D point) {
 107         if (SUBPIXEL && matrix == null) {
 108             /* Prism only produces 3 position, so for sizes smaller than 12 use
 109              * Coretext for LCD and grayscale text
 110              */
 111             if (getSize() < SUBPIXEL4_SIZE) {
 112                 float subPixelX = point.x;
 113                 point.x = (int) point.x;
 114                 subPixelX -= point.x;
 115                 point.y = (float) Math.round(point.y);
 116                 if (subPixelX >= 0.75f) return 3;
 117                 if (subPixelX >= 0.50f) return 2;
 118                 if (subPixelX >= 0.25f) return 1;
 119                 return 0;
 120             }
 121             if (getAAMode() == FontResource.AA_GREYSCALE) {
 122                 if (getSize() < SUBPIXEL3_SIZE) {
 123                     float subPixelX = point.x;
 124                     point.x = (int) point.x;
 125                     subPixelX -= point.x;
 126                     point.y = (float) Math.round(point.y);
 127                     if (subPixelX >= 0.66f) return 2;
 128                     if (subPixelX >= 0.33f) return 1;
 129                     return 0;
 130                 }
 131                 if (getSize() < SUBPIXEL2_SIZE) {
 132                     float subPixelX = point.x;
 133                     point.x = (int) point.x;
 134                     subPixelX -= point.x;
 135                     point.y = (float) Math.round(point.y);
 136                     if (subPixelX >= 0.5f) return 1;
 137                 }
 138                 return 0;
 139             }
 140         }
 141         return super.getQuantizedPosition(point);
 142     }
 143 
 144     float getSubPixelPosition(int index) {
 145         if (index == 0) return 0;
 146         float size = getSize();
 147         if (size < SUBPIXEL4_SIZE) {
 148             if (index == 3) return 0.75f;
 149             if (index == 2) return 0.50f;
 150             if (index == 1) return 0.25f;
 151             return 0;
 152         }
 153         if (getAAMode() == FontResource.AA_LCD) return 0;
 154         if (size < SUBPIXEL3_SIZE) {
 155             if (index == 2) return 0.66f;
 156             if (index == 1) return 0.33f;
 157             return 0;
 158         }
 159         if (size < SUBPIXEL2_SIZE) {
 160             if (index == 1) return 0.50f;
 161         }
 162         return 0;
 163     }
 164 
 165     boolean isSubPixelGlyph() {
 166         return SUBPIXEL && matrix == null;
 167     }
 168 
 169     @Override protected Path2D createGlyphOutline(int glyphCode) {
 170         CTFontFile fontResource = getFontResource();
 171         return fontResource.getGlyphOutline(glyphCode, getSize());
 172     }
 173 
 174     CGRect getBBox(int glyphCode) {
 175         CTFontFile fontResource = getFontResource();
 176         return fontResource.getBBox(glyphCode, getSize());
 177     }
 178 }