diff options
author | Sven Gothel <[email protected]> | 2023-02-10 14:20:35 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-02-10 14:20:35 +0100 |
commit | feb8de27f848b5213423389cf0e19cbd88095682 (patch) | |
tree | ec7051b6fec0a78a4f78b1958a3f7999a063c1d9 /src/jogl/classes/com/jogamp/graph | |
parent | bc951476c67282d9676f33ee25fb0f697a4dbe45 (diff) |
Font/Graph, {Font, Glyph}/Typecast: Add kerning and expose values in original font-units (FU) to have them scaled later ( fu * pixelScale / unitsPerEM )
Scaling from font-units (funits, or FU) is now performed by the renderer itself,
i.e. applying the scale-factor 'fontPixelSize / font.getMetrics().getUnitsPerEM()'
to the PMV matrix to render the whole graph GLRegion.
This finally provides proper device and resolution independent font utilization.
Further, preliminary kerning has been added.
+++
Also ...
TypecastFont:
- getGlyphID(..) getGlyph(..) enforce symbol mapping to Glyph.ID_SPACE Glyph.ID_CR,
as some fonts ave an erroneous cmap (FreeSerif-Regular)
- add getKerning(..)
TODO: Add binary search
- Set TypecastFont.USE_PRESCALED_ADVANCE := false,
i.e. dropping all prescaled pixel-sized advance values mapped to font pixel-size
as we utilize font-units only for later uniform scaling.
- Drop virtual getPixelSize() and add static FontScale.toPixels(..)
- Add fullString() for debugging purposed, including some font tables
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph')
3 files changed, 317 insertions, 122 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java index 344e1e51f..5aa2be258 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRegionUtil.java @@ -74,41 +74,41 @@ public class TextRegionUtil { /** * Visit each {@link Font.Glyph}'s {@link OutlineShape} with the given {@link ShapeVisitor} - * additionally passing the progressed {@link AffineTransform}. - * The latter reflects the given font metric, pixelSize and hence character position. + * additionally passing the progressed {@link AffineTransform} in font-units. + * The latter reflects the given font metric in font-units and hence character position. * @param visitor * @param transform optional given transform * @param font the target {@link Font} - * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size. * @param str string text * @param temp1 temporary AffineTransform storage, mandatory, will be passed to {@link ShapeVisitor#visit(OutlineShape, AffineTransform)} and can be modified. * @param temp2 temporary AffineTransform storage, mandatory, can be re-used in {@link ShapeVisitor#visit(OutlineShape, AffineTransform)} by user code. */ public static void processString(final ShapeVisitor visitor, final AffineTransform transform, - final Font font, final float pixelSize, final CharSequence str, + final Font font, final CharSequence str, final AffineTransform temp1, final AffineTransform temp2) { final int charCount = str.length(); // region.setFlipped(true); final Font.Metrics metrics = font.getMetrics(); - final float lineHeight = font.getLineHeight(pixelSize); + final int lineHeight = font.getLineHeightFU(); - final float scale = metrics.getScale(pixelSize); - - float y = 0; - float advanceTotal = 0; + int y = 0; + int advanceTotal = 0; + char left_character = 0; + int left_glyphid = 0; for(int i=0; i< charCount; i++) { final char character = str.charAt(i); if( '\n' == character ) { y -= lineHeight; advanceTotal = 0; + left_glyphid = 0; + left_character = 0; } else if (character == ' ') { - advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE, pixelSize); + advanceTotal += font.getAdvanceWidthFU(Glyph.ID_SPACE); + left_glyphid = 0; + left_character = character; } else { - if(Region.DEBUG_INSTANCE) { - System.err.println("XXXXXXXXXXXXXXx char: "+character+", scale: "+scale+"; translate: "+advanceTotal+", "+y); - } // reset transform if( null != transform ) { temp1.setTransform(transform); @@ -116,51 +116,65 @@ public class TextRegionUtil { temp1.setToIdentity(); } temp1.translate(advanceTotal, y, temp2); - temp1.scale(scale, scale, temp2); final Font.Glyph glyph = font.getGlyph(character); final OutlineShape glyphShape = glyph.getShape(); if( null == glyphShape ) { + left_glyphid = 0; continue; } visitor.visit(glyphShape, temp1); - - advanceTotal += glyph.getAdvance(pixelSize, true); + final int right_glyphid = glyph.getID(); + final int kern = font.getKerningFU(left_glyphid, right_glyphid); + final int advance = glyph.getAdvanceFU(); + advanceTotal += advance + kern; + if( Region.DEBUG_INSTANCE && 0 != left_character && kern > 0f ) { + System.err.println(": '"+left_character+"'/"+left_glyphid+" -> '"+character+"'/"+right_glyphid+ + ": a "+advance+"px + k ["+kern+"em, "+kern+"px = "+(advance+kern)+"px -> "+advanceTotal+"px, y "+y); + } + // advanceTotal += glyph.getAdvance(pixelSize, true) + // + font.getKerning(left_glyphid, right_glyphid); + left_glyphid = right_glyphid; + left_character = character; } } } /** - * Add the string in 3D space w.r.t. the font and pixelSize at the end of the {@link GLRegion}. + * Add the string in 3D space w.r.t. the font using font-units at the end of the {@link GLRegion}. + * <p> + * The resulting GLRegion should be scaled by the chosen pixelSize of the font divided by the font's unitsPerEM. + * </p> * @param region the {@link GLRegion} sink * @param vertexFactory vertex impl factory {@link Factory} * @param font the target {@link Font} - * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size. * @param str string text * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored. * @param temp1 temporary AffineTransform storage, mandatory * @param temp2 temporary AffineTransform storage, mandatory */ public static void addStringToRegion(final GLRegion region, final Factory<? extends Vertex> vertexFactory, - final Font font, final float pixelSize, final CharSequence str, final float[] rgbaColor, + final Font font, final CharSequence str, final float[] rgbaColor, final AffineTransform temp1, final AffineTransform temp2) { final ShapeVisitor visitor = new ShapeVisitor() { + @Override public final void visit(final OutlineShape shape, final AffineTransform t) { region.addOutlineShape(shape, t, region.hasColorChannel() ? rgbaColor : null); } }; - processString(visitor, null, font, pixelSize, str, temp1, temp2); + processString(visitor, null, font, str, temp1, temp2); } /** - * Render the string in 3D space w.r.t. the font and pixelSize - * using a cached {@link GLRegion} for reuse. + * Render the string in 3D space w.r.t. the font using font-units at the end of an internally cached {@link GLRegion}. + * <p> + * The resulting GLRegion should be scaled by the chosen pixelSize of the font divided by the font's unitsPerEM. + * </p> * <p> * Cached {@link GLRegion}s will be destroyed w/ {@link #clear(GL2ES2)} or to free memory. * </p> * @param gl the current GL state * @param renderer TODO * @param font {@link Font} to be used - * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size. * @param str text to be rendered * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored. * @param sampleCount desired multisampling sample count for msaa-rendering. @@ -168,34 +182,35 @@ public class TextRegionUtil { * @throws Exception if TextRenderer not initialized */ public void drawString3D(final GL2ES2 gl, - final RegionRenderer renderer, final Font font, final float pixelSize, - final CharSequence str, final float[] rgbaColor, final int[/*1*/] sampleCount) { + final RegionRenderer renderer, final Font font, final CharSequence str, + final float[] rgbaColor, final int[/*1*/] sampleCount) { if( !renderer.isInitialized() ) { throw new GLException("TextRendererImpl01: not initialized!"); } final int special = 0; - GLRegion region = getCachedRegion(font, str, pixelSize, special); + GLRegion region = getCachedRegion(font, str, special); if(null == region) { region = GLRegion.create(renderModes, null); - addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor, tempT1, tempT2); - addCachedRegion(gl, font, str, pixelSize, special, region); + addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, tempT1, tempT2); + addCachedRegion(gl, font, str, special, region); } region.draw(gl, renderer, sampleCount); } /** - * Render the string in 3D space w.r.t. the font and pixelSize - * using a temporary {@link GLRegion}, which will be destroyed afterwards. + * Render the string in 3D space w.r.t. the font using font-units at the end of an internally temporary {@link GLRegion}. + * <p> + * The resulting GLRegion should be scaled by the chosen pixelSize of the font divided by the font's unitsPerEM. + * </p> * <p> * In case of a multisampling region renderer, i.e. {@link Region#VBAA_RENDERING_BIT}, recreating the {@link GLRegion} * is a huge performance impact. - * In such case better use {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, float, CharSequence, float[], int[], AffineTransform, AffineTransform)} + * In such case better use {@link #drawString3D(GL2ES2, GLRegion, RegionRenderer, Font, CharSequence, float[], int[], AffineTransform, AffineTransform)} * instead. * </p> * @param gl the current GL state * @param renderModes TODO * @param font {@link Font} to be used - * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size. * @param str text to be rendered * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored. * @param sampleCount desired multisampling sample count for msaa-rendering. @@ -205,24 +220,26 @@ public class TextRegionUtil { * @throws Exception if TextRenderer not initialized */ public static void drawString3D(final GL2ES2 gl, final int renderModes, - final RegionRenderer renderer, final Font font, final float pixelSize, - final CharSequence str, final float[] rgbaColor, final int[/*1*/] sampleCount, - final AffineTransform temp1, final AffineTransform temp2) { + final RegionRenderer renderer, final Font font, final CharSequence str, + final float[] rgbaColor, final int[/*1*/] sampleCount, final AffineTransform temp1, + final AffineTransform temp2) { if(!renderer.isInitialized()){ throw new GLException("TextRendererImpl01: not initialized!"); } final GLRegion region = GLRegion.create(renderModes, null); - addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor, temp1, temp2); + addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, temp1, temp2); region.draw(gl, renderer, sampleCount); region.destroy(gl); } /** - * Render the string in 3D space w.r.t. the font and pixelSize - * using the given {@link GLRegion}, which will {@link GLRegion#clear(GL2ES2) cleared} beforehand. + * Render the string in 3D space w.r.t. the font using font-units at the end of the given {@link GLRegion}, + * which will {@link GLRegion#clear(GL2ES2) cleared} beforehand. + * <p> + * The resulting GLRegion should be scaled by the chosen pixelSize of the font divided by the font's unitsPerEM. + * </p> * @param gl the current GL state * @param font {@link Font} to be used - * @param pixelSize Use {@link Font#getPixelSize(float, float)} for resolution correct pixel-size. * @param str text to be rendered * @param rgbaColor if {@link Region#hasColorChannel()} RGBA color must be passed, otherwise value is ignored. * @param sampleCount desired multisampling sample count for msaa-rendering. @@ -232,14 +249,14 @@ public class TextRegionUtil { * @throws Exception if TextRenderer not initialized */ public static void drawString3D(final GL2ES2 gl, final GLRegion region, final RegionRenderer renderer, - final Font font, final float pixelSize, final CharSequence str, - final float[] rgbaColor, final int[/*1*/] sampleCount, - final AffineTransform temp1, final AffineTransform temp2) { + final Font font, final CharSequence str, final float[] rgbaColor, + final int[/*1*/] sampleCount, final AffineTransform temp1, + final AffineTransform temp2) { if(!renderer.isInitialized()){ throw new GLException("TextRendererImpl01: not initialized!"); } region.clear(gl); - addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, pixelSize, str, rgbaColor, temp1, temp2); + addStringToRegion(region, renderer.getRenderState().getVertexFactory(), font, str, rgbaColor, temp1, temp2); region.draw(gl, renderer, sampleCount); } @@ -297,13 +314,13 @@ public class TextRegionUtil { } } - protected final GLRegion getCachedRegion(final Font font, final CharSequence str, final float pixelSize, final int special) { - return stringCacheMap.get(getKey(font, str, pixelSize, special)); + protected final GLRegion getCachedRegion(final Font font, final CharSequence str, final int special) { + return stringCacheMap.get(getKey(font, str, special)); } - protected final void addCachedRegion(final GL2ES2 gl, final Font font, final CharSequence str, final float pixelSize, final int special, final GLRegion glyphString) { + protected final void addCachedRegion(final GL2ES2 gl, final Font font, final CharSequence str, final int special, final GLRegion glyphString) { if ( 0 != getCacheLimit() ) { - final String key = getKey(font, str, pixelSize, special); + final String key = getKey(font, str, special); final GLRegion oldRegion = stringCacheMap.put(key, glyphString); if ( null == oldRegion ) { // new entry .. @@ -313,8 +330,8 @@ public class TextRegionUtil { } } - protected final void removeCachedRegion(final GL2ES2 gl, final Font font, final CharSequence str, final int pixelSize, final int special) { - final String key = getKey(font, str, pixelSize, special); + protected final void removeCachedRegion(final GL2ES2 gl, final Font font, final CharSequence str, final int special) { + final String key = getKey(font, str, special); final GLRegion region = stringCacheMap.remove(key); if(null != region) { region.destroy(gl); @@ -332,10 +349,10 @@ public class TextRegionUtil { } } - protected final String getKey(final Font font, final CharSequence str, final float pixelSize, final int special) { + protected final String getKey(final Font font, final CharSequence str, final int special) { final StringBuilder sb = new StringBuilder(); return font.getName(sb, Font.NAME_UNIQUNAME) - .append(".").append(str.hashCode()).append(".").append(Float.floatToIntBits(pixelSize)).append(special).toString(); + .append(".").append(str.hashCode()).append(".").append(special).toString(); } /** Default cache limit, see {@link #setCacheLimit(int)} */ diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index 597a7e76f..9f25b5481 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -37,7 +37,7 @@ import com.jogamp.opengl.math.geom.AABBox; * TrueType Font Specification: * <ul> * <li>http://www.freetype.org/freetype2/documentation.html</li> - * <li>http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html</li> + * <li>https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html</li> * <li>http://www.microsoft.com/typography/SpecificationsOverview.mspx</li> * <li>http://www.microsoft.com/typography/otspec/</li> * </ul> @@ -76,20 +76,54 @@ public interface Font { * Depending on the font's direction, horizontal or vertical, * the following tables shall be used: * - * Vertical http://developer.apple.com/fonts/TTRefMan/RM06/Chap6vhea.html - * Horizontal http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html + * Vertical https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6vhea.html + * Horizontal https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html */ public interface Metrics { - float getAscent(final float pixelSize); - float getDescent(final float pixelSize); - float getLineGap(final float pixelSize); - float getMaxExtend(final float pixelSize); - float getScale(final float pixelSize); + /** + * @return ascent in font-units to be divided by {@link #getUnitsPerEM()} + */ + int getAscentFU(); + + /** + * @return descent in font-units to be divided by {@link #getUnitsPerEM()} + */ + int getDescentFU(); + + /** + * @return line-gap in font-units to be divided by {@link #getUnitsPerEM()} + */ + int getLineGapFU(); + + /** + * @return max-extend in font-units to be divided by {@link #getUnitsPerEM()} + */ + int getMaxExtendFU(); + + /** Returns the font's units per EM from the 'head' table. One em square covers one glyph. */ + int getUnitsPerEM(); + + /** + * Return fractional font em-size [0..1], i.e. funits divided by {@link #getUnitsPerEM()}, i.e. + * <pre> + * return funits / head.unitsPerEM; + * </pre> + * @param funits smallest font unit, where {@link #getUnitsPerEM()} square covers whole glyph + * @return fractional font em-size [0..1] + */ + float getScale(final int funits); + + /** + * @param dest AABBox instance set to this metrics boundary in font-units + * @return the given and set AABBox 'dest' in font units + */ + AABBox getBBox(final AABBox dest); + /** * @param dest AABBox instance set to this metrics boundary w/ given pixelSize - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link Font#getPixelSize(float, float)} + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} * @param tmpV3 caller provided temporary 3-component vector - * @return the given and set AABBox 'dest' + * @return the given and set AABBox 'dest' in pixel size */ AABBox getBBox(final AABBox dest, final float pixelSize, final float[] tmpV3); } @@ -108,118 +142,192 @@ public interface Font { public static final int ID_CR = 2; public static final int ID_SPACE = 3; - public Font getFont(); - public char getSymbol(); - public short getID(); - public AABBox getBBox(); + Font getFont(); + char getSymbol(); + int getID(); + /** - * - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link Font#getPixelSize(float, float)} - * @return + * Return fractional font em-size [0..1], i.e. funits divided by {@link #getUnitsPerEM()}, i.e. + * <pre> + * return funits / head.unitsPerEM; + * </pre> + * @param funits smallest font unit, where {@link #getUnitsPerEM()} square covers whole glyph + * @return fractional font em-size [0..1] */ - public float getScale(final float pixelSize); + float getScale(final int funits); + /** * @param dest AABBox instance set to this metrics boundary w/ given pixelSize - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link Font#getPixelSize(float, float)} + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} * @param tmpV3 caller provided temporary 3-component vector - * @return the given and set AABBox 'dest' + * @return the given and set AABBox 'dest' in pixel size + */ + AABBox getBBox(final AABBox dest, final float pixelSize, float[] tmpV3); + + /** + * Return the AABBox in font-units to be divided by unitsPerEM + * @param dest AABBox instance set to this metrics boundary in font-units + * @return the given and set AABBox 'dest' in font-units + */ + AABBox getBBoxFU(final AABBox dest); + + /** + * Return the AABBox in font-units to be divided by unitsPerEM */ - public AABBox getBBox(final AABBox dest, final float pixelSize, float[] tmpV3); + AABBox getBBoxFU(); + + /** Return advance in font units to be divided by unitsPerEM */ + int getAdvanceFU(); + + /** Return advance in font em-size [0..1] */ + float getAdvance(); + /** - * - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link Font#getPixelSize(float, float)} - * @param useFrationalMetrics - * @return + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} + * @return pixel size of advance */ - public float getAdvance(final float pixelSize, boolean useFrationalMetrics); - public OutlineShape getShape(); - public int hashCode(); + float getAdvance(final float pixelSize); + + OutlineShape getShape(); + + @Override + int hashCode(); } - public String getName(final int nameIndex); - public StringBuilder getName(final StringBuilder string, final int nameIndex); + String getName(final int nameIndex); + StringBuilder getName(final StringBuilder string, final int nameIndex); /** Shall return the family and subfamily name, separated a dash. * <p>{@link #getName(StringBuilder, int)} w/ {@link #NAME_FAMILY} and {@link #NAME_SUBFAMILY}</p> * <p>Example: "{@code Ubuntu-Regular}"</p> */ - public StringBuilder getFullFamilyName(final StringBuilder buffer); + StringBuilder getFullFamilyName(final StringBuilder buffer); + + StringBuilder getAllNames(final StringBuilder string, final String separator); - public StringBuilder getAllNames(final StringBuilder string, final String separator); + /** + * + * @param glyphID + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} + * @return pixel size of advance width + */ + float getAdvanceWidth(final int glyphID, final float pixelSize); /** - * <pre> - Font Scale Formula: - inch: 25.4 mm - pointSize: [point] = [1/72 inch] - - [1] Scale := pointSize * resolution / ( 72 points per inch * units_per_em ) - [2] PixelSize := pointSize * resolution / ( 72 points per inch ) - [3] Scale := PixelSize / units_per_em - * </pre> - * @param fontSize in point-per-inch - * @param resolution display resolution in dots-per-inch - * @return pixel-per-inch, pixelSize scale factor for font operations. + * Return advance-width of given glyphID in font em-size [0..1] + * @param glyphID */ - public float getPixelSize(final float fontSize /* points per inch */, final float resolution); + float getAdvanceWidth(final int glyphID); /** - * + * Return advance-width of given glyphID in font-units to be divided by unitsPerEM * @param glyphID - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} - * @return */ - public float getAdvanceWidth(final int glyphID, final float pixelSize); - public Metrics getMetrics(); - public Glyph getGlyph(final char symbol); - public int getNumGlyphs(); + int getAdvanceWidthFU(final int glyphID); /** + * Returns the optional kerning inter-glyph distance within words in fractional font em-size [0..1]. * - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} - * @return + * @param left_glyphid left glyph code id + * @param right_glyphid right glyph code id + * @return fractional font em-size distance [0..1] */ - public float getLineHeight(final float pixelSize); + float getKerning(final int left_glyphid, final int right_glyphid); + + /** + * Returns the optional kerning inter-glyph distance within words in fractional font-units to be divided by unitsPerEM + * + * @param left_glyphid left glyph code id + * @param right_glyphid right glyph code id + * @return font-units to be divided by unitsPerEM + */ + int getKerningFU(final int left_glyphid, final int right_glyphid); + + Metrics getMetrics(); + int getGlyphID(final char symbol); + Glyph getGlyph(final char symbol); + int getNumGlyphs(); + + /** + * + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} + * @return pixel size of line height + */ + float getLineHeight(final float pixelSize); + + /** + * Return line height in font em-size [0..1] + */ + float getLineHeight(); + + /** + * Return line height in font-units to be divided by unitsPerEM + */ + int getLineHeightFU(); + /** * * @param string - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} - * @return + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} + * @return pixel size of metric width */ - public float getMetricWidth(final CharSequence string, final float pixelSize); + float getMetricWidth(final CharSequence string, final float pixelSize); + + /** Return metric-width in font em-size */ + float getMetricWidth(final CharSequence string); + + /** Return metric-width in font-units */ + int getMetricWidthFU(final CharSequence string); + /** * * @param string - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} - * @param tmp - * @return + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} + * @return pixel size of metric height */ - public float getMetricHeight(final CharSequence string, final float pixelSize, final AABBox tmp); + float getMetricHeight(final CharSequence string, final float pixelSize); + + /** Return metric-height in font em-size */ + float getMetricHeight(final CharSequence string); + + /** Return metric-height in font-units */ + int getMetricHeightFU(final CharSequence string); + /** * Return the <i>layout</i> bounding box as computed by each glyph's metrics. - * The result is not pixel correct, bit reflects layout specific metrics. + * The result is not pixel correct, but reflects layout specific metrics. * <p> * See {@link #getPointsBounds(AffineTransform, CharSequence, float, AffineTransform, AffineTransform)} for pixel correct results. * </p> * @param string string text - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} */ - public AABBox getMetricBounds(final CharSequence string, final float pixelSize); + AABBox getMetricBounds(final CharSequence string, final float pixelSize); + + /** Return layout metric-bounds in font em-size, see {@link #getMetricBounds(CharSequence, float)} */ + AABBox getMetricBounds(final CharSequence string); + + /** Return layout metric-bounds in font-units, see {@link #getMetricBounds(CharSequence, float)} */ + AABBox getMetricBoundsFU(final CharSequence string); /** * Return the bounding box by taking each glyph's point-based bounding box into account. * @param transform optional given transform * @param string string text - * @param pixelSize Use <code>pointSize * resolution</code> for resolution correct pixel-size, see {@link #getPixelSize(float, float)} - * @param temp1 temporary AffineTransform storage, mandatory - * @param temp2 temporary AffineTransform storage, mandatory + * @param pixelSize pixel-size of font, for resolution correct pixel-size use {@link FontScale#toPixels(float, float)} */ - public AABBox getPointsBounds(final AffineTransform transform, final CharSequence string, final float pixelSize, - final AffineTransform temp1, final AffineTransform temp2); + AABBox getPointsBounds(final AffineTransform transform, final CharSequence string, final float pixelSize); + + AABBox getPointsBounds(final AffineTransform transform, final CharSequence string); - public boolean isPrintableChar(final char c); + AABBox getPointsBoundsFU(final AffineTransform transform, final CharSequence string); + + boolean isPrintableChar(final char c); /** Shall return {@link #getFullFamilyName()} */ @Override public String toString(); + + /** Return all font details as string. */ + String fullString(); } diff --git a/src/jogl/classes/com/jogamp/graph/font/FontScale.java b/src/jogl/classes/com/jogamp/graph/font/FontScale.java new file mode 100644 index 000000000..a0f2ef4e0 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/font/FontScale.java @@ -0,0 +1,70 @@ +package com.jogamp.graph.font; + +/** + * Simple static font scale methods for unit conversion. + */ +public class FontScale { + /** + * Converts typical font size in points (per-inch) and screen resolution in dpi to font size in pixels (per-inch), + * which can be used for pixel-size font scaling operations. + * <p> + * Note that 1em == size of the selected font.<br/> + * In case the pixel per em size is required (advance etc), + * the resulting pixel-size (per-inch) of this method shall be used if rendering directly into the screen resolution! + * </p> + * <pre> + Font Scale Formula: + 1 inch = 25.4 mm + + 1 inch = 72 points + pointSize: [point] = [1/72 inch] + + [1] Scale := pointSize * resolution / ( 72 points per inch * units_per_em ) + [2] PixelSize := pointSize * resolution / ( 72 points per inch ) + [3] Scale := PixelSize / units_per_em + * </pre> + * @param font_sz_pt in points (per-inch) + * @param res_dpi display resolution in dots-per-inch + * @return pixel-per-inch, pixelSize scale factor for font operations. + * @see #toPixels2(float, float) + */ + public static float toPixels(final float font_sz_pt /* points per inch */, final float res_dpi /* dots per inch */) { + return ( font_sz_pt / 72f /* points per inch */ ) * res_dpi; + } + + /** + * Converts typical font size in points-per-inch and screen resolution in points-per-mm to font size in pixels (per-inch), + * which can be used for pixel-size font scaling operations. + * + * @param font_sz_pt in points (per-inch) + * @param res_ppmm display resolution in dots-per-mm + * @return pixel-per-inch, pixelSize scale factor for font operations. + * @see #toPixels(float, float) + */ + public static float toPixels2(final float font_sz_pt /* points per inch */, final float res_ppmm /* pixels per mm */) { + return ( font_sz_pt / 72f /* points per inch */ ) * ( res_ppmm * 25.4f /* mm per inch */ ) ; + } + + /** + * Converts [1/mm] to [1/inch] in place + * @param ppmm float[2] [1/mm] value + * @return return [1/inch] value + */ + public static float[/*2*/] perMMToPerInch(final float[/*2*/] ppmm) { + ppmm[0] *= 25.4f; + ppmm[1] *= 25.4f; + return ppmm; + } + + /** + * Converts [1/mm] to [1/inch] into res storage + * @param ppmm float[2] [1/mm] value + * @param res the float[2] result storage + * @return return [1/inch] value, i.e. the given res storage + */ + public static float[/*2*/] ppmmToPPI(final float[/*2*/] ppmm, final float[/*2*/] res) { + res[0] = ppmm[0] * 25.4f; + res[1] = ppmm[1] * 25.4f; + return res; + } +} |