use of sun.font.CoreMetrics in project jdk8u_jdk by JetBrains.
the class TextLayout method fastInit.
/*
* the fast init generates a single glyph set. This requires:
* all one style
* all renderable by one font (ie no embedded graphics)
* all on one baseline
*/
private void fastInit(char[] chars, Font font, Map<? extends Attribute, ?> attrs, FontRenderContext frc) {
// Object vf = attrs.get(TextAttribute.ORIENTATION);
// isVerticalLine = TextAttribute.ORIENTATION_VERTICAL.equals(vf);
isVerticalLine = false;
LineMetrics lm = font.getLineMetrics(chars, 0, chars.length, frc);
CoreMetrics cm = CoreMetrics.get(lm);
byte glyphBaseline = (byte) cm.baselineIndex;
if (attrs == null) {
baseline = glyphBaseline;
baselineOffsets = cm.baselineOffsets;
justifyRatio = 1.0f;
} else {
paragraphInit(glyphBaseline, cm, attrs, chars);
}
characterCount = chars.length;
textLine = TextLine.fastCreateTextLine(frc, chars, font, cm, attrs);
}
use of sun.font.CoreMetrics in project jdk8u_jdk by JetBrains.
the class TextLayout method hitTestChar.
/**
* Returns a <code>TextHitInfo</code> corresponding to the
* specified point.
* Coordinates outside the bounds of the <code>TextLayout</code>
* map to hits on the leading edge of the first logical character,
* or the trailing edge of the last logical character, as appropriate,
* regardless of the position of that character in the line. Only the
* direction along the baseline is used to make this evaluation.
* @param x the x offset from the origin of this
* <code>TextLayout</code>. This is in standard coordinates.
* @param y the y offset from the origin of this
* <code>TextLayout</code>. This is in standard coordinates.
* @param bounds the bounds of the <code>TextLayout</code>. This
* is in baseline-relative coordinates.
* @return a hit describing the character and edge (leading or trailing)
* under the specified point.
*/
public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) {
// check boundary conditions
LayoutPathImpl lp = textLine.getLayoutPath();
boolean prev = false;
if (lp != null) {
Point2D.Float pt = new Point2D.Float(x, y);
prev = lp.pointToPath(pt, pt);
x = pt.x;
y = pt.y;
}
if (isVertical()) {
if (y < bounds.getMinY()) {
return TextHitInfo.leading(0);
} else if (y >= bounds.getMaxY()) {
return TextHitInfo.trailing(characterCount - 1);
}
} else {
if (x < bounds.getMinX()) {
return isLeftToRight() ? TextHitInfo.leading(0) : TextHitInfo.trailing(characterCount - 1);
} else if (x >= bounds.getMaxX()) {
return isLeftToRight() ? TextHitInfo.trailing(characterCount - 1) : TextHitInfo.leading(0);
}
}
// revised hit test
// the original seems too complex and fails miserably with italic offsets
// the natural tendency is to move towards the character you want to hit
// so we'll just measure distance to the center of each character's visual
// bounds, pick the closest one, then see which side of the character's
// center line (italic) the point is on.
// this tends to make it easier to hit narrow characters, which can be a
// bit odd if you're visually over an adjacent wide character. this makes
// a difference with bidi, so perhaps i need to revisit this yet again.
double distance = Double.MAX_VALUE;
int index = 0;
int trail = -1;
CoreMetrics lcm = null;
float icx = 0, icy = 0, ia = 0, cy = 0, dya = 0, ydsq = 0;
for (int i = 0; i < characterCount; ++i) {
if (!textLine.caretAtOffsetIsValid(i)) {
continue;
}
if (trail == -1) {
trail = i;
}
CoreMetrics cm = textLine.getCoreMetricsAt(i);
if (cm != lcm) {
lcm = cm;
// just work around baseline mess for now
if (cm.baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
cy = -(textLine.getMetrics().ascent - cm.ascent) + cm.ssOffset;
} else if (cm.baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) {
cy = textLine.getMetrics().descent - cm.descent + cm.ssOffset;
} else {
cy = cm.effectiveBaselineOffset(baselineOffsets) + cm.ssOffset;
}
float dy = (cm.descent - cm.ascent) / 2 - cy;
dya = dy * cm.italicAngle;
cy += dy;
ydsq = (cy - y) * (cy - y);
}
float cx = textLine.getCharXPosition(i);
float ca = textLine.getCharAdvance(i);
float dx = ca / 2;
cx += dx - dya;
// proximity in x (along baseline) is two times as important as proximity in y
double nd = Math.sqrt(4 * (cx - x) * (cx - x) + ydsq);
if (nd < distance) {
distance = nd;
index = i;
trail = -1;
icx = cx;
icy = cy;
ia = cm.italicAngle;
}
}
boolean left = x < icx - (y - icy) * ia;
boolean leading = textLine.isCharLTR(index) == left;
if (trail == -1) {
trail = characterCount;
}
TextHitInfo result = leading ? TextHitInfo.leading(index) : TextHitInfo.trailing(trail - 1);
return result;
}
use of sun.font.CoreMetrics in project jdk8u_jdk by JetBrains.
the class Font method defaultLineMetrics.
private FontLineMetrics defaultLineMetrics(FontRenderContext frc) {
FontLineMetrics flm = null;
if (flmref == null || (flm = flmref.get()) == null || !flm.frc.equals(frc)) {
/* The device transform in the frc is not used in obtaining line
* metrics, although it probably should be: REMIND find why not?
* The font transform is used but its applied in getFontMetrics, so
* just pass identity here
*/
float[] metrics = new float[8];
getFont2D().getFontMetrics(this, identityTx, frc.getAntiAliasingHint(), frc.getFractionalMetricsHint(), metrics);
float ascent = metrics[0];
float descent = metrics[1];
float leading = metrics[2];
float ssOffset = 0;
if (values != null && values.getSuperscript() != 0) {
ssOffset = (float) getTransform().getTranslateY();
ascent -= ssOffset;
descent += ssOffset;
}
float height = ascent + descent + leading;
// need real index, assumes roman for everything
int baselineIndex = 0;
// need real baselines eventually
float[] baselineOffsets = { 0, (descent / 2f - ascent) / 2f, -ascent };
float strikethroughOffset = metrics[4];
float strikethroughThickness = metrics[5];
float underlineOffset = metrics[6];
float underlineThickness = metrics[7];
float italicAngle = getItalicAngle(frc);
if (isTransformed()) {
// extract rotation
AffineTransform ctx = values.getCharTransform();
if (ctx != null) {
Point2D.Float pt = new Point2D.Float();
pt.setLocation(0, strikethroughOffset);
ctx.deltaTransform(pt, pt);
strikethroughOffset = pt.y;
pt.setLocation(0, strikethroughThickness);
ctx.deltaTransform(pt, pt);
strikethroughThickness = pt.y;
pt.setLocation(0, underlineOffset);
ctx.deltaTransform(pt, pt);
underlineOffset = pt.y;
pt.setLocation(0, underlineThickness);
ctx.deltaTransform(pt, pt);
underlineThickness = pt.y;
}
}
strikethroughOffset += ssOffset;
underlineOffset += ssOffset;
CoreMetrics cm = new CoreMetrics(ascent, descent, leading, height, baselineIndex, baselineOffsets, strikethroughOffset, strikethroughThickness, underlineOffset, underlineThickness, ssOffset, italicAngle);
flm = new FontLineMetrics(0, cm, frc);
flmref = new SoftReference<FontLineMetrics>(flm);
}
return (FontLineMetrics) flm.clone();
}
use of sun.font.CoreMetrics in project jdk8u_jdk by JetBrains.
the class TextLayout method getCaretInfoTestInternal.
// this version provides extra info in the float array
// the first two values are as above
// the next four values are the endpoints of the caret, as computed
// using the hit character's offset (baseline + ssoffset) and
// natural ascent and descent.
// these values are trimmed to the bounds where required to fit,
// but otherwise independent of it.
private float[] getCaretInfoTestInternal(TextHitInfo hit, Rectangle2D bounds) {
ensureCache();
checkTextHit(hit);
float[] info = new float[6];
// get old data first
getCaretInfo(hitToCaret(hit), bounds, info);
// then add our new data
double iangle, ixbase, p1x, p1y, p2x, p2y;
int charix = hit.getCharIndex();
boolean lead = hit.isLeadingEdge();
boolean ltr = textLine.isDirectionLTR();
boolean horiz = !isVertical();
if (charix == -1 || charix == characterCount) {
// !!! note: want non-shifted, baseline ascent and descent here!
// TextLine should return appropriate line metrics object for these values
TextLineMetrics m = textLine.getMetrics();
boolean low = ltr == (charix == -1);
iangle = 0;
if (horiz) {
p1x = p2x = low ? 0 : m.advance;
p1y = -m.ascent;
p2y = m.descent;
} else {
p1y = p2y = low ? 0 : m.advance;
p1x = m.descent;
p2x = m.ascent;
}
} else {
CoreMetrics thiscm = textLine.getCoreMetricsAt(charix);
iangle = thiscm.italicAngle;
ixbase = textLine.getCharLinePosition(charix, lead);
if (thiscm.baselineIndex < 0) {
// this is a graphic, no italics, use entire line height for caret
TextLineMetrics m = textLine.getMetrics();
if (horiz) {
p1x = p2x = ixbase;
if (thiscm.baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
p1y = -m.ascent;
p2y = p1y + thiscm.height;
} else {
p2y = m.descent;
p1y = p2y - thiscm.height;
}
} else {
p1y = p2y = ixbase;
p1x = m.descent;
p2x = m.ascent;
// !!! top/bottom adjustment not implemented for vertical
}
} else {
float bo = baselineOffsets[thiscm.baselineIndex];
if (horiz) {
ixbase += iangle * thiscm.ssOffset;
p1x = ixbase + iangle * thiscm.ascent;
p2x = ixbase - iangle * thiscm.descent;
p1y = bo - thiscm.ascent;
p2y = bo + thiscm.descent;
} else {
ixbase -= iangle * thiscm.ssOffset;
p1y = ixbase + iangle * thiscm.ascent;
p2y = ixbase - iangle * thiscm.descent;
p1x = bo + thiscm.ascent;
p2x = bo + thiscm.descent;
}
}
}
info[2] = (float) p1x;
info[3] = (float) p1y;
info[4] = (float) p2x;
info[5] = (float) p2y;
return info;
}
use of sun.font.CoreMetrics in project jdk8u_jdk by JetBrains.
the class TextLine method init.
private void init() {
// first, we need to check for graphic components on the TOP or BOTTOM baselines. So
// we perform the work that used to be in getMetrics here.
float ascent = 0;
float descent = 0;
float leading = 0;
float advance = 0;
// ascent + descent must not be less than this value
float maxGraphicHeight = 0;
float maxGraphicHeightWithLeading = 0;
// walk through EGA's
TextLineComponent tlc;
boolean fitTopAndBottomGraphics = false;
isSimple = true;
for (int i = 0; i < fComponents.length; i++) {
tlc = fComponents[i];
isSimple &= tlc.isSimple();
CoreMetrics cm = tlc.getCoreMetrics();
byte baseline = (byte) cm.baselineIndex;
if (baseline >= 0) {
float baselineOffset = fBaselineOffsets[baseline];
ascent = Math.max(ascent, -baselineOffset + cm.ascent);
float gd = baselineOffset + cm.descent;
descent = Math.max(descent, gd);
leading = Math.max(leading, gd + cm.leading);
} else {
fitTopAndBottomGraphics = true;
float graphicHeight = cm.ascent + cm.descent;
float graphicHeightWithLeading = graphicHeight + cm.leading;
maxGraphicHeight = Math.max(maxGraphicHeight, graphicHeight);
maxGraphicHeightWithLeading = Math.max(maxGraphicHeightWithLeading, graphicHeightWithLeading);
}
}
if (fitTopAndBottomGraphics) {
if (maxGraphicHeight > ascent + descent) {
descent = maxGraphicHeight - ascent;
}
if (maxGraphicHeightWithLeading > ascent + leading) {
leading = maxGraphicHeightWithLeading - ascent;
}
}
leading -= descent;
if (fitTopAndBottomGraphics) {
// we have top or bottom baselines, so expand the baselines array
// full offsets are needed by CoreMetrics.effectiveBaselineOffset
fBaselineOffsets = new float[] { fBaselineOffsets[0], fBaselineOffsets[1], fBaselineOffsets[2], descent, -ascent };
}
float x = 0;
float y = 0;
CoreMetrics pcm = null;
boolean needPath = false;
locs = new float[fComponents.length * 2 + 2];
for (int i = 0, n = 0; i < fComponents.length; ++i, n += 2) {
tlc = fComponents[getComponentLogicalIndex(i)];
CoreMetrics cm = tlc.getCoreMetrics();
if ((pcm != null) && // adjust because of italics
(pcm.italicAngle != 0 || cm.italicAngle != 0) && (pcm.italicAngle != cm.italicAngle || pcm.baselineIndex != cm.baselineIndex || pcm.ssOffset != cm.ssOffset)) {
// 1) compute the area of overlap - min effective ascent and min effective descent
// 2) compute the x positions along italic angle of ascent and descent for left and right
// 3) compute maximum left - right, adjust right position by this value
// this is a crude form of kerning between textcomponents
// note glyphvectors preposition glyphs based on offset,
// so tl doesn't need to adjust glyphvector position
// 1)
float pb = pcm.effectiveBaselineOffset(fBaselineOffsets);
float pa = pb - pcm.ascent;
float pd = pb + pcm.descent;
// pb += pcm.ssOffset;
float cb = cm.effectiveBaselineOffset(fBaselineOffsets);
float ca = cb - cm.ascent;
float cd = cb + cm.descent;
// cb += cm.ssOffset;
float a = Math.max(pa, ca);
float d = Math.min(pd, cd);
// 2)
float pax = pcm.italicAngle * (pb - a);
float pdx = pcm.italicAngle * (pb - d);
float cax = cm.italicAngle * (cb - a);
float cdx = cm.italicAngle * (cb - d);
// 3)
float dax = pax - cax;
float ddx = pdx - cdx;
float dx = Math.max(dax, ddx);
x += dx;
y = cb;
} else {
// no italic adjustment for x, but still need to compute y
// + cm.ssOffset;
y = cm.effectiveBaselineOffset(fBaselineOffsets);
}
locs[n] = x;
locs[n + 1] = y;
x += tlc.getAdvance();
pcm = cm;
needPath |= tlc.getBaselineTransform() != null;
}
// do we want italic padding at the right of the line?
if (pcm.italicAngle != 0) {
float pb = pcm.effectiveBaselineOffset(fBaselineOffsets);
float pa = pb - pcm.ascent;
float pd = pb + pcm.descent;
pb += pcm.ssOffset;
float d;
if (pcm.italicAngle > 0) {
d = pb + pcm.ascent;
} else {
d = pb - pcm.descent;
}
d *= pcm.italicAngle;
x += d;
}
locs[locs.length - 2] = x;
// locs[locs.length - 1] = 0; // final offset is always back on baseline
// ok, build fMetrics since we have the final advance
advance = x;
fMetrics = new TextLineMetrics(ascent, descent, leading, advance);
// build path if we need it
if (needPath) {
isSimple = false;
Point2D.Double pt = new Point2D.Double();
double tx = 0, ty = 0;
SegmentPathBuilder builder = new SegmentPathBuilder();
builder.moveTo(locs[0], 0);
for (int i = 0, n = 0; i < fComponents.length; ++i, n += 2) {
tlc = fComponents[getComponentLogicalIndex(i)];
AffineTransform at = tlc.getBaselineTransform();
if (at != null && ((at.getType() & AffineTransform.TYPE_TRANSLATION) != 0)) {
double dx = at.getTranslateX();
double dy = at.getTranslateY();
builder.moveTo(tx += dx, ty += dy);
}
pt.x = locs[n + 2] - locs[n];
pt.y = 0;
if (at != null) {
at.deltaTransform(pt, pt);
}
builder.lineTo(tx += pt.x, ty += pt.y);
}
lp = builder.complete();
if (lp == null) {
// empty path
tlc = fComponents[getComponentLogicalIndex(0)];
AffineTransform at = tlc.getBaselineTransform();
if (at != null) {
lp = new EmptyPath(at);
}
}
}
}
Aggregations