/** * Unions the supplied two rectangles, writing the result into {@code dst}. */ public static void union (IRectangle src1, IRectangle src2, Rectangle dst) { float x1 = Math.min(src1.minX(), src2.minX()); float y1 = Math.min(src1.minY(), src2.minY()); float x2 = Math.max(src1.maxX(), src2.maxX()); float y2 = Math.max(src1.maxY(), src2.maxY()); dst.setBounds(x1, y1, x2 - x1, y2 - y1); }
/** Tries to place the inner bounds within the outer bounds, such that the inner bounds does * not contain the position. */ protected static boolean avoidPoint (IRectangle outer, Rectangle inner, IRectangle fingerprint) { Rectangle checkBounds = new Rectangle(); Rectangle best = new Rectangle(inner); float bestDist = Float.MAX_VALUE, edge; // confine to the left edge = fingerprint.x(); checkBounds.setBounds(outer.x(), outer.y(), edge - outer.x(), outer.height()); bestDist = compareAndConfine(checkBounds, inner, best, bestDist); // right edge = fingerprint.maxX(); checkBounds.setBounds(edge, outer.y(), outer.width() - edge, outer.height()); bestDist = compareAndConfine(checkBounds, inner, best, bestDist); // top edge = fingerprint.y(); checkBounds.setBounds(outer.x(), outer.y(), outer.width(), edge - outer.y()); bestDist = compareAndConfine(checkBounds, inner, best, bestDist); // bottom edge = fingerprint.maxY(); checkBounds.setBounds(outer.x(), edge, outer.width(), outer.height() - edge); bestDist = compareAndConfine(checkBounds, inner, best, bestDist); inner.setBounds(best); return bestDist < Float.MAX_VALUE; }
/** * Creates a canvas image large enough to accommodate this text block and renders the lines into * it. The image will include padding around the edge to ensure that antialiasing has a bit of * extra space to do its work. */ public Canvas toCanvas(Graphics gfx, Align align, int fillColor) { float pad = 1/gfx.scale().factor; Canvas canvas = gfx.createCanvas(bounds.width()+2*pad, bounds.height()+2*pad); canvas.setFillColor(fillColor); fill(canvas, align, pad, pad); return canvas; } }
/** * Strokes {@code lines} into {@code canvas} at the specified coordinates, using the specified * alignment. */ public void stroke(Canvas canvas, Align align, float x, float y) { float sy = y + bounds.y(); for (TextLayout line : lines) { float sx = x + bounds.x() + align.getX(line.size.width(), textWidth()); canvas.strokeText(line, sx, sy); sy += line.ascent() + line.descent() + line.leading(); } }
/** Moves ths given inner rectangle such that it lies within the given outer rectangle. * The results are undefined if either the inner width or height is greater that the outer's * width or height, respectively. */ protected static Rectangle confine (IRectangle outer, Rectangle inner) { float dx = outer.x() - inner.x(), dy = outer.y() - inner.y(); if (dx <= 0) dx = Math.min(0, outer.maxX() - inner.maxX()); if (dy <= 0) dy = Math.min(0, outer.maxY() - inner.maxY()); inner.translate(dx, dy); return inner; }
/** 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.size.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; }
/** * Creates a canvas image large enough to accommodate this text block and renders the lines into * it. The image will include padding around the edge to ensure that antialiasing has a bit of * extra space to do its work. */ public Canvas toCanvas(Graphics gfx, Align align, int fillColor) { float pad = 1/gfx.scale().factor; Canvas canvas = gfx.createCanvas(bounds.width()+2*pad, bounds.height()+2*pad); canvas.setFillColor(fillColor); fill(canvas, align, pad, pad); return canvas; } }
/** * Fills {@code lines} into {@code canvas} at the specified coordinates, using the specified * alignment. */ public void fill(Canvas canvas, Align align, float x, float y) { float sy = y + bounds.y(); for (TextLayout line : lines) { float sx = x + bounds.x() + align.getX(line.width(), textWidth()); canvas.fillText(line, sx, sy); sy += line.ascent() + line.descent() + line.leading(); } }
/** 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.size.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; }
/** * Creates a canvas image large enough to accommodate this text block and renders the lines into * it. The image will include padding around the edge to ensure that antialiasing has a bit of * extra space to do its work. */ public CanvasImage toImage(Align align, int fillColor) { float pad = pad(); CanvasImage image = graphics().createImage(bounds.width()+2*pad, bounds.height()+2*pad); image.canvas().setFillColor(fillColor); fill(image.canvas(), align, pad, pad); return image; } }
/** * Fills {@code lines} into {@code canvas} at the specified coordinates, using the specified * alignment. */ public void fill(Canvas canvas, Align align, float x, float y) { float sy = y + bounds.y(); for (TextLayout line : lines) { float sx = x + bounds.x() + align.getX(line.size.width(), textWidth()); canvas.fillText(line, sx, sy); sy += line.ascent() + line.descent() + line.leading(); } }
/** * Intersects the supplied two rectangles, writing the result into {@code dst}. */ public static void intersect (IRectangle src1, IRectangle src2, Rectangle dst) { float x1 = Math.max(src1.minX(), src2.minX()); float y1 = Math.max(src1.minY(), src2.minY()); float x2 = Math.min(src1.maxX(), src2.maxX()); float y2 = Math.min(src1.maxY(), src2.maxY()); dst.setBounds(x1, y1, x2 - x1, y2 - y1); }
/** 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; }