/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* fffe and ffff are values we specially interpret as meaning
* invisible glyphs.
*/
/* REMIND: replace this scheme with one that installs a cache
* instance of the appropriate type. It will require changes in
* FontStrikeDisposer and NativeStrike etc.
*/
/* segmented arrays are blocks of 32 */
private boolean segmentedCache;
private int[][] segIntGlyphImages;
private long[][] segLongGlyphImages;
/* The "metrics" information requested by clients is usually nothing
* more than the horizontal advance of the character.
* In most cases this advance and other metrics information is stored
* in the glyph image cache.
* But in some cases we do not automatically retrieve the glyph
* image when the advance is requested. In those cases we want to
* cache the advances since this has been shown to be important for
* performance.
* The segmented cache is used in cases when the single array
* would be too large.
*/
private float[] horizontalAdvances;
private float[][] segHorizontalAdvances;
/* Outline bounds are used when printing and when drawing outlines
* to the screen. On balance the relative rarity of these cases
* and the fact that getting this requires generating a path at
* the scaler level means that its probably OK to store these
* in a Java-level hashmap as the trade-off between time and space.
* Later can revisit whether to cache these at all, or elsewhere.
* Should also profile whether subsequent to getting the bounds, the
* outline itself is also requested. The 1.4 implementation doesn't
* cache outlines so you could generate the path twice - once to get
* the bounds and again to return the outline to the client.
* If the two uses are coincident then also look into caching outlines.
* One simple optimisation is that we could store the last single
* outline retrieved. This assumes that bounds then outline will always
* be retrieved for a glyph rather than retrieving bounds for all glyphs
* then outlines for all glyphs.
*/
boolean useNatives;
/* Used only for communication to native layer */
private int intPtSize;
/* Perform global initialisation needed for Windows native rasterizer */
private static native boolean initNative();
private static boolean isXPorLater = false;
static {
isXPorLater = initNative();
}
}
/* If using algorithmic styling, the base values are
* boldness = 1.0, italic = 0.0. The superclass constructor
* initialises these.
*/
algoStyle = true;
italic = 0.7f;
}
algoStyle = true;
boldness = 1.33f;
}
}
double[] matrix = new double[4];
try {
} catch (NoninvertibleTransformException e) {
}
}
/* Amble fonts are better rendered unhinted although there's the
* inevitable fuzziness that accompanies this due to no longer
* snapping stems to the pixel grid. The exception is that in B&W
* mode they are worse without hinting. The down side to that is that
* B&W metrics will differ which normally isn't the case, although
* since AA mode is part of the measuring context that should be OK.
* We don't expect Amble to be installed in the Windows fonts folder.
* If we were to, then we'd also might want to disable using the
* native rasteriser path which is used for LCD mode for platform
* fonts. since we have no way to disable hinting by GDI.
* In the case of Amble, since its 'gasp' table says to disable
* hinting, I'd expect GDI to follow that, so likely it should
* all be consistent even if GDI used.
*/
/* If any of the values is NaN then substitute the null scaler context.
* This will return null images, zero advance, and empty outlines
* as no rendering need take place in this case.
* We pass in the null scaler as the singleton null context
* requires it. However
*/
} else {
}
/* Always segment for fonts with > 256 glyphs, but also for smaller
* fonts with non-typical sizes and transforms.
* Segmenting for all non-typical pt sizes helps to minimise memory
* usage when very many distinct strikes are created.
* The size range of 0->5 and 37->INF for segmenting is arbitrary
* but the intention is that typical GUI integer point sizes (6->36)
* should not segment unless there's another reason to do so.
*/
/* This can only happen if we failed to allocate memory for context.
* NB: in such case we may still have some memory in java heap
* but subsequent attempt to allocate null scaler context
* may fail too (cause it is allocate in the native heap).
* It is not clear how to make this more robust but on the
* other hand getting NULL here seems to be extremely unlikely.
*/
if (pScalerContext == 0L) {
/* REMIND: when the code is updated to install cache objects
* rather than using a switch this will be more efficient.
*/
return;
}
/* First, see if native code should be used to create the glyph.
* GDI will return the integer metrics, not fractional metrics, which
* may be requested for this strike, so we would require here that :
* desc.fmHint != INTVAL_FRACTIONALMETRICS_ON
* except that the advance returned by GDI is always overwritten by
* the JDK rasteriser supplied one (see getGlyphImageFromWindows()).
*/
!FontUtilities.useT2K &&
useNatives = true;
}
/* Check its a simple scale of a pt size in the range
* where native bitmaps typically exist (6-36 pts) */
useNatives = true;
/* Maybe initialise these strikes lazily?. But we
* know we need at least one
*/
for (int i=0; i<numNatives; i++) {
nativeStrikes[i] =
}
}
}
" use natives = " + useNatives +
" Has Embedded bitmaps = " +
((TrueTypeFont)fileFont).
}
/* Always get the image and the advance together for smaller sizes
* that are likely to be important to rendering performance.
* The pixel size of 48.0 can be thought of as
* "maximumSizeForGetImageWithAdvance".
* This should be no greater than OutlineTextRender.THRESHOLD.
*/
double maxSz = 48.0;
/* Some applications request advance frequently during layout.
* If we are not getting and caching the image with the advance,
* there is a potentially significant performance penalty if the
* advance is repeatedly requested before requesting the image.
* We should at least cache the horizontal advance.
* REMIND: could use info in the font, eg hmtx, to retrieve some
* advances. But still want to cache it here.
*/
if (!getImageWithAdvance) {
if (!segmentedCache) {
horizontalAdvances = new float[numGlyphs];
/* use max float as uninitialised advance */
for (int i=0; i<numGlyphs; i++) {
}
} else {
segHorizontalAdvances = new float[numSegments][];
}
}
}
/* A number of methods are delegated by the strike to the scaler
* context which is a shared resource on a physical font.
*/
public int getNumGlyphs() {
return fileFont.getNumGlyphs();
}
if (FontUtilities.isWindows) {
return getGlyphImageFromWindows(glyphCode);
} else {
return getGlyphImageFromX11(glyphCode);
}
}
/* There's no global state conflicts, so this method is not
* presently synchronized.
*/
int style,
int size,
int glyphCode,
boolean fracMetrics);
long ptr = _getGlyphImageFromWindows
if (ptr != 0) {
/* Get the advance from the JDK rasterizer. This is mostly
* necessary for the fractional metrics case, but there are
* also some very small number (<0.25%) of marginal cases where
* there is some rounding difference between windows and JDK.
* After these are resolved, we can restrict this extra
* work to the FM case.
*/
advance);
return ptr;
} else {
}
}
/* Try the native strikes first, then try the fileFont strike */
long glyphPtr;
if (glyphPtr != 0L) {
return glyphPtr;
}
}
}
}
if (glyphCode >= INVISIBLE_GLYPHS) {
return StrikeCache.invisibleGlyphPtr;
}
long glyphPtr = 0L;
return glyphPtr;
} else {
if (useNatives) {
("Strike for " + fileFont +
" at size = " + intPtSize +
" couldn't get native glyph for code = " + glyphCode);
}
} if (glyphPtr == 0L) {
}
}
}
for (int i=0; i<len; i++) {
int glyphCode = glyphCodes[i];
if (glyphCode >= INVISIBLE_GLYPHS) {
continue;
continue;
} else {
long glyphPtr = 0L;
if (useNatives) {
} if (glyphPtr == 0L) {
}
}
}
}
/* The following method is called from CompositeStrike as a special case.
*/
int convertedCnt = 0;
for (int i=0; i<len; i++) {
int glyphCode = glyphCodes[i];
if (glyphCode >= SLOTZEROMAX) {
return convertedCnt;
} else {
convertedCnt++;
}
if (glyphCode >= INVISIBLE_GLYPHS) {
continue;
continue;
} else {
long glyphPtr = 0L;
if (useNatives) {
}
if (glyphPtr == 0L) {
}
}
}
return convertedCnt;
}
/* Only look in the cache */
switch (glyphCacheFormat) {
case INTARRAY:
case SEGINTARRAY:
} else {
return 0L;
}
case LONGARRAY:
return longGlyphImages[glyphCode];
case SEGLONGARRAY:
} else {
return 0L;
}
}
/* If reach here cache is UNINITIALISED. */
return 0L;
}
switch (glyphCacheFormat) {
case INTARRAY:
return glyphPtr;
} else {
}
case SEGINTARRAY:
}
return glyphPtr;
} else {
}
case LONGARRAY:
return glyphPtr;
} else {
return longGlyphImages[glyphCode];
}
case SEGLONGARRAY:
}
return glyphPtr;
} else {
}
}
/* Reach here only when the cache is not initialised which is only
* for the first glyph to be initialised in the strike.
* Initialise it and recurse. Note that we are already synchronized.
*/
}
/* Called only from synchronized code or constructor */
private synchronized void initGlyphCache() {
int tmpFormat = UNINITIALISED;
if (segmentedCache) {
if (longAddresses) {
segLongGlyphImages = new long[numSegments][];
} else {
segIntGlyphImages = new int[numSegments][];
}
} else {
if (longAddresses) {
longGlyphImages = new long[numGlyphs];
} else {
intGlyphImages = new int[numGlyphs];
}
}
}
return getGlyphAdvance(glyphCode, true);
}
/* Metrics info is always retrieved. If the GlyphInfo address is non-zero
* then metrics info there is valid and can just be copied.
* This is in user space coordinates unless getUserAdv == false.
* Device space advance should not be propagated out of this class.
*/
float advance;
if (glyphCode >= INVISIBLE_GLYPHS) {
return 0f;
}
/* Notes on the (getUserAdv == false) case.
*
* Setting getUserAdv == false is internal to this class.
* If there's no graphics transform we can let
* getGlyphAdvance take its course, and potentially caching in
* advances arrays, except for signalling that
* getUserAdv == false means there is no need to create an image.
* It is possible that code already calculated the user advance,
* and it is desirable to take advantage of that work.
* But, if there's a transform and we want device advance, we
* can't use any values cached in the advances arrays - unless
* first re-transform them into device space using 'desc.devTx'.
* invertDevTx is null if the graphics transform is identity,
* a translate, or non-invertible. The latter case should
* not ever occur in the getUserAdv == false path.
* In other words its either null, or the inversion of a
* simple uniform scale. If its null, we can populate and
* use the advance caches as normal.
*
* If we don't find a cached value, obtain the device advance and
* return it. This will get stashed on the image by the caller and any
* subsequent metrics calls will be able to use it as is the case
* whenever an image is what is initially requested.
*
* Don't query if there's a value cached on the image, since this
* getUserAdv==false code path is entered solely when none exists.
*/
if (horizontalAdvances != null) {
return metrics.x;
} else {
return advance;
}
}
return metrics.x;
} else {
return advance;
}
}
}
}
return metrics.x;
}
/* If there is a device transform need x & y advance to
* transform back into user space.
*/
} else {
long glyphPtr;
if (getImageWithAdvance) {
/* A heuristic optimisation says that for most cases its
* worthwhile retrieving the image at the same time as the
* advance. So here we get the image data even if its not
* already cached.
*/
} else {
}
if (glyphPtr != 0L) {
} else {
}
}
if (horizontalAdvances != null) {
for (int i=0; i<SEGSIZE; i++) {
}
}
}
return advance;
}
}
/**
* Result and pt are both in device space.
*/
/* With our current design NULL ptr is not possible
but if we eventually allow scalers to return NULL pointers
this check might be actually useful. */
if (ptr == 0L) {
return;
}
/* HRGB LCD text may have padding that is empty. This is almost always
* going to be when topLeftX is -2 or less.
* Try to return a tighter bounding box in that case.
* If the first three bytes of every row are all zero, then
* add 1 to "x" and reduce "width" by 1.
*/
&& topLeftX <= -2.0f) {
result.x += 1;
}
}
}
int rowBytes =
return origMinX;
}
long pixelData =
if (pixelData == 0L) {
return origMinX;
}
for (int y=0;y<height;y++) {
for (int x=0;x<3;x++) {
return origMinX;
}
}
}
return origMinX+1;
}
/* These 3 metrics methods below should be implemented to return
* values in user space.
*/
if (strikeMetrics == null) {
if (invertDevTx != null) {
}
}
return strikeMetrics;
}
return getGlyphMetrics(glyphCode, true);
}
// !!! or do we force sgv user glyphs?
if (glyphCode >= INVISIBLE_GLYPHS) {
return metrics;
}
long glyphPtr;
if (getImageWithAdvance && getImage) {
/* A heuristic optimisation says that for most cases its
* worthwhile retrieving the image at the same time as the
* metrics. So here we get the image data even if its not
* already cached.
*/
} else {
}
if (glyphPtr != 0L) {
/* advance is currently in device space, need to convert back
* into user space.
* This must not include the translation component. */
if (invertDevTx != null) {
}
} else {
/* We sometimes cache these metrics as they are expensive to
* generate for large glyphs.
* We never reach this path if we obtain images with advances.
* But if we do not obtain images with advances its possible that
* we first obtain this information, then the image, and never
* will access this value again.
*/
if (glyphMetricsMapRef != null) {
}
if (glyphMetricsMap != null) {
/* already in user space */
return metrics;
}
}
/* advance is currently in device space, need to convert back
* into user space.
*/
if (invertDevTx != null) {
}
/* We aren't synchronizing here so it is possible to
* overwrite the map with another one but this is harmless.
*/
if (glyphMetricsMap == null) {
}
}
}
return metrics;
}
}
/* The caller of this can be trusted to return a copy of this
* return value rectangle to public API. In fact frequently it
* can't use use this return value directly anyway.
* This returns bounds in device space. Currently the only
* caller is SGV and it converts back to user space.
* We could change things so that this code does the conversion so
* that all coords coming out of the font system are converted back
* into user space even if they were measured in device space.
* The same applies to the other methods that return outlines (below)
* But it may make particular sense for this method that caches its
* results.
* There'd be plenty of exceptions, to this too, eg getGlyphPoint needs
* device coords as its called from native layout and getGlyphImageBounds
* is used by GlyphVector.getGlyphPixelBounds which is specified to
* return device coordinates, the image pointers aren't really used
* up in Java code either.
*/
}
}
return bounds;
}
}
private
if (outlineMapRef != null) {
if (outlineMap != null) {
}
}
if (outlineMap == null) {
new WeakReference
}
}
if (x != 0f || y != 0f) {
}
return gp;
}
}
if (invertDevTx != null) {
}
}
}