shared/java/TextBlob.java (199 lines of code) (raw):
package org.jetbrains.skija;
import java.lang.ref.*;
import org.jetbrains.annotations.*;
import org.jetbrains.skija.impl.*;
public class TextBlob extends Managed {
static { Library.staticLoad(); }
@ApiStatus.Internal
public TextBlob(long ptr) {
super(ptr, _FinalizerHolder.PTR);
}
/**
* Returns conservative bounding box. Uses Paint associated with each glyph to
* determine glyph bounds, and unions all bounds. Returned bounds may be
* larger than the bounds of all glyphs in runs.
*
* @return conservative bounding box
*/
public Rect getBounds() {
try {
Stats.onNativeCall();
return _nBounds(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Returns a non-zero value unique among all text blobs.
*
* @return identifier for TextBlob
*/
public int getUniqueId() {
try {
Stats.onNativeCall();
return _nGetUniqueId(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Returns the number of intervals that intersect bounds.
* bounds describes a pair of lines parallel to the text advance.
* The return array size is a multiple of two, and is at most twice the number of glyphs in
* the the blob.</p>
*
* <p>Runs within the blob that contain SkRSXform are ignored when computing intercepts.</p>
*
* @param lowerBound lower line parallel to the advance
* @param upperBound upper line parallel to the advance
* @return intersections; may be null
*/
@Nullable
public float[] getIntercepts(float lowerBound, float upperBound) {
return getIntercepts(lowerBound, upperBound);
}
/**
* <p>Returns the number of intervals that intersect bounds.
* bounds describes a pair of lines parallel to the text advance.
* The return array size is a multiple of two, and is at most twice the number of glyphs in
* the the blob.</p>
*
* <p>Runs within the blob that contain SkRSXform are ignored when computing intercepts.</p>
*
* @param lowerBound lower line parallel to the advance
* @param upperBound upper line parallel to the advance
* @param paint specifies stroking, PathEffect that affects the result; may be null
* @return intersections; may be null
*/
@Nullable
public float[] getIntercepts(float lowerBound, float upperBound, @Nullable Paint paint) {
try {
Stats.onNativeCall();
return _nGetIntercepts(_ptr, lowerBound, upperBound, Native.getPtr(paint));
} finally {
Reference.reachabilityFence(this);
Reference.reachabilityFence(paint);
}
}
/**
* Returns a TextBlob built from a single run of text with x-positions and a single y value.
* Returns null if glyphs is empty.
*
* @param glyphs glyphs drawn
* @param xpos array of x-positions, must contain values for all of the glyphs.
* @param ypos shared y-position for each glyph, to be paired with each xpos.
* @param font Font used for this run
* @return new TextBlob or null
*/
public static TextBlob makeFromPosH(short[] glyphs, float[] xpos, float ypos, Font font) {
try {
assert glyphs.length == xpos.length : "glyphs.length " + glyphs.length + " != xpos.length " + xpos.length;
Stats.onNativeCall();
long ptr = _nMakeFromPosH(glyphs, xpos, ypos, Native.getPtr(font));
return ptr == 0 ? null : new TextBlob(ptr);
} finally {
Reference.reachabilityFence(font);
}
}
/**
* Returns a TextBlob built from a single run of text with positions.
* Returns null if glyphs is empty.
*
* @param glyphs glyphs drawn
* @param pos array of positions, must contain values for all of the glyphs.
* @param font Font used for this run
* @return new TextBlob or null
*/
public static TextBlob makeFromPos(short[] glyphs, Point[] pos, Font font) {
try {
assert glyphs.length == pos.length : "glyphs.length " + glyphs.length + " != pos.length " + pos.length;
float[] floatPos = new float[pos.length * 2];
for (int i = 0; i < pos.length; ++i) {
floatPos[i * 2] = pos[i]._x;
floatPos[i * 2 + 1] = pos[i]._y;
}
Stats.onNativeCall();
long ptr = _nMakeFromPos(glyphs, floatPos, Native.getPtr(font));
return ptr == 0 ? null : new TextBlob(ptr);
} finally {
Reference.reachabilityFence(font);
}
}
public static TextBlob makeFromRSXform(short[] glyphs, RSXform[] xform, Font font) {
try {
assert glyphs.length == xform.length : "glyphs.length " + glyphs.length + " != xform.length " + xform.length;
float[] floatXform = new float[xform.length * 4];
for (int i = 0; i < xform.length; ++i) {
floatXform[i * 4] = xform[i]._scos;
floatXform[i * 4 + 1] = xform[i]._ssin;
floatXform[i * 4 + 2] = xform[i]._tx;
floatXform[i * 4 + 3] = xform[i]._ty;
}
Stats.onNativeCall();
long ptr = _nMakeFromRSXform(glyphs, floatXform, Native.getPtr(font));
return ptr == 0 ? null : new TextBlob(ptr);
} finally {
Reference.reachabilityFence(font);
}
}
public Data serializeToData() {
try {
Stats.onNativeCall();
return new Data(_nSerializeToData(_ptr));
} finally {
Reference.reachabilityFence(this);
}
}
@Nullable
public static TextBlob makeFromData(Data data) {
try {
Stats.onNativeCall();
long ptr = _nMakeFromData(Native.getPtr(data));
return ptr == 0 ? null : new TextBlob(ptr);
} finally {
Reference.reachabilityFence(data);
}
}
/**
* @return glyph indices for the whole blob
*/
@NotNull
public short[] getGlyphs() {
try {
Stats.onNativeCall();
return _nGetGlyphs(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* <p>Return result depends on how blob was constructed.</p>
*
* <ul><li>makeFromPosH returns 1 float per glyph (x pos)
* <li>makeFromPos returns 2 floats per glyph (x, y pos)
* <li>makeFromRSXform returns 4 floats per glyph
* </ul>
*
* <p>Blobs constructed by TextBlobBuilderRunHandler/Shaper default handler have 2 floats per glyph.</p>
*
* @return glyph positions for the blob if it was made with makeFromPos, null otherwise
*/
@NotNull
public float[] getPositions() {
try {
Stats.onNativeCall();
return _nGetPositions(_ptr);
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Only works on TextBlobs that come from TextBlobBuilderRunHandler/Shaper default handler.
*
* @return utf-16 offsets of clusters that start the glyph
* @throws IllegalArgumentException if TextBlob doesn’t have this information
*/
@NotNull
public int[] getClusters() {
try {
Stats.onNativeCall();
int[] res = _nGetClusters(_ptr);
if (res == null)
throw new IllegalArgumentException();
return res;
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Only works on TextBlobs that come from TextBlobBuilderRunHandler/Shaper default handler.
*
* @return tight bounds around all the glyphs in the TextBlob
* @throws IllegalArgumentException if TextBlob doesn’t have this information
*/
@NotNull
public Rect getTightBounds() {
try {
Stats.onNativeCall();
Rect res = _nGetTightBounds(_ptr);
if (res == null)
throw new IllegalArgumentException();
return res;
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Only works on TextBlobs that come from TextBlobBuilderRunHandler/Shaper default handler.
*
* @return tight bounds around all the glyphs in the TextBlob
* @throws IllegalArgumentException if TextBlob doesn’t have this information
*/
@NotNull
public Rect getBlockBounds() {
try {
Stats.onNativeCall();
Rect res = _nGetBlockBounds(_ptr);
if (res == null)
throw new IllegalArgumentException();
return res;
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Only works on TextBlobs that come from TextBlobBuilderRunHandler/Shaper default handler.
*
* @return first baseline in TextBlob
* @throws IllegalArgumentException if TextBlob doesn’t have this information
*/
@NotNull
public Float getFirstBaseline() {
try {
Stats.onNativeCall();
Float res = _nGetFirstBaseline(_ptr);
if (res == null)
throw new IllegalArgumentException();
return res;
} finally {
Reference.reachabilityFence(this);
}
}
/**
* Only works on TextBlobs that come from TextBlobBuilderRunHandler/Shaper default handler.
*
* @return last baseline in TextBlob
* @throws IllegalArgumentException if TextBlob doesn’t have this information
*/
@NotNull
public Float getLastBaseline() {
try {
Stats.onNativeCall();
Float res = _nGetLastBaseline(_ptr);
if (res == null)
throw new IllegalArgumentException();
return res;
} finally {
Reference.reachabilityFence(this);
}
}
@ApiStatus.Internal
public static class _FinalizerHolder {
public static final long PTR = _nGetFinalizer();
}
@ApiStatus.Internal public static native long _nGetFinalizer();
@ApiStatus.Internal public static native Rect _nBounds(long ptr);
@ApiStatus.Internal public static native int _nGetUniqueId(long ptr);
@ApiStatus.Internal public static native float[] _nGetIntercepts(long ptr, float lower, float upper, long paintPtr);
@ApiStatus.Internal public static native long _nMakeFromPosH(short[] glyphs, float[] xpos, float ypos, long fontPtr);
@ApiStatus.Internal public static native long _nMakeFromPos(short[] glyphs, float[] pos, long fontPtr);
@ApiStatus.Internal public static native long _nMakeFromRSXform(short[] glyphs, float[] xform, long fontPtr);
@ApiStatus.Internal public static native long _nSerializeToData(long ptr /*, SkSerialProcs */);
@ApiStatus.Internal public static native long _nMakeFromData(long dataPtr /*, SkDeserialProcs */);
@ApiStatus.Internal public static native short[] _nGetGlyphs(long ptr);
@ApiStatus.Internal public static native float[] _nGetPositions(long ptr);
@ApiStatus.Internal public static native int[] _nGetClusters(long ptr);
@ApiStatus.Internal public static native Rect _nGetTightBounds(long ptr);
@ApiStatus.Internal public static native Rect _nGetBlockBounds(long ptr);
@ApiStatus.Internal public static native Float _nGetFirstBaseline(long ptr);
@ApiStatus.Internal public static native Float _nGetLastBaseline(long ptr);
}