Search in sources :

Example 1 with LayoutPathImpl

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;
}
Also used : GeneralPath(java.awt.geom.GeneralPath) LayoutPathImpl(sun.font.LayoutPathImpl)

Example 2 with LayoutPathImpl

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;
}
Also used : Shape(java.awt.Shape) LayoutPathImpl(sun.font.LayoutPathImpl)

Example 3 with LayoutPathImpl

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;
}
Also used : GeneralPath(java.awt.geom.GeneralPath) LayoutPathImpl(sun.font.LayoutPathImpl)

Example 4 with LayoutPathImpl

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;
}
Also used : CoreMetrics(sun.font.CoreMetrics) LayoutPathImpl(sun.font.LayoutPathImpl) Point2D(java.awt.geom.Point2D)

Example 5 with LayoutPathImpl

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;
}
Also used : Shape(java.awt.Shape) LayoutPathImpl(sun.font.LayoutPathImpl)

Aggregations

LayoutPathImpl (sun.font.LayoutPathImpl)6 GeneralPath (java.awt.geom.GeneralPath)3 Shape (java.awt.Shape)2 AffineTransform (java.awt.geom.AffineTransform)1 Point2D (java.awt.geom.Point2D)1 Rectangle2D (java.awt.geom.Rectangle2D)1 CoreMetrics (sun.font.CoreMetrics)1