jdk/src/macosx/classes/sun/font/CStrike.java
changeset 19011 b738ae865548
parent 15973 ea0278a3c432
child 25186 63e1a2ec30f5
equal deleted inserted replaced
19010:8148c141f16e 19011:b738ae865548
     1 /*
     1 /*
     2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    29 import java.awt.geom.*;
    29 import java.awt.geom.*;
    30 import java.util.*;
    30 import java.util.*;
    31 
    31 
    32 import sun.awt.SunHints;
    32 import sun.awt.SunHints;
    33 
    33 
    34 public class CStrike extends FontStrike {
    34 public final class CStrike extends FontStrike {
    35 
    35 
    36     // Creates the native strike
    36     // Creates the native strike
    37     private static native long createNativeStrikePtr(long nativeFontPtr,
    37     private static native long createNativeStrikePtr(long nativeFontPtr,
    38                                                      double[] glyphTx,
    38                                                      double[] glyphTx,
    39                                                      double[] invDevTxMatrix,
    39                                                      double[] invDevTxMatrix,
    66     private static native void getNativeGlyphImageBounds(long nativeStrikePtr,
    66     private static native void getNativeGlyphImageBounds(long nativeStrikePtr,
    67                                                          int glyphCode,
    67                                                          int glyphCode,
    68                                                          Rectangle2D.Float result,
    68                                                          Rectangle2D.Float result,
    69                                                          double x, double y);
    69                                                          double x, double y);
    70 
    70 
    71     private CFont nativeFont;
    71     private final CFont nativeFont;
    72     private AffineTransform invDevTx;
    72     private AffineTransform invDevTx;
    73     private GlyphInfoCache glyphInfoCache;
    73     private final GlyphInfoCache glyphInfoCache;
    74     private GlyphAdvanceCache glyphAdvanceCache;
    74     private final GlyphAdvanceCache glyphAdvanceCache;
    75     private long nativeStrikePtr;
    75     private long nativeStrikePtr;
    76 
    76 
    77     CStrike(final CFont font, final FontStrikeDesc inDesc) {
    77     CStrike(final CFont font, final FontStrikeDesc inDesc) {
    78         nativeFont = font;
    78         nativeFont = font;
    79         desc = inDesc;
    79         desc = inDesc;
    82         disposer = glyphInfoCache;
    82         disposer = glyphInfoCache;
    83 
    83 
    84         // Normally the device transform should be the identity transform
    84         // Normally the device transform should be the identity transform
    85         // for screen operations.  The device transform only becomes
    85         // for screen operations.  The device transform only becomes
    86         // interesting when we are outputting between different dpi surfaces,
    86         // interesting when we are outputting between different dpi surfaces,
    87         // like when we are printing to postscript.
    87         // like when we are printing to postscript or use retina.
    88         if (inDesc.devTx != null && !inDesc.devTx.isIdentity()) {
    88         if (inDesc.devTx != null && !inDesc.devTx.isIdentity()) {
    89             try {
    89             try {
    90                 invDevTx = inDesc.devTx.createInverse();
    90                 invDevTx = inDesc.devTx.createInverse();
    91             } catch (NoninvertibleTransformException e) {
    91             } catch (NoninvertibleTransformException ignored) {
    92                 // ignored, since device transforms should not be that
    92                 // ignored, since device transforms should not be that
    93                 // complicated, and if they are - there is nothing we can do,
    93                 // complicated, and if they are - there is nothing we can do,
    94                 // so we won't worry about it.
    94                 // so we won't worry about it.
    95             }
    95             }
    96         }
    96         }
   132             disposeNativeStrikePtr(nativeStrikePtr);
   132             disposeNativeStrikePtr(nativeStrikePtr);
   133         }
   133         }
   134         nativeStrikePtr = 0;
   134         nativeStrikePtr = 0;
   135     }
   135     }
   136 
   136 
   137     // the fractional metrics default on our platform is OFF
   137 
   138     private boolean useFractionalMetrics() {
   138     @Override
   139         return desc.fmHint == SunHints.INTVAL_FRACTIONALMETRICS_ON;
       
   140     }
       
   141 
       
   142     public int getNumGlyphs() {
   139     public int getNumGlyphs() {
   143         return nativeFont.getNumGlyphs();
   140         return nativeFont.getNumGlyphs();
   144     }
   141     }
   145 
   142 
       
   143     @Override
   146     StrikeMetrics getFontMetrics() {
   144     StrikeMetrics getFontMetrics() {
   147         if (strikeMetrics == null) {
   145         if (strikeMetrics == null) {
   148             StrikeMetrics metrics = getFontMetrics(getNativeStrikePtr());
   146             StrikeMetrics metrics = getFontMetrics(getNativeStrikePtr());
   149             if (invDevTx != null) {
   147             if (invDevTx != null) {
   150                 metrics.convertToUserSpace(invDevTx);
   148                 metrics.convertToUserSpace(invDevTx);
   153             strikeMetrics = metrics;
   151             strikeMetrics = metrics;
   154         }
   152         }
   155         return strikeMetrics;
   153         return strikeMetrics;
   156     }
   154     }
   157 
   155 
   158     float getGlyphAdvance(int glyphCode) {
   156     @Override
   159         return getScaledAdvanceForAdvance(getCachedNativeGlyphAdvance(glyphCode));
   157     float getGlyphAdvance(final int glyphCode) {
   160     }
   158         return getCachedNativeGlyphAdvance(glyphCode);
   161 
   159     }
   162     float getCodePointAdvance(int cp) {
   160 
   163         float advance = getCachedNativeGlyphAdvance(nativeFont.getMapper().charToGlyph(cp));
   161     @Override
   164 
   162     float getCodePointAdvance(final int cp) {
   165         double glyphScaleX = desc.glyphTx.getScaleX();
   163         return getGlyphAdvance(nativeFont.getMapper().charToGlyph(cp));
   166         double devScaleX = desc.devTx.getScaleX();
   164     }
   167 
   165 
   168         if (devScaleX == 0) {
   166     @Override
   169             glyphScaleX = Math.sqrt(desc.glyphTx.getDeterminant());
   167     Point2D.Float getCharMetrics(final char ch) {
   170             devScaleX = Math.sqrt(desc.devTx.getDeterminant());
   168         return getGlyphMetrics(nativeFont.getMapper().charToGlyph(ch));
   171         }
   169     }
   172 
   170 
   173         if (devScaleX == 0) {
   171     @Override
   174             devScaleX = Double.NaN; // this an undefined graphics state
   172     Point2D.Float getGlyphMetrics(final int glyphCode) {
   175         }
   173         return new Point2D.Float(getGlyphAdvance(glyphCode), 0.0f);
   176         advance = (float) (advance * glyphScaleX / devScaleX);
       
   177         return useFractionalMetrics() ? advance : Math.round(advance);
       
   178     }
       
   179 
       
   180     // calculate an advance, and round if not using fractional metrics
       
   181     private float getScaledAdvanceForAdvance(float advance) {
       
   182         if (invDevTx != null) {
       
   183             advance *= invDevTx.getScaleX();
       
   184         }
       
   185         advance *= desc.glyphTx.getScaleX();
       
   186         return useFractionalMetrics() ? advance : Math.round(advance);
       
   187     }
       
   188 
       
   189     Point2D.Float getCharMetrics(char ch) {
       
   190         return getScaledPointForAdvance(getCachedNativeGlyphAdvance(nativeFont.getMapper().charToGlyph(ch)));
       
   191     }
       
   192 
       
   193     Point2D.Float getGlyphMetrics(int glyphCode) {
       
   194         return getScaledPointForAdvance(getCachedNativeGlyphAdvance(glyphCode));
       
   195     }
       
   196 
       
   197     // calculate an advance point, and round if not using fractional metrics
       
   198     private Point2D.Float getScaledPointForAdvance(float advance) {
       
   199         Point2D.Float pt = new Point2D.Float(advance, 0);
       
   200 
       
   201         if (!desc.glyphTx.isIdentity()) {
       
   202             return scalePoint(pt);
       
   203         }
       
   204 
       
   205         if (!useFractionalMetrics()) {
       
   206             pt.x = Math.round(pt.x);
       
   207         }
       
   208         return pt;
       
   209     }
       
   210 
       
   211     private Point2D.Float scalePoint(Point2D.Float pt) {
       
   212         if (invDevTx != null) {
       
   213             // transform the point out of the device space first
       
   214             invDevTx.transform(pt, pt);
       
   215         }
       
   216         desc.glyphTx.transform(pt, pt);
       
   217         pt.x -= desc.glyphTx.getTranslateX();
       
   218         pt.y -= desc.glyphTx.getTranslateY();
       
   219 
       
   220         if (!useFractionalMetrics()) {
       
   221             pt.x = Math.round(pt.x);
       
   222             pt.y = Math.round(pt.y);
       
   223         }
       
   224 
       
   225         return pt;
       
   226     }
   174     }
   227 
   175 
   228     Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
   176     Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
   229         GeneralPath gp = getGlyphOutline(glyphCode, 0f, 0f);
   177         GeneralPath gp = getGlyphOutline(glyphCode, 0f, 0f);
   230         Rectangle2D r2d = gp.getBounds2D();
   178         Rectangle2D r2d = gp.getBounds2D();
   412 
   360 
   413         private final long[] firstLayerCache;
   361         private final long[] firstLayerCache;
   414         private SparseBitShiftingTwoLayerArray secondLayerCache;
   362         private SparseBitShiftingTwoLayerArray secondLayerCache;
   415         private HashMap<Integer, Long> generalCache;
   363         private HashMap<Integer, Long> generalCache;
   416 
   364 
   417         public GlyphInfoCache(final Font2D nativeFont,
   365         GlyphInfoCache(final Font2D nativeFont, final FontStrikeDesc desc) {
   418                               final FontStrikeDesc desc)
       
   419         {
       
   420             super(nativeFont, desc);
   366             super(nativeFont, desc);
   421             firstLayerCache = new long[FIRST_LAYER_SIZE];
   367             firstLayerCache = new long[FIRST_LAYER_SIZE];
   422         }
   368         }
   423 
   369 
   424         public synchronized long get(final int index) {
   370         public synchronized long get(final int index) {
   525         private static class SparseBitShiftingTwoLayerArray {
   471         private static class SparseBitShiftingTwoLayerArray {
   526             final long[][] cache;
   472             final long[][] cache;
   527             final int shift;
   473             final int shift;
   528             final int secondLayerLength;
   474             final int secondLayerLength;
   529 
   475 
   530             public SparseBitShiftingTwoLayerArray(final int size, final int shift) {
   476             SparseBitShiftingTwoLayerArray(final int size, final int shift) {
   531                 this.shift = shift;
   477                 this.shift = shift;
   532                 this.cache = new long[1 << shift][];
   478                 this.cache = new long[1 << shift][];
   533                 this.secondLayerLength = size >> shift;
   479                 this.secondLayerLength = size >> shift;
   534             }
   480             }
   535 
   481 
   556         private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
   502         private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
   557 
   503 
   558         private final float[] firstLayerCache = new float[FIRST_LAYER_SIZE];
   504         private final float[] firstLayerCache = new float[FIRST_LAYER_SIZE];
   559         private SparseBitShiftingTwoLayerArray secondLayerCache;
   505         private SparseBitShiftingTwoLayerArray secondLayerCache;
   560         private HashMap<Integer, Float> generalCache;
   506         private HashMap<Integer, Float> generalCache;
       
   507 
       
   508         // Empty non private constructor was added because access to this
       
   509         // class shouldn't be emulated by a synthetic accessor method.
       
   510         GlyphAdvanceCache() {
       
   511             super();
       
   512         }
   561 
   513 
   562         public synchronized float get(final int index) {
   514         public synchronized float get(final int index) {
   563             if (index < 0) {
   515             if (index < 0) {
   564                 if (-index < SECOND_LAYER_SIZE) {
   516                 if (-index < SECOND_LAYER_SIZE) {
   565                     // catch common unicodes
   517                     // catch common unicodes
   607         private static class SparseBitShiftingTwoLayerArray {
   559         private static class SparseBitShiftingTwoLayerArray {
   608             final float[][] cache;
   560             final float[][] cache;
   609             final int shift;
   561             final int shift;
   610             final int secondLayerLength;
   562             final int secondLayerLength;
   611 
   563 
   612             public SparseBitShiftingTwoLayerArray(final int size,
   564             SparseBitShiftingTwoLayerArray(final int size, final int shift) {
   613                                                   final int shift)
       
   614             {
       
   615                 this.shift = shift;
   565                 this.shift = shift;
   616                 this.cache = new float[1 << shift][];
   566                 this.cache = new float[1 << shift][];
   617                 this.secondLayerLength = size >> shift;
   567                 this.secondLayerLength = size >> shift;
   618             }
   568             }
   619 
   569