use of sun.font.LayoutPathImpl in project jdk8u_jdk by JetBrains.
the class TextLayout method getVisualHighlightShape.
/**
* Returns a path enclosing the visual selection in the specified range,
* extended to <code>bounds</code>.
* <p>
* If the selection includes the leftmost (topmost) position, the selection
* is extended to the left (top) of <code>bounds</code>. If the
* selection includes the rightmost (bottommost) position, the selection
* is extended to the right (bottom) of the bounds. The height
* (width on vertical lines) of the selection is always extended to
* <code>bounds</code>.
* <p>
* Although the selection is always contiguous, the logically selected
* text can be discontiguous on lines with mixed-direction text. The
* logical ranges of text selected can be retrieved using
* <code>getLogicalRangesForVisualSelection</code>. For example,
* consider the text 'ABCdef' where capital letters indicate
* right-to-left text, rendered on a right-to-left line, with a visual
* selection from 0L (the leading edge of 'A') to 3T (the trailing edge
* of 'd'). The text appears as follows, with bold underlined areas
* representing the selection:
* <br><pre>
* d<u><b>efCBA </b></u>
* </pre>
* The logical selection ranges are 0-3, 4-6 (ABC, ef) because the
* visually contiguous text is logically discontiguous. Also note that
* since the rightmost position on the layout (to the right of 'A') is
* selected, the selection is extended to the right of the bounds.
* @param firstEndpoint one end of the visual selection
* @param secondEndpoint the other end of the visual selection
* @param bounds the bounding rectangle to which to extend the selection.
* This is in baseline-relative coordinates.
* @return a <code>Shape</code> enclosing the selection. This is in
* standard coordinates.
* @see #getLogicalRangesForVisualSelection(TextHitInfo, TextHitInfo)
* @see #getLogicalHighlightShape(int, int, Rectangle2D)
*/
public Shape getVisualHighlightShape(TextHitInfo firstEndpoint, TextHitInfo secondEndpoint, Rectangle2D bounds) {
ensureCache();
checkTextHit(firstEndpoint);
checkTextHit(secondEndpoint);
if (bounds == null) {
throw new IllegalArgumentException("Null Rectangle2D passed to TextLayout.getVisualHighlightShape()");
}
GeneralPath result = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
int firstCaret = hitToCaret(firstEndpoint);
int secondCaret = hitToCaret(secondEndpoint);
result.append(caretBoundingShape(firstCaret, secondCaret, bounds), false);
if (firstCaret == 0 || secondCaret == 0) {
GeneralPath ls = leftShape(bounds);
if (!ls.getBounds().isEmpty())
result.append(ls, false);
}
if (firstCaret == characterCount || secondCaret == characterCount) {
GeneralPath rs = rightShape(bounds);
if (!rs.getBounds().isEmpty()) {
result.append(rs, false);
}
}
LayoutPathImpl lp = textLine.getLayoutPath();
if (lp != null) {
// dlf cast safe?
result = (GeneralPath) lp.mapShape(result);
}
return result;
}
use of sun.font.LayoutPathImpl in project jdk8u_jdk by JetBrains.
the class TextLayout method getCaretShapes.
/**
* Returns two paths corresponding to the strong and weak caret.
* @param offset an offset in this <code>TextLayout</code>
* @param bounds the bounds to which to extend the carets. The
* bounds is in baseline-relative coordinates.
* @param policy the specified <code>CaretPolicy</code>
* @return an array of two paths. Element zero is the strong
* caret. If there are two carets, element one is the weak caret,
* otherwise it is <code>null</code>. The returned shapes
* are in standard coordinates.
*/
public Shape[] getCaretShapes(int offset, Rectangle2D bounds, CaretPolicy policy) {
ensureCache();
if (offset < 0 || offset > characterCount) {
throw new IllegalArgumentException("Offset out of bounds in TextLayout.getCaretShapes()");
}
if (bounds == null) {
throw new IllegalArgumentException("Null Rectangle2D passed to TextLayout.getCaretShapes()");
}
if (policy == null) {
throw new IllegalArgumentException("Null CaretPolicy passed to TextLayout.getCaretShapes()");
}
Shape[] result = new Shape[2];
TextHitInfo hit = TextHitInfo.afterOffset(offset);
int hitCaret = hitToCaret(hit);
LayoutPathImpl lp = textLine.getLayoutPath();
Shape hitShape = pathToShape(getCaretPath(hit, bounds), false, lp);
TextHitInfo otherHit = hit.getOtherHit();
int otherCaret = hitToCaret(otherHit);
if (hitCaret == otherCaret) {
result[0] = hitShape;
} else {
// more than one caret
Shape otherShape = pathToShape(getCaretPath(otherHit, bounds), false, lp);
TextHitInfo strongHit = policy.getStrongCaret(hit, otherHit, this);
boolean hitIsStrong = strongHit.equals(hit);
if (hitIsStrong) {
// then other is weak
result[0] = hitShape;
result[1] = otherShape;
} else {
result[0] = otherShape;
result[1] = hitShape;
}
}
return result;
}
use of sun.font.LayoutPathImpl in project jdk8u_jdk by JetBrains.
the class TextLayout method getLogicalHighlightShape.
/**
* Returns a <code>Shape</code> enclosing the logical selection in the
* specified range, extended to the specified <code>bounds</code>.
* <p>
* If the selection range includes the first logical character, the
* selection is extended to the portion of <code>bounds</code> before
* the start of this <code>TextLayout</code>. If the range includes
* the last logical character, the selection is extended to the portion
* of <code>bounds</code> after the end of this <code>TextLayout</code>.
* The height (width on vertical lines) of the selection is always
* extended to <code>bounds</code>.
* <p>
* The selection can be discontiguous on lines with mixed-direction text.
* Only those characters in the logical range between start and limit
* appear selected. For example, consider the text 'ABCdef' where capital
* letters indicate right-to-left text, rendered on a right-to-left line,
* with a logical selection from 0 to 4 ('ABCd'). The text appears as
* follows, with bold standing in for the selection, and underlining for
* the extension:
* <br><pre>
* <u><b>d</b></u>ef<u><b>CBA </b></u>
* </pre>
* The selection is discontiguous because the selected characters are
* visually discontiguous. Also note that since the range includes the
* first logical character (A), the selection is extended to the portion
* of the <code>bounds</code> before the start of the layout, which in
* this case (a right-to-left line) is the right portion of the
* <code>bounds</code>.
* @param firstEndpoint an endpoint in the range of characters to select
* @param secondEndpoint the other endpoint of the range of characters
* to select. Can be less than <code>firstEndpoint</code>. The range
* includes the character at min(firstEndpoint, secondEndpoint), but
* excludes max(firstEndpoint, secondEndpoint).
* @param bounds the bounding rectangle to which to extend the selection.
* This is in baseline-relative coordinates.
* @return an area enclosing the selection. This is in standard
* coordinates.
* @see #getVisualHighlightShape(TextHitInfo, TextHitInfo, Rectangle2D)
*/
public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) {
if (bounds == null) {
throw new IllegalArgumentException("Null Rectangle2D passed to TextLayout.getLogicalHighlightShape()");
}
ensureCache();
if (firstEndpoint > secondEndpoint) {
int t = firstEndpoint;
firstEndpoint = secondEndpoint;
secondEndpoint = t;
}
if (firstEndpoint < 0 || secondEndpoint > characterCount) {
throw new IllegalArgumentException("Range is invalid in TextLayout.getLogicalHighlightShape()");
}
GeneralPath result = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
// would this ever not handle all cases?
int[] carets = new int[10];
int count = 0;
if (firstEndpoint < secondEndpoint) {
int logIndex = firstEndpoint;
do {
carets[count++] = hitToCaret(TextHitInfo.leading(logIndex));
boolean ltr = textLine.isCharLTR(logIndex);
do {
logIndex++;
} while (logIndex < secondEndpoint && textLine.isCharLTR(logIndex) == ltr);
int hitCh = logIndex;
carets[count++] = hitToCaret(TextHitInfo.trailing(hitCh - 1));
if (count == carets.length) {
int[] temp = new int[carets.length + 10];
System.arraycopy(carets, 0, temp, 0, count);
carets = temp;
}
} while (logIndex < secondEndpoint);
} else {
count = 2;
carets[0] = carets[1] = hitToCaret(TextHitInfo.leading(firstEndpoint));
}
for (int i = 0; i < count; i += 2) {
result.append(caretBoundingShape(carets[i], carets[i + 1], bounds), false);
}
if (firstEndpoint != secondEndpoint) {
if ((textLine.isDirectionLTR() && firstEndpoint == 0) || (!textLine.isDirectionLTR() && secondEndpoint == characterCount)) {
GeneralPath ls = leftShape(bounds);
if (!ls.getBounds().isEmpty()) {
result.append(ls, false);
}
}
if ((textLine.isDirectionLTR() && secondEndpoint == characterCount) || (!textLine.isDirectionLTR() && firstEndpoint == 0)) {
GeneralPath rs = rightShape(bounds);
if (!rs.getBounds().isEmpty()) {
result.append(rs, false);
}
}
}
LayoutPathImpl lp = textLine.getLayoutPath();
if (lp != null) {
// dlf cast safe?
result = (GeneralPath) lp.mapShape(result);
}
return result;
}
use of sun.font.LayoutPathImpl 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.LayoutPathImpl in project jdk8u_jdk by JetBrains.
the class TextLayout method getOutline.
/**
* Returns a <code>Shape</code> representing the outline of this
* <code>TextLayout</code>.
* @param tx an optional {@link AffineTransform} to apply to the
* outline of this <code>TextLayout</code>.
* @return a <code>Shape</code> that is the outline of this
* <code>TextLayout</code>. This is in standard coordinates.
*/
public Shape getOutline(AffineTransform tx) {
ensureCache();
Shape result = textLine.getOutline(tx);
LayoutPathImpl lp = textLine.getLayoutPath();
if (lp != null) {
result = lp.mapShape(result);
}
return result;
}
Aggregations