/** Computes the bounds of a block of text. The {@code x} component of the bounds may be * positive, indicating that the text should be rendered at that offset. This is to account for * the fact that some text renders to the left of its reported origin due to font * extravagance. */ public static Rectangle getBounds(TextLayout[] lines, Rectangle into) { // some font glyphs start rendering at a negative inset, blowing outside their bounding box // (naughty!); in such cases, we use xAdjust to shift everything to the right to ensure that we // don't paint outside our reported bounding box (so that someone can create a single canvas of // bounding box size and render this text layout into it at (0,0) and nothing will get cut off) float xAdjust = 0, twidth = 0, theight = 0; for (TextLayout layout : lines) { IRectangle bounds = layout.bounds(); xAdjust = Math.max(xAdjust, -Math.min(0, bounds.x())); // we use layout.width() here not bounds width because layout width includes extra space // needed for lines that start rendering at a positive x offset whereas bounds.width() is // only the precise width of the rendered text twidth = Math.max(twidth, layout.width()); if (layout != lines[0]) theight += layout.leading(); // leading only applied to lines after 0 theight += layout.ascent() + layout.descent(); } into.setBounds(xAdjust, 0, xAdjust+twidth, theight); return into; }
protected void render (Canvas canvas, String strokeFill, TextBlock block, TextBlock.Align align, int color, float x, float y, boolean showBounds) { float sy = y + block.bounds.y(); for (TextLayout layout : block.lines) { float sx = x + block.bounds.x() + align.getX( layout.width(), block.bounds.width()-block.bounds.x()); if (showBounds) { IRectangle lbounds = layout.bounds(); canvas.setStrokeColor(0xFFFFCCCC).setStrokeWidth(1); canvas.strokeRect(sx+lbounds.x(), sy+lbounds.y(), lbounds.width(), lbounds.height()); } if (strokeFill.equals("Fill")) { canvas.setFillColor(color).fillText(layout, sx, sy); } else { canvas.setStrokeColor(color).strokeText(layout, sx, sy); } sy += layout.ascent() + layout.descent() + layout.leading(); } }