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 |