# HG changeset patch # Parent adcb59265f40ca1ad38814a4678415aaaf575ca8 RT-26277: add RegionInsets, which BackgroundFill, BorderStroke and BorderImage can use for their respective -fx-*-insets. RegionInsets allows for percentage values, but this means that the actual Insets values that NGRegion uses have to be calculated on the fly. diff -r adcb59265f40 modules/graphics/src/main/java/com/sun/javafx/css/converters/InsetsConverter.java --- a/modules/graphics/src/main/java/com/sun/javafx/css/converters/InsetsConverter.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/com/sun/javafx/css/converters/InsetsConverter.java Mon Nov 25 12:35:17 2013 -0500 @@ -26,6 +26,7 @@ package com.sun.javafx.css.converters; import com.sun.javafx.css.Size; +import com.sun.javafx.css.SizeUnits; import com.sun.javafx.css.StyleConverterImpl; import javafx.css.ParsedValue; import javafx.css.StyleConverter; @@ -58,11 +59,13 @@ @Override public Insets convert(ParsedValue value, Font font) { ParsedValue[] sides = value.getValue(); - double top = ((Size)sides[0].convert(font)).pixels(font); - double right = (sides.length > 1) ? ((Size)sides[1].convert(font)).pixels(font) : top; - double bottom = (sides.length > 2) ? ((Size)sides[2].convert(font)).pixels(font) : top; - double left = (sides.length > 3) ? ((Size)sides[3].convert(font)).pixels(font) : right; - return new Insets(top, right, bottom, left); + Size top = (Size)sides[0].convert(font); + Size right = (sides.length > 1) ? (Size)sides[1].convert(font) : top; + Size bottom = (sides.length > 2) ? (Size)sides[2].convert(font) : top; + Size left = (sides.length > 3) ? (Size)sides[3].convert(font) : right; + return new Insets(top.pixels(font), right.pixels(font), bottom.pixels(font), left.pixels(font), + top.getUnits() == SizeUnits.PERCENT, right.getUnits() == SizeUnits.PERCENT, + bottom.getUnits() == SizeUnits.PERCENT, left.getUnits() == SizeUnits.PERCENT); } @Override diff -r adcb59265f40 modules/graphics/src/main/java/com/sun/javafx/css/parser/CSSParser.java --- a/modules/graphics/src/main/java/com/sun/javafx/css/parser/CSSParser.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/com/sun/javafx/css/parser/CSSParser.java Mon Nov 25 12:35:17 2013 -0500 @@ -714,7 +714,7 @@ } else if ("-fx-background-image".equals(prop)) { return parseURILayers(root); } else if ("-fx-background-insets".equals(prop)) { - return parseInsetsLayers(root); + return parseInsetsLayers(root); } else if ("-fx-opaque-insets".equals(prop)) { return parseInsetsLayer(root); } else if ("-fx-background-position".equals(prop)) { @@ -745,6 +745,9 @@ return parseURILayers(root); } else if ("-fx-border-image-width".equals(prop)) { return parseBorderImageWidthLayers(root); + } else if ("-fx-margin".equals(prop)) { + ParsedValueImpl[] sides = parseSizeSeries(root); + return new ParsedValueImpl(sides, InsetsConverter.getInstance()); } else if ("-fx-padding".equals(prop)) { ParsedValueImpl[] sides = parseSizeSeries(root); return new ParsedValueImpl(sides, InsetsConverter.getInstance()); @@ -2388,7 +2391,6 @@ return new ParsedValueImpl[], Margins[]>(layers, Margins.SequenceConverter.getInstance()); } - // http://www.w3.org/TR/css3-background/#the-border-radius // {1,4} [ '/' {1,4}]? [',' {1,4} [ '/' {1,4}]?]? private ParsedValueImpl[][],CornerRadii>[], CornerRadii[]> parseCornerRadius(Term root) diff -r adcb59265f40 modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java --- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java Mon Nov 25 12:35:17 2013 -0500 @@ -170,6 +170,14 @@ private float width, height; /** + * Margins + */ + private float marginTop = Float.NaN, + marginRight = Float.NaN, + marginBottom = Float.NaN, + marginLeft = Float.NaN; + + /** * Determined when a background is set on the region, this flag indicates whether this * background can be cached. As of this time, the only backgrounds which can be cached * are those where there are only solid fills or linear gradients. @@ -270,7 +278,7 @@ // on the border objects is generally very fast (either for identity or // for !equals. It is a bit longer for when they really are equal, but faster // than a geometryChanged!) - if (!border.getOutsets().equals(old.getOutsets())) { + if (!border.getOutsets(width, height).equals(old.getOutsets(width, height))) { geometryChanged(); } else { visualsChanged(); @@ -328,7 +336,7 @@ cacheKey = null; // Only update the geom if the new background is geometrically different from the old - if (!background.getOutsets().equals(old.getOutsets())) { + if (!background.getOutsets(width, height).equals(old.getOutsets(width, height))) { geometryChanged(); } else { visualsChanged(); @@ -358,6 +366,13 @@ invalidateOpaqueRegion(); } + public void setMargins(float top, float right, float bottom, float left) { + marginTop = top; + marginRight = right; + marginBottom = bottom; + marginLeft = left; + } + /** * When cleaning the dirty tree, we also have to keep in mind * the NGShape used by the NGRegion @@ -516,7 +531,7 @@ // it if we absolutely have to. Specifically, if the background, shape, and size of the region // has not changed since the last time we rendered we could skip all this and render // directly out of a cache. - final Insets outsets = background.getOutsets(); + final Insets outsets = background.getOutsets(width, height); final Shape outsetShape = resizeShape((float) -outsets.getTop(), (float) -outsets.getRight(), (float) -outsets.getBottom(), (float) -outsets.getLeft()); final RectBounds outsetShapeBounds = outsetShape.getBounds(); @@ -601,8 +616,8 @@ // Instead, we just pass -1, telling setBorderStyle to just do a simple stroke setBorderStyle(g, stroke, -1); final Insets insets = stroke.getInsets(); - g.draw(resizeShape((float) insets.getTop(), (float) insets.getRight(), - (float) insets.getBottom(), (float) insets.getLeft())); + g.draw(resizeShape((float) insets.getTop(this.height), (float) insets.getRight(this.width), + (float) insets.getBottom(this.height), (float) insets.getLeft(this.width))); } } } @@ -627,8 +642,8 @@ // Adjust the box within which we will fit the shape based on the // insets. The resize shape method will resize the shape to fit final Insets insets = fill.getInsets(); - g.fill(resizeShape((float) insets.getTop(), (float) insets.getRight(), - (float) insets.getBottom(), (float) insets.getLeft())); + g.fill(resizeShape((float) insets.getTop(this.height), (float) insets.getRight(this.width), + (float) insets.getBottom(this.height), (float) insets.getLeft(this.width))); } // We now need to draw each background image. Only the "cover" property @@ -707,7 +722,7 @@ cacheHeight = Math.min(cacheHeight, (int) (topInset + bottomInset)); } - final Insets outsets = background.getOutsets(); + final Insets outsets = background.getOutsets(width, height); final int outsetsTop = roundUp(outsets.getTop()); final int outsetsRight = roundUp(outsets.getRight()); final int outsetsBottom = roundUp(outsets.getBottom()); @@ -990,18 +1005,18 @@ } } - private void renderBackgroundRectanglesDirectly(Graphics g, float width, float height) { + private void renderBackgroundRectanglesDirectly(Graphics g, float _width, float _height) { final List fills = background.getFills(); for (int i = 0, max = fills.size(); i < max; i++) { final BackgroundFill fill = fills.get(i); final Insets insets = fill.getInsets(); - final float t = (float) insets.getTop(), - l = (float) insets.getLeft(), - b = (float) insets.getBottom(), - r = (float) insets.getRight(); + final float t = (float) insets.getTop( _height - marginTop - marginBottom) + marginTop, + l = (float) insets.getLeft(_width - marginLeft - marginRight) + marginLeft, + b = (float) insets.getBottom( _height - marginTop - marginBottom) + marginBottom, + r = (float) insets.getRight(_width - marginLeft - marginRight) + marginRight; // w and h is the width and height of the area to be filled (width and height less insets) - float w = width - l - r; - float h = height - t - b; + float w = _width - l - r; + float h = _height - t - b; // Only setup and paint for those areas which have positive width and height. This means, if // the insets are such that the right edge is left of the left edge, then we have a negative // width and will not paint it. TODO we need to document this fact (RT-26924) @@ -1023,8 +1038,8 @@ g.fillRect(l, t, w, h); } else { // Fix the horizontal and vertical radii if they are percentage based - if (radii.isTopLeftHorizontalRadiusAsPercentage()) tlhr = tlhr * width; - if (radii.isTopLeftVerticalRadiusAsPercentage()) tlvr = tlvr * height; + if (radii.isTopLeftHorizontalRadiusAsPercentage()) tlhr = tlhr * _width; + if (radii.isTopLeftVerticalRadiusAsPercentage()) tlvr = tlvr * _height; // The edges are rounded, so we need to compute the arc width and arc height // and fill a round rect float arcWidth = tlhr + tlhr; @@ -1045,7 +1060,7 @@ // TODO document the issue number which will give us a fast path for rendering // non-uniform corners, and that we want to implement that instead of createPath2 // below in such cases. (RT-26979) - g.fill(createPath(width, height, t, l, b, r, normalize(radii))); + g.fill(createPath(_width, _height, t, l, b, r, normalize(radii))); } } } @@ -1065,10 +1080,10 @@ final javafx.scene.paint.Paint bottomStroke = stroke.getBottomStroke(); final javafx.scene.paint.Paint leftStroke = stroke.getLeftStroke(); - final float topInset = (float) insets.getTop(); - final float rightInset = (float) insets.getRight(); - final float bottomInset = (float) insets.getBottom(); - final float leftInset = (float) insets.getLeft(); + final float topInset = (float) insets.getTop(this.height - marginTop - marginBottom) + marginTop; + final float rightInset = (float) insets.getRight(this.width - marginLeft - marginRight) + marginRight; + final float bottomInset = (float) insets.getBottom(this.height - marginTop - marginBottom) + marginBottom; + final float leftInset = (float) insets.getLeft(this.width - marginLeft - marginRight) + marginLeft; final float topWidth = (float) (widths.isTopAsPercentage() ? height * widths.getTop() : widths.getTop()); final float rightWidth = (float) (widths.isRightAsPercentage() ? width * widths.getRight() : widths.getRight()); @@ -1260,10 +1275,10 @@ final BorderWidths slices = ib.getSlices(); // we will get gaps if we don't round to pixel boundaries - final int topInset = (int) Math.round(insets.getTop()); - final int rightInset = (int) Math.round(insets.getRight()); - final int bottomInset = (int) Math.round(insets.getBottom()); - final int leftInset = (int) Math.round(insets.getLeft()); + final int topInset = (int) Math.round(insets.getTop(this.height)); + final int rightInset = (int) Math.round(insets.getRight(this.width)); + final int bottomInset = (int) Math.round(insets.getBottom(this.height)); + final int leftInset = (int) Math.round(insets.getLeft(this.width)); final int topWidth = widthSize(widths.isTopAsPercentage(), widths.getTop(), height); final int rightWidth = widthSize(widths.isRightAsPercentage(), widths.getRight(), width); @@ -1357,7 +1372,7 @@ } /** - * Visits each of the background fills and takes their raddi into account to determine the insets. + * Visits each of the background fills and takes their radii into account to determine the insets. * The backgroundInsets variable is cleared whenever the fills change, or whenever the size of the * region has changed (because if the size of the region changed and a radius is percentage based * then we need to recompute the insets). @@ -1373,10 +1388,10 @@ final BackgroundFill fill = fills.get(i); final Insets insets = fill.getInsets(); final CornerRadii radii = normalize(fill.getRadii()); - top = (float) Math.max(top, insets.getTop() + Math.max(radii.getTopLeftVerticalRadius(), radii.getTopRightVerticalRadius())); - right = (float) Math.max(right, insets.getRight() + Math.max(radii.getTopRightHorizontalRadius(), radii.getBottomRightHorizontalRadius())); - bottom = (float) Math.max(bottom, insets.getBottom() + Math.max(radii.getBottomRightVerticalRadius(), radii.getBottomLeftVerticalRadius())); - left = (float) Math.max(left, insets.getLeft() + Math.max(radii.getTopLeftHorizontalRadius(), radii.getBottomLeftHorizontalRadius())); + top = (float) Math.max(top, insets.getTop(this.height) + Math.max(radii.getTopLeftVerticalRadius(), radii.getTopRightVerticalRadius())); + right = (float) Math.max(right, insets.getRight(this.width) + Math.max(radii.getTopRightHorizontalRadius(), radii.getBottomRightHorizontalRadius())); + bottom = (float) Math.max(bottom, insets.getBottom(this.height) + Math.max(radii.getBottomRightVerticalRadius(), radii.getBottomLeftVerticalRadius())); + left = (float) Math.max(left, insets.getLeft(this.width) + Math.max(radii.getTopLeftHorizontalRadius(), radii.getBottomLeftHorizontalRadius())); } backgroundInsets = new Insets(roundUp(top), roundUp(right), roundUp(bottom), roundUp(left)); } diff -r adcb59265f40 modules/graphics/src/main/java/javafx/geometry/Insets.java --- a/modules/graphics/src/main/java/javafx/geometry/Insets.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/geometry/Insets.java Mon Nov 25 12:35:17 2013 -0500 @@ -38,29 +38,113 @@ public static final Insets EMPTY = new Insets(0, 0, 0, 0); /** + * Specifies whether the {@link #getTop() top} property should be interpreted as a + * percentage ({@code true}) or not ({@code false}). + */ + public final boolean isTopAsPercentage() { return topAsPercentage; } + final boolean topAsPercentage; + + /** + * Specifies whether the {@link #getRight() right} property should be interpreted as a + * percentage ({@code true}) or not ({@code false}). + */ + public final boolean isRightAsPercentage() { return rightAsPercentage; } + final boolean rightAsPercentage; + + /** + * Specifies whether the {@link #getBottom() bottom} property should be interpreted as a + * percentage ({@code true}) or not ({@code false}). + */ + public final boolean isBottomAsPercentage() { return bottomAsPercentage; } + final boolean bottomAsPercentage; + + /** + * Specifies whether the {@link #getLeft() left} property should be interpreted as a + * percentage ({@code true}) or not ({@code false}). + */ + public final boolean isLeftAsPercentage() { return leftAsPercentage; } + final boolean leftAsPercentage; + + /** * The inset on the top side */ public final double getTop() { return top; } + + /** + * The normalized inset on the top side + * @param height The height applied to percentage values + * @return If top is a percentage, {@code top*height} else {@code top} + */ + public final double getTop(double height) { + return isTopAsPercentage() ? top * height : top; + } private double top; /** * The inset on the right side */ public final double getRight() { return right; } + + /** + * The normalized inset on the right side + * @param width The width applied to percentage values + * @return If right is a percentage, {@code right*width} else {@code right} + */ + public final double getRight(double width) { + return isRightAsPercentage() ? right * width : right; + } private double right; /** * The inset on the bottom side */ public final double getBottom() { return bottom; } + + /** + * The normalized inset on the bottom side + * @param height The height applied to percentage values + * @return If bottom is a percentage, {@code bottom*height} else {@code bottom} + */ + public final double getBottom(double height) { + return isBottomAsPercentage() ? bottom * height : bottom; + } private double bottom; /** * The inset on the left side */ public final double getLeft() { return left; } + + /** + * The normalized inset on the left side + * @param width The width applied to percentage values + * @return If left is a percentage, {@code left*width} else {@code left} + */ + public final double getLeft(double width) { + return isLeftAsPercentage() ? left * width : left; + } private double left; + public final boolean hasPercentBasedInsets() { + return topAsPercentage || rightAsPercentage || bottomAsPercentage || leftAsPercentage; + + } + + /** + * Return a new Insets from this Insets normalized to pixel values. + * @param width The width applied to percentage values + * @param height The height applied to percentage values + */ + public final Insets normalize(double width, double height) { + + final double _top = isTopAsPercentage() ? top * height : top; + final double _right = isRightAsPercentage() ? right * width : right; + final double _bottom = isBottomAsPercentage() ? bottom * height : bottom; + final double _left = isLeftAsPercentage() ? left * width : left; + + return new Insets(_top, _right, _bottom, _left); + } + /** * The cached hash code, used to improve performance in situations where * we cache gradients, such as in the CSS routines. @@ -69,6 +153,7 @@ /** * Constructs a new Insets instance with four different offsets. + * The offsets are treated as pixel values. * * @param top the top offset * @param right the right offset @@ -76,41 +161,101 @@ * @param left the left offset */ public Insets(@NamedArg("top") double top, @NamedArg("right") double right, @NamedArg("bottom") double bottom, @NamedArg("left") double left) { + this(top, right, bottom, left, false, false, false, false); + } + + /** + * Constructs a new Insets instance with same value for all four offsets. + * The offsets are treated as pixel values. + * + * @param topRightBottomLeft the value used for top, bottom, right and left + * offset + */ + public Insets(@NamedArg("topRightBottomLeft") double topRightBottomLeft) { + this(topRightBottomLeft, topRightBottomLeft, topRightBottomLeft, topRightBottomLeft, false, false, false, false); + } + + /** + * Constructs a new Insets instance with same value for all four offsets. + * + * @param topRightBottomLeft the value used for top, bottom, right and left + * @param topRightBottomLeftAsPercentage If true, topRightBottomLeft is treated as a percentage value + * offset + */ + public Insets(@NamedArg("topRightBottomLeft") double topRightBottomLeft, + @NamedArg("topRightBottomLeftAsPercentage") boolean topRightBottomLeftAsPercentage) { + this(topRightBottomLeft, topRightBottomLeft, topRightBottomLeft, topRightBottomLeft, + topRightBottomLeftAsPercentage, topRightBottomLeftAsPercentage, topRightBottomLeftAsPercentage, topRightBottomLeftAsPercentage); + } + + /** + * Creates a new Insets. + * + * @param top The offsets of the top. + * @param right The inset of the right. + * @param bottom The inset of the bottom. + * @param left The inset of the left. + * @param topAsPercentage Whether the top should be treated as a percentage. + * @param rightAsPercentage Whether the right should be treated as a percentage. + * @param bottomAsPercentage Whether the bottom should be treated as a percentage. + * @param leftAsPercentage Whether the left should be treated as a percentage. + */ + public Insets(@NamedArg("top") double top, @NamedArg("right") double right, + @NamedArg("bottom") double bottom, @NamedArg("left") double left, + @NamedArg("topAsPercentage") boolean topAsPercentage, @NamedArg("rightAsPercentage") boolean rightAsPercentage, + @NamedArg("bottomAsPercentage") boolean bottomAsPercentage, @NamedArg("leftAsPercentage") boolean leftAsPercentage) { + this.top = top; this.right = right; this.bottom = bottom; this.left = left; + + this.topAsPercentage = topAsPercentage; + this.rightAsPercentage = rightAsPercentage; + this.bottomAsPercentage = bottomAsPercentage; + this.leftAsPercentage = leftAsPercentage; + + long bits = 17L; + bits = 37L * bits + Double.doubleToLongBits(top); + bits = 37L * bits + Double.doubleToLongBits(right); + bits = 37L * bits + Double.doubleToLongBits(bottom); + bits = 37L * bits + Double.doubleToLongBits(left); + bits = 37L * bits + (this.topAsPercentage ? 1 : 0); + bits = 37L * bits + (this.rightAsPercentage ? 1 : 0); + bits = 37L * bits + (this.bottomAsPercentage ? 1 : 0); + bits = 37L * bits + (this.leftAsPercentage ? 1 : 0); + hash = (int) (bits ^ (bits >> 32)); } - /** - * Constructs a new Insets instance with same value for all four offsets. - * - * @param topRightBottomLeft the value used for top, bottom, right and left - * offset - */ - public Insets(@NamedArg("topRightBottomLeft") double topRightBottomLeft) { - this.top = topRightBottomLeft; - this.right = topRightBottomLeft; - this.bottom = topRightBottomLeft; - this.left = topRightBottomLeft; - } + /** - * Indicates whether some other object is "equal to" this one. - * - * @param obj the reference object with which to compare - * @return true if this object is the same as the obj argument; false otherwise - */ + * Indicates whether some other object is "equal to" this one. + * + * @param obj the reference object with which to compare + * @return true if this object is the same as the obj argument; false otherwise + */ @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj instanceof Insets) { Insets other = (Insets) obj; - return top == other.top - && right == other.right - && bottom == other.bottom - && left == other.left; - } else return false; + if (this.hash != other.hash) return false; + + if (bottomAsPercentage != other.bottomAsPercentage) return false; + if (leftAsPercentage != other.leftAsPercentage) return false; + if (rightAsPercentage != other.rightAsPercentage) return false; + if (topAsPercentage != other.topAsPercentage) return false; + + if (Double.compare(this.top, other.top) != 0) return false; + if (Double.compare(this.right, other.right) != 0) return false; + if (Double.compare(this.bottom, other.bottom) != 0) return false; + if (Double.compare(this.left, other.left) != 0) return false; + + return true; + } + + return false; } /** @@ -118,14 +263,6 @@ * @return a hash code value for the insets. */ @Override public int hashCode() { - if (hash == 0) { - long bits = 17L; - bits = 37L * bits + Double.doubleToLongBits(top); - bits = 37L * bits + Double.doubleToLongBits(right); - bits = 37L * bits + Double.doubleToLongBits(bottom); - bits = 37L * bits + Double.doubleToLongBits(left); - hash = (int) (bits ^ (bits >> 32)); - } return hash; } @@ -134,7 +271,14 @@ * @return a string representation for the insets. */ @Override public String toString() { - return "Insets [top=" + top + ", right=" + right + ", bottom=" - + bottom + ", left=" + left + "]"; + return String.format("Insets [" + + "top=" + (isTopAsPercentage() ? "%1$.2f%%" : "%5$.2f") + + ",right=" + (isRightAsPercentage() ? "%2$.2f%%" : "%6$.2f") + + ",bottom=" + (isBottomAsPercentage() ? "%3$.2f%%" : "%7$.2f") + + ",left=" + (isLeftAsPercentage() ? "%4$.2f%%" : "%8$.2f") + + "]", + top*100, right*100, bottom*100, left*100, + top, right, bottom, left + ); } } diff -r adcb59265f40 modules/graphics/src/main/java/javafx/scene/layout/Background.java --- a/modules/graphics/src/main/java/javafx/scene/layout/Background.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/scene/layout/Background.java Mon Nov 25 12:35:17 2013 -0500 @@ -60,7 +60,7 @@ * both may be empty. Each defined {@link BackgroundFill} is rendered in order, * followed by each defined {@link BackgroundImage}. *

- * The Background's {@link #getOutsets() outsets} define any extension of the drawing area of a Region + * The Background's {@link #getOutsets(double, double) outsets} define any extension of the drawing area of a Region * which is necessary to account for all background drawing. These outsets are strictly * defined by the BackgroundFills that are specified on this Background, if any, because * all BackgroundImages are clipped to the drawing area, and do not define it. The @@ -152,9 +152,47 @@ * the distance from the edge of the Region outward. Any BackgroundImages * which would extend beyond the outsets will be clipped. Only the * BackgroundFills contribute to the outsets. + * @param width + * @param height */ - public final Insets getOutsets() { return outsets; } - final Insets outsets; + public final Insets getOutsets(double width, double height) { + + // This has to be calculated on the fly since the BackgroundFill's insets, which are RegionInsets, + // might be proportional. + if (fills == null || fills.isEmpty()) { + return Insets.EMPTY; + } + + double outerTop = 0, outerRight = 0, outerBottom = 0, outerLeft = 0; + + for (int i=0, iMax=fills.size(); i(noNulls, size); } - hasPercentageBasedFills = hasPercentFillRadii; - - // This ensures that we either have outsets of 0, if all the insets were positive, - // or a value greater than zero if they were negative. - outsets = new Insets( - Math.max(0, -outerTop), - Math.max(0, -outerRight), - Math.max(0, -outerBottom), - Math.max(0, -outerLeft)); + hasPercentageBasedFills = hasPercentFill; // An null or empty images array results in an empty list if (images == null || images.length == 0) { @@ -423,10 +444,10 @@ for (int i=0, max=fills.size(); i + * The RegionInsets will never be null, but the values may be negative * in order to position the border beyond the natural bounds * (that is, (0, 0, width, height)) of the Region. */ - public final Insets getInsets() { return insets; } + public final Insets getInsets() { + return insets; + } final Insets insets; + final boolean hasPercentBasedFill; /** * A cached hash for improved performance on subsequent hash or * equality look ups. It is expected that BackgroundFill will in @@ -91,6 +95,8 @@ this.radii = radii == null ? CornerRadii.EMPTY : radii; this.insets = insets == null ? Insets.EMPTY : insets; + hasPercentBasedFill = this.radii.hasPercentBasedRadii || this.insets.hasPercentBasedInsets(); + // Pre-compute the hash code. NOTE: all variables are prefixed with "this" so that we // do not accidentally compute the hash based on the constructor arguments rather than // based on the fields themselves! diff -r adcb59265f40 modules/graphics/src/main/java/javafx/scene/layout/Border.java --- a/modules/graphics/src/main/java/javafx/scene/layout/Border.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/scene/layout/Border.java Mon Nov 25 12:35:17 2013 -0500 @@ -60,15 +60,15 @@ * both may be empty. When rendering, if no images are specified or no * image succeeds in loading, then all strokes will be rendered in order. * If any image is specified and succeeds in loading, then no strokes will - * be drawn, although they will still contribute to the {@link #getInsets() insets} - * and {@link #getOutsets() outsets} of the Border. + * be drawn, although they will still contribute to the {@link #getInsets(double, double) insets} + * and {@link #getOutsets(double, double) outsets} of the Border. *

- * The Border's {@link #getOutsets() outsets} define any extension of the drawing area of a Region + * The Border's {@link #getOutsets(double, double) outsets} define any extension of the drawing area of a Region * which is necessary to account for all border drawing and positioning. These outsets are defined * by both the {@link BorderStroke}s and {@link BorderImage}s specified on this Border. * Outsets are strictly non-negative. *

- * {@link #getInsets()} are used to define the inner-most edge of all of the borders. It also is + * {@link #getInsets(double, double)} are used to define the inner-most edge of all of the borders. It also is * always strictly non-negative. The Region uses the insets of the {@link Background} and Border * and the {@link javafx.scene.layout.Region#getPadding() Region's padding} to determine the * Region {@link javafx.scene.layout.Region#getInsets() insets}, which define the content area @@ -180,17 +180,141 @@ /** * The outsets of the border define the outer-most edge of the border to be drawn. * The values in these outsets are strictly non-negative. + * @param width + * @param height */ - public final Insets getOutsets() { return outsets; } - final Insets outsets; + public final Insets getOutsets(double width, double height) { + + // outsets have to be calculated on the fly since RegionInsets on strokes and images may be proportional + double outerTop = 0d; + double outerRight = 0d; + double outerBottom = 0d; + double outerLeft = 0d; + + if (strokes != null) { + for (int i=0, iMax=strokes.size(); i= strokeOuterTop ? outerTop : strokeOuterTop; + outerRight = outerRight >= strokeOuterRight ? outerRight : strokeOuterRight; + outerBottom = outerBottom >= strokeOuterBottom ? outerBottom : strokeOuterBottom; + outerLeft = outerLeft >= strokeOuterLeft ? outerLeft : strokeOuterLeft; + } + } + } + + if (images != null) { + for (int i=0, iMax=images.size(); i= imageOuterTop ? outerTop : imageOuterTop; + outerRight = outerRight >= imageOuterRight ? outerRight : imageOuterRight; + outerBottom = outerBottom >= imageOuterBottom ? outerBottom : imageOuterBottom; + outerLeft = outerLeft >= imageOuterLeft ? outerLeft : imageOuterLeft; + } + } + } + + // Both the BorderStroke and BorderImage class make sure to return the outsets + // and insets in the right way, such that we don't have to worry about adjusting + // the sign, etc, unlike in the Background implementation. + return new Insets(outerTop, outerRight, outerBottom, outerLeft); + } /** * The insets define the distance from the edge of the Region to the inner-most edge - * of the border, if that distance is non-negative. The values in these outsets + * of the border, if that distance is non-negative. The values in these insets * are strictly non-negative. + * @param width + * @param height */ - public final Insets getInsets() { return insets; } - final Insets insets; + public final Insets getInsets(double width, double height) { + + if ((strokes == null || strokes.isEmpty()) && (images == null || images.isEmpty())) { + return Insets.EMPTY; + } + + // insets have to be calculated on the fly since RegionInsets on strokes and images may be proportional + double innerTop = 0d; + double innerRight = 0d; + double innerBottom = 0d; + double innerLeft = 0d; + + if (strokes != null) { + for (int i=0, iMax=strokes.size(); i= strokeInnerTop ? innerTop : strokeInnerTop; + innerRight = innerRight >= strokeInnerRight ? innerRight : strokeInnerRight; + innerBottom = innerBottom >= strokeInnerBottom ? innerBottom : strokeInnerBottom; + innerLeft = innerLeft >= strokeInnerLeft ? innerLeft : strokeInnerLeft; + + } + } + } + + if (images != null) { + for (int i=0, iMax=images.size(); i= imageInnerTop ? innerTop : imageInnerTop; + innerRight = innerRight >= imageInnerRight ? innerRight : imageInnerRight; + innerBottom = innerBottom >= imageInnerBottom ? innerBottom : imageInnerBottom; + innerLeft = innerLeft >= imageInnerLeft ? innerLeft : imageInnerLeft; + + } + } + } + + // Both the BorderStroke and BorderImage class make sure to return the outsets + // and insets in the right way, such that we don't have to worry about adjusting + // the sign, etc, unlike in the Background implementation. + return new Insets(innerTop, innerRight, innerBottom, innerLeft); + } + final boolean hasPercentBasedInsets; /** * Gets whether the Border is empty. It is empty if there are no strokes or images. @@ -212,7 +336,7 @@ * Creates a new Border by supplying an array of BorderStrokes. * This array may be null, or may contain null values. Any null values * will be ignored and will not contribute to the {@link #getStrokes() strokes} - * or {@link #getOutsets() outsets} or {@link #getInsets() insets}. + * or {@link #getOutsets(double, double) outsets} or {@link #getInsets(double, double) insets}. * * @param strokes The strokes. This may be null, and may contain nulls. Any * contained nulls are filtered out and not included in the @@ -230,7 +354,7 @@ * Creates a new Border by supplying an array of BorderImages. * This array may be null, or may contain null values. Any null values * will be ignored and will not contribute to the {@link #getImages() images} - * or {@link #getOutsets() outsets} or {@link #getInsets() insets}. + * or {@link #getOutsets(double, double) outsets} or {@link #getInsets(double, double) insets}. * * @param images The images. This may be null, and may contain nulls. Any * contained nulls are filtered out and not included in the @@ -244,8 +368,8 @@ * Creates a new Border by supplying a List of BorderStrokes and BorderImages. * These Lists may be null, or may contain null values. Any null values * will be ignored and will not contribute to the {@link #getStrokes() strokes} - * or {@link #getImages() images}, {@link #getOutsets() outsets}, or - * {@link #getInsets() insets}. + * or {@link #getImages() images}, {@link #getOutsets(double, double) outsets}, or + * {@link #getInsets(double, double) insets}. * * @param strokes The strokes. This may be null, and may contain nulls. Any * contained nulls are filtered out and not included in the @@ -272,8 +396,8 @@ * Creates a new Border by supplying an array of BorderStrokes and BorderImages. * These arrays may be null, or may contain null values. Any null values * will be ignored and will not contribute to the {@link #getStrokes() strokes} - * or {@link #getImages() images}, {@link #getOutsets() outsets}, or - * {@link #getInsets() insets}. + * or {@link #getImages() images}, {@link #getOutsets(double, double) outsets}, or + * {@link #getInsets(double, double) insets}. * * @param strokes The strokes. This may be null, and may contain nulls. Any * contained nulls are filtered out and not included in the @@ -287,9 +411,8 @@ * final List of images. A null array becomes an empty List. */ public Border(@NamedArg("strokes") BorderStroke[] strokes, @NamedArg("images") BorderImage[] images) { - double innerTop = 0, innerRight = 0, innerBottom = 0, innerLeft = 0; - double outerTop = 0, outerRight = 0, outerBottom = 0, outerLeft = 0; + boolean hasPercentBasedInsets = false; if (strokes == null || strokes.length == 0) { this.strokes = Collections.emptyList(); } else { @@ -299,34 +422,12 @@ final BorderStroke stroke = strokes[i]; if (stroke != null) { noNulls[size++] = stroke; - - // Calculate the insets and outsets. "insets" are the distance - // from the edge of the region to the inmost edge of the inmost border. - // Outsets are the distance from the edge of the region out towards the - // outer-most edge of the outer-most border. - final double strokeInnerTop = stroke.innerEdge.getTop(); - final double strokeInnerRight = stroke.innerEdge.getRight(); - final double strokeInnerBottom = stroke.innerEdge.getBottom(); - final double strokeInnerLeft = stroke.innerEdge.getLeft(); - - innerTop = innerTop >= strokeInnerTop ? innerTop : strokeInnerTop; - innerRight = innerRight >= strokeInnerRight? innerRight : strokeInnerRight; - innerBottom = innerBottom >= strokeInnerBottom ? innerBottom : strokeInnerBottom; - innerLeft = innerLeft >= strokeInnerLeft ? innerLeft : strokeInnerLeft; - - final double strokeOuterTop = stroke.outerEdge.getTop(); - final double strokeOuterRight = stroke.outerEdge.getRight(); - final double strokeOuterBottom = stroke.outerEdge.getBottom(); - final double strokeOuterLeft = stroke.outerEdge.getLeft(); - - outerTop = outerTop >= strokeOuterTop ? outerTop : strokeOuterTop; - outerRight = outerRight >= strokeOuterRight? outerRight : strokeOuterRight; - outerBottom = outerBottom >= strokeOuterBottom ? outerBottom : strokeOuterBottom; - outerLeft = outerLeft >= strokeOuterLeft ? outerLeft : strokeOuterLeft; + hasPercentBasedInsets |= stroke.getInsets().hasPercentBasedInsets(); } } this.strokes = new UnmodifiableArrayList(noNulls, size); } + this.hasPercentBasedInsets = hasPercentBasedInsets; if (images == null || images.length == 0) { this.images = Collections.emptyList(); @@ -337,39 +438,11 @@ final BorderImage image = images[i]; if (image != null){ noNulls[size++] = image; - - // The Image width + insets may contribute to the insets / outsets of - // this border. - final double imageInnerTop = image.innerEdge.getTop(); - final double imageInnerRight = image.innerEdge.getRight(); - final double imageInnerBottom = image.innerEdge.getBottom(); - final double imageInnerLeft = image.innerEdge.getLeft(); - - innerTop = innerTop >= imageInnerTop ? innerTop : imageInnerTop; - innerRight = innerRight >= imageInnerRight? innerRight : imageInnerRight; - innerBottom = innerBottom >= imageInnerBottom ? innerBottom : imageInnerBottom; - innerLeft = innerLeft >= imageInnerLeft ? innerLeft : imageInnerLeft; - - final double imageOuterTop = image.outerEdge.getTop(); - final double imageOuterRight = image.outerEdge.getRight(); - final double imageOuterBottom = image.outerEdge.getBottom(); - final double imageOuterLeft = image.outerEdge.getLeft(); - - outerTop = outerTop >= imageOuterTop ? outerTop : imageOuterTop; - outerRight = outerRight >= imageOuterRight? outerRight : imageOuterRight; - outerBottom = outerBottom >= imageOuterBottom ? outerBottom : imageOuterBottom; - outerLeft = outerLeft >= imageOuterLeft ? outerLeft : imageOuterLeft; } } this.images = new UnmodifiableArrayList(noNulls, size); } - // Both the BorderStroke and BorderImage class make sure to return the outsets - // and insets in the right way, such that we don't have to worry about adjusting - // the sign, etc, unlike in the Background implementation. - outsets = new Insets(outerTop, outerRight, outerBottom, outerLeft); - insets = new Insets(innerTop, innerRight, innerBottom, innerLeft); - // Pre-compute the hash code. NOTE: all variables are prefixed with "this" so that we // do not accidentally compute the hash based on the constructor arguments rather than // based on the fields themselves! diff -r adcb59265f40 modules/graphics/src/main/java/javafx/scene/layout/BorderImage.java --- a/modules/graphics/src/main/java/javafx/scene/layout/BorderImage.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/scene/layout/BorderImage.java Mon Nov 25 12:35:17 2013 -0500 @@ -111,15 +111,39 @@ final boolean filled; /** - * The insets of the BorderImage define where the border should be positioned - * relative to the edge of the Region. This value will never be null. + * The Insets to use for this border image. Each inset indicates at what + * distance from the Region's bounds the drawing should begin. + *

+ * The Insets will never be null, but the values may be negative + * in order to position the border beyond the natural bounds + * (that is, (0, 0, width, height)) of the Region. */ - public final Insets getInsets() { return insets; } + public final Insets getInsets() { + return insets; + } final Insets insets; - // These two are used by Border to compute the insets and outsets of the border - final Insets innerEdge; - final Insets outerEdge; + // Compute the insets of the inner edge of the border + final Insets getInnerEdge(double width, double height) { + + return new Insets( + insets.getTop(height) + (widths.isTopAsPercentage() ? height * widths.getTop() : widths.getTop()), + insets.getRight(width) + (widths.isRightAsPercentage() ? width * widths.getRight() : widths.getRight()), + insets.getBottom(height) + (widths.isBottomAsPercentage() ? width * widths.getBottom() : widths.getBottom()), + insets.getLeft(width) + (widths.isLeftAsPercentage() ? height * widths.getLeft() : widths.getLeft())); + } + + // Compute the insets of the outer edge of the border + final Insets getOuterEdge(double width, double height) { + + if (insets == Insets.EMPTY) return insets; + + return new Insets( + Math.max(0, -insets.getTop(height)), + Math.max(0, -insets.getRight(width)), + Math.max(0, -insets.getBottom(height)), + Math.max(0, -insets.getLeft(width))); + } /** * A cached hash code for faster secondary usage. It is expected @@ -134,11 +158,10 @@ * @param image The image to use. This must not be null. * @param widths The widths of the border in each dimension. A null value results in Insets.EMPTY. * @param insets The insets at which to place the border relative to the region. - * A null value results in Insets.EMPTY. + * A null value results in Insets.EMPTY. * @param slices The slices for the image. If null, defaults to BorderImageSlices.DEFAULT * @param repeatX The repeat value for the border image in the x direction. If null, defaults to STRETCH. * @param repeatY The repeat value for the border image in the y direction. If null, defaults to the same - * value as repeatX. */ public BorderImage( @NamedArg("image") Image image, @NamedArg("widths") BorderWidths widths, @NamedArg("insets") Insets insets, @NamedArg("slices") BorderWidths slices, @NamedArg("filled") boolean filled, @@ -152,19 +175,6 @@ this.repeatX = repeatX == null ? BorderRepeat.STRETCH : repeatX; this.repeatY = repeatY == null ? this.repeatX : repeatY; - // Compute the inner & outer edge. The outer edge is insets.top, - // while the inner edge is insets.top + widths.top - outerEdge = new Insets( - Math.max(0, -this.insets.getTop()), - Math.max(0, -this.insets.getRight()), - Math.max(0, -this.insets.getBottom()), - Math.max(0, -this.insets.getLeft())); - innerEdge = new Insets( - this.insets.getTop() + this.widths.getTop(), - this.insets.getRight() + this.widths.getRight(), - this.insets.getBottom() + this.widths.getBottom(), - this.insets.getLeft() + this.widths.getLeft()); - // Pre-compute the hash code. NOTE: all variables are prefixed with "this" so that we // do not accidentally compute the hash based on the constructor arguments rather than // based on the fields themselves! diff -r adcb59265f40 modules/graphics/src/main/java/javafx/scene/layout/BorderStroke.java --- a/modules/graphics/src/main/java/javafx/scene/layout/BorderStroke.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/scene/layout/BorderStroke.java Mon Nov 25 12:35:17 2013 -0500 @@ -149,16 +149,40 @@ final BorderWidths widths; /** - * Defines the insets of each side of the BorderStroke. This will never - * be null, and defaults to EMPTY. + * The Insets to use for this border. Each inset indicates at what + * distance from the Region's bounds the drawing should begin. + *

+ * The Insets will never be null, but the values may be negative + * in order to position the border beyond the natural bounds + * (that is, (0, 0, width, height)) of the Region. */ - public final Insets getInsets() { return insets; } + public final Insets getInsets() { + return insets; + } final Insets insets; // These two are used by Border to compute the insets and outsets of the border - final Insets innerEdge; - final Insets outerEdge; + final Insets getInnerEdge(double width, double height) { + return new Insets( + insets.getTop(height) + innerEdge.getTop(height), + insets.getRight(width) + innerEdge.getRight(width), + insets.getBottom(height) + innerEdge.getBottom(height), + insets.getLeft(width) + innerEdge.getLeft(width) + ); + } + private final Insets innerEdge; + + final Insets getOuterEdge(double width, double height) { + + return new Insets( + Math.max(0, outerEdge.getTop(height)) - insets.getTop(height), + Math.max(0, outerEdge.getRight(width)) - insets.getRight(width), + Math.max(0, outerEdge.getBottom(height))- insets.getBottom(height), + Math.max(0, outerEdge.getLeft(width)) - insets.getLeft(width) + ); + } + private final Insets outerEdge; /** * Defines the radii for each corner of this BorderStroke. This will never * be null, and defaults to CornerRadii.EMPTY. @@ -291,17 +315,24 @@ // TODO these calculations are not accurate if we are stroking a shape. In such cases, we // need to account for the mitre limit + // innerEdge and outerEdge are calculated without regard to the Insets. The + // Insets are accounted for in the getInnerEdge and getOuterEdge methods. + // TODO: if none of the Insets are proportional, then these could be pre-calculated. innerEdge = new Insets( - this.insets.getTop() + computeInside(this.topStyle.getType(), this.widths.getTop()), - this.insets.getRight() + computeInside(this.rightStyle.getType(), this.widths.getRight()), - this.insets.getBottom() + computeInside(this.bottomStyle.getType(), this.widths.getBottom()), - this.insets.getLeft() + computeInside(this.leftStyle.getType(), this.widths.getLeft()) + computeInside(this.topStyle.getType(), this.widths.getTop()), + computeInside(this.rightStyle.getType(), this.widths.getRight()), + computeInside(this.bottomStyle.getType(), this.widths.getBottom()), + computeInside(this.leftStyle.getType(), this.widths.getLeft()), + this.widths.isTopAsPercentage(), this.widths.isRightAsPercentage(), + this.widths.isBottomAsPercentage(), this.widths.isLeftAsPercentage() ); outerEdge = new Insets( - Math.max(0, computeOutside(this.topStyle.getType(), this.widths.getTop()) - this.insets.getTop()), - Math.max(0, computeOutside(this.rightStyle.getType(), this.widths.getRight()) - this.insets.getRight()), - Math.max(0, computeOutside(this.bottomStyle.getType(), this.widths.getBottom())- this.insets.getBottom()), - Math.max(0, computeOutside(this.leftStyle.getType(), this.widths.getLeft()) - this.insets.getLeft()) + computeOutside(this.topStyle.getType(), this.widths.getTop()), + computeOutside(this.rightStyle.getType(), this.widths.getRight()), + computeOutside(this.bottomStyle.getType(), this.widths.getBottom()), + computeOutside(this.leftStyle.getType(), this.widths.getLeft()), + this.widths.isTopAsPercentage(), this.widths.isRightAsPercentage(), + this.widths.isBottomAsPercentage(), this.widths.isLeftAsPercentage() ); this.hash = preComputeHash(); } diff -r adcb59265f40 modules/graphics/src/main/java/javafx/scene/layout/Region.java --- a/modules/graphics/src/main/java/javafx/scene/layout/Region.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/main/java/javafx/scene/layout/Region.java Mon Nov 25 12:35:17 2013 -0500 @@ -568,6 +568,89 @@ public final ObjectProperty paddingProperty() { return padding; } /** + * The top, right, bottom, and left margin which extends from the padding + * around the region's content. This space will be included in the calculation of the region's + * minimum and preferred sizes. By default margin is Insets.EMPTY. Setting the + * value to null should be avoided. Margins may be negative. + * @since JavaFX 8.0 + */ + private ObjectProperty margin = new StyleableObjectProperty(Insets.EMPTY) { + // Keep track of the last valid value for the sake of + // rollback in case margin is set to null. Note that + // Richard really does not like this pattern because + // it essentially means that binding the margin property + // is not possible since a binding expression could very + // easily produce an intermediate null value. + + // Also note that because margin is set virtually everywhere via CSS, and CSS + // requires a property object in order to set it, there is no benefit to having + // lazy initialization here. + + private Insets lastValidValue = Insets.EMPTY; + + @Override public Object getBean() { return Region.this; } + @Override public String getName() { return "padding"; } + @Override public CssMetaData getCssMetaData() { + return StyleableProperties.PADDING; + } + @Override public void invalidated() { + final Insets newValue = get(); + if (newValue == null) { + // rollback + if (isBound()) { + unbind(); + } + set(lastValidValue); + throw new NullPointerException("cannot set padding to null"); + } else if (!newValue.equals(lastValidValue)) { + lastValidValue = newValue; + insets.fireValueChanged(); + } + } + }; + public final void setMargin(Insets value) { marginProperty().set(value); } + public final Insets getMargin() { return margin == null ? Insets.EMPTY : margin.get(); } + public final ObjectProperty marginProperty() { + if (margin == null) { + margin = new StyleableObjectProperty(Insets.EMPTY) { + // Keep track of the last valid value for the sake of + // rollback in case margin is set to null. Note that + // Richard really does not like this pattern because + // it essentially means that binding the margin property + // is not possible since a binding expression could very + // easily produce an intermediate null value. + + // Unlike padding, margin is not often used from CSS, + // so it is lazily instantiated here. + + private Insets lastValidValue = Insets.EMPTY; + + @Override public Object getBean() { return Region.this; } + @Override public String getName() { return "margin"; } + @Override public CssMetaData getCssMetaData() { + return StyleableProperties.MARGIN; + } + @Override public void invalidated() { + final Insets newValue = get(); + if (newValue == null) { + // rollback + if (isBound()) { + unbind(); + } + set(lastValidValue); + throw new NullPointerException("cannot set margin to null"); + } else if (!newValue.equals(lastValidValue)) { + lastValidValue = newValue; + insets.fireValueChanged(); + } + } + }; + + } + return margin; + } + + /** * The background of the Region, which is made up of zero or more BackgroundFills, and * zero or more BackgroundImages. It is possible for a Background to be empty, where it * has neither fills nor images, and is semantically equivalent to null. @@ -585,7 +668,10 @@ final Background b = get(); if(old != null ? !old.equals(b) : b != null) { // They are different! Both cannot be null - if (old == null || b == null || !old.getOutsets().equals(b.getOutsets())) { + // getOutsets wants width and height. Here we just want to know if they are different + // so the actual width and height don't matter, but we need to pass 1 in case the + // outsets are proportional. + if (old == null || b == null || !old.getOutsets(1d,1d).equals(b.getOutsets(1d,1d))) { // We have determined that the outsets of these two different background // objects is different, and therefore the bounds have changed. impl_geomChanged(); @@ -641,7 +727,10 @@ final Border b = get(); if(old != null ? !old.equals(b) : b != null) { // They are different! Both cannot be null - if (old == null || b == null || !old.getOutsets().equals(b.getOutsets())) { + // getOutsets wants width and height. Here we just want to know if they are different + // so the actual width and height don't matter, but we need to pass 1 in case the + // outsets are proportional. + if (old == null || b == null || !old.getOutsets(1d,1d).equals(b.getOutsets(1d,1d))) { // We have determined that the outsets of these two different border // objects is different, and therefore the bounds have changed. impl_geomChanged(); @@ -784,26 +873,26 @@ // If there is no border or the border has no insets itself, then the only thing // affecting the insets is the padding, so we can just return it directly. final Border b = getBorder(); - if (b == null || Insets.EMPTY.equals(b.getInsets())) { + if (b == null) { return getPadding(); } // There is a border with some non-zero insets and we do not have a _shape, so we need // to take the border's insets into account if (cache == null) { - // Combine the padding and the border insets. - // TODO note that negative border insets were being ignored, but - // I'm not sure that that made sense or was reasonable, so I have - // changed it so that we just do simple math. - // TODO Stroke borders should NOT contribute to the insets. Ensure via tests. - final Insets borderInsets = b.getInsets(); + // Combine the padding and the margin insets. + final Insets marginInsets = getMargin(); final Insets paddingInsets = getPadding(); - cache = new Insets( - borderInsets.getTop() + paddingInsets.getTop(), - borderInsets.getRight() + paddingInsets.getRight(), - borderInsets.getBottom() + paddingInsets.getBottom(), - borderInsets.getLeft() + paddingInsets.getLeft() - ); + if (!Insets.EMPTY.equals(marginInsets) || !Insets.EMPTY.equals(paddingInsets)) { + cache = new Insets( + marginInsets.getTop() + paddingInsets.getTop(), + marginInsets.getRight() + paddingInsets.getRight(), + marginInsets.getBottom() + paddingInsets.getBottom(), + marginInsets.getLeft() + paddingInsets.getLeft() + ); + } else { + cache = Insets.EMPTY; + } } return cache; } @@ -820,17 +909,17 @@ /** Called to update the cached snapped insets */ private void updateSnappedInsets() { - final Insets insets = getInsets(); + final Insets _insets = getInsets(); if (_snapToPixel) { - snappedTopInset = Math.ceil(insets.getTop()); - snappedRightInset = Math.ceil(insets.getRight()); - snappedBottomInset = Math.ceil(insets.getBottom()); - snappedLeftInset = Math.ceil(insets.getLeft()); + snappedTopInset = Math.ceil(_insets.getTop()); + snappedRightInset = Math.ceil(_insets.getRight()); + snappedBottomInset = Math.ceil(_insets.getBottom()); + snappedLeftInset = Math.ceil(_insets.getLeft()); } else { - snappedTopInset = insets.getTop(); - snappedRightInset = insets.getRight(); - snappedBottomInset = insets.getBottom(); - snappedLeftInset = insets.getLeft(); + snappedTopInset = _insets.getTop(); + snappedRightInset = _insets.getRight(); + snappedBottomInset = _insets.getBottom(); + snappedLeftInset = _insets.getLeft(); } } @@ -2373,6 +2462,8 @@ final boolean sizeChanged = impl_isDirty(DirtyBits.NODE_GEOMETRY); if (sizeChanged) { pg.setSize((float)getWidth(), (float)getHeight()); + Insets _margins = getMargin(); + pg.setMargins((float)_margins.getTop(), (float)_margins.getRight(), (float)_margins.getBottom(), (float)_margins.getLeft()); } // NOTE: The order here is very important. There is logic in NGRegion which determines @@ -2590,7 +2681,7 @@ final List fills = background.getFills(); for (int i = 0, max = fills.size(); i < max; i++) { final BackgroundFill bgFill = fills.get(i); - if (contains(localX, localY, 0, 0, x2, y2, bgFill.getInsets(), bgFill.getRadii(), maxRadius)) { + if (contains(localX, localY, 0, 0, x2, y2, bgFill.getInsets().normalize(x2,y2), bgFill.getRadii(), maxRadius)) { return true; } } @@ -2606,7 +2697,7 @@ final List strokes = border.getStrokes(); for (int i=0, max=strokes.size(); i MARGIN = + new CssMetaData("-fx-margin", + InsetsConverter.getInstance(), Insets.EMPTY) { + + @Override public boolean isSettable(Region node) { + return node.margin == null || !node.margin.isBound(); + } + + @Override public StyleableProperty getStyleableProperty(Region node) { + return (StyleableProperty)node.marginProperty(); + } + }; + private static final CssMetaData OPAQUE_INSETS = new CssMetaData("-fx-opaque-insets", InsetsConverter.getInstance(), null) { @@ -3135,6 +3239,7 @@ final List> styleables = new ArrayList>(Parent.getClassCssMetaData()); styleables.add(PADDING); + styleables.add(MARGIN); styleables.add(BACKGROUND); styleables.add(BORDER); styleables.add(OPAQUE_INSETS); diff -r adcb59265f40 modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundFillConverterTest.java --- a/modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundFillConverterTest.java Mon Nov 25 10:00:45 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.javafx.scene.layout.region; - -import org.junit.Test; - -/** - * Tests for the BackgroundFillConverter class - */ -public class BackgroundFillConverterTest { - - @Test public void dummy() { } - /* - -fx-background-color: - -fx-background-radius: - -fx-background-insets: - */ -// @Test public void scenario1() { -// Map map = new HashMap(); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(0, fills.size()); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: -// -fx-background-insets: -// */ -// @Test public void scenario2() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 0, 0, 0, 0, Insets.EMPTY); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: 10 -// -fx-background-insets: -// */ -// @Test public void scenario3() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, Insets.EMPTY); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: 1 2 3 4 -// -fx-background-insets: -// */ -// @Test public void scenario4() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(1.0, 2.0, 3.0, 4.0) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 1, 2, 3, 4, Insets.EMPTY); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: 10 -// -fx-background-insets: 1 -// */ -// @Test public void scenario5() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: 10, 20 -// -fx-background-insets: 1 -// */ -// @Test public void scenario6() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10), new Insets(20) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue -// -fx-background-radius: 10 -// -fx-background-insets: 1, 2 -// */ -// @Test public void scenario7() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1), new Insets(2) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(1, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue, green -// -fx-background-radius: 10 -// -fx-background-insets: 1 -// */ -// @Test public void scenario8() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE, Color.GREEN }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(2, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// -// fill = fills.get(1); -// expected = new BackgroundFill(Color.GREEN, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue, green -// -fx-background-radius: 10, 20 -// -fx-background-insets: 1 -// */ -// @Test public void scenario9() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE, Color.GREEN }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10), new Insets(20) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(2, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// -// fill = fills.get(1); -// expected = new BackgroundFill(Color.GREEN, 20, 20, 20, 20, new Insets(1)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: blue, green -// -fx-background-radius: 10 -// -fx-background-insets: 1, 2 -// */ -// @Test public void scenario10() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Paint[] { Color.BLUE, Color.GREEN }); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[] { new Insets(10) }); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[] { new Insets(1), new Insets(2) }); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(2, fills.size()); -// -// BackgroundFill fill = fills.get(0); -// BackgroundFill expected = new BackgroundFill(Color.BLUE, 10, 10, 10, 10, new Insets(1)); -// assertEquals(expected, fill); -// -// fill = fills.get(1); -// expected = new BackgroundFill(Color.GREEN, 10, 10, 10, 10, new Insets(2)); -// assertEquals(expected, fill); -// } -// -// /* -// -fx-background-color: null -// -fx-background-radius: null -// -fx-background-insets: null -// */ -// @Test public void scenario11() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, null); -// map.put(BackgroundFill.BACKGROUND_RADIUS, null); -// map.put(BackgroundFill.BACKGROUND_INSETS, null); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(0, fills.size()); -// } -// -// /* -// -fx-background-color: [] -// -fx-background-radius: [] -// -fx-background-insets: [] -// */ -// @Test public void scenario12() { -// Map map = new HashMap(); -// map.put(BackgroundFill.BACKGROUND_COLOR, new Color[0]); -// map.put(BackgroundFill.BACKGROUND_RADIUS, new Insets[0]); -// map.put(BackgroundFill.BACKGROUND_INSETS, new Insets[0]); -// List fills = BackgroundFillConverter.getInstance().convert(map); -// assertEquals(0, fills.size()); -// } - -} diff -r adcb59265f40 modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundFillTest.java --- a/modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundFillTest.java Mon Nov 25 10:00:45 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.javafx.scene.layout.region; - -import javafx.geometry.Insets; -import javafx.scene.layout.BackgroundFill; -import javafx.scene.paint.Color; -import org.junit.Test; - -import java.util.HashMap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Tests for the BackgroundFill class - */ -public class BackgroundFillTest { - - @Test public void valuesAreSetCorrectly() { -// BackgroundFill obj = new BackgroundFill(Color.ORANGE, 1, 2, 3, 4, new Insets(20)); -// assertEquals(Color.ORANGE, obj.getFill()); -// assertEquals(1, obj.getTopLeftCornerRadius(), 0); -// assertEquals(2, obj.getTopRightCornerRadius(), 0); -// assertEquals(3, obj.getBottomRightCornerRadius(), 0); -// assertEquals(4, obj.getBottomLeftCornerRadius(), 0); -// assertEquals(new Insets(20), obj.getOffsets()); - } - - @Test public void hashingReturnsSameObject() { -// HashMap map = new HashMap(); -// BackgroundFill obj = new BackgroundFill(Color.ORANGE, 1, 2, 3, 4, new Insets(20)); -// map.put(obj, "YES"); -// assertEquals("YES", map.get(obj)); -// -// BackgroundFill equivalent = new BackgroundFill(Color.ORANGE, 1, 2, 3, 4, new Insets(20)); -// assertEquals("YES", map.get(equivalent)); -// -// BackgroundFill different = new BackgroundFill(Color.ORANGE, 1, /*different!*/3, 3, 4, new Insets(20)); -// assertFalse(map.containsKey(different)); - } - - @Test public void equality() { -// BackgroundFill obj = new BackgroundFill(Color.ORANGE, 1, 2, 3, 4, new Insets(20)); -// BackgroundFill equivalent = new BackgroundFill(Color.ORANGE, 1, 2, 3, 4, new Insets(20)); -// assertTrue(obj.equals(equivalent)); -// -// BackgroundFill different = new BackgroundFill(Color.ORANGE, 1, /*different!*/3, 3, 4, new Insets(20)); -// assertFalse(obj.equals(different)); - } -} diff -r adcb59265f40 modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundImageTest.java --- a/modules/graphics/src/test/java/com/sun/javafx/scene/layout/region/BackgroundImageTest.java Mon Nov 25 10:00:45 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.javafx.scene.layout.region; - -import org.junit.Test; - -/** - * Tests for the BackgroundImage class - */ -public class BackgroundImageTest { - - @Test public void dummy() { } - -// @Test public void valuesAreSetCorrectly() { -// Image image = new Image("http://dummyUrl", true); -// BackgroundImage obj = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, true, false, true, false, true, false); -// -// assertEquals(image, obj.getImage()); -// assertEquals(Repeat.SPACE, obj.getRepeatX()); -// assertEquals(Repeat.ROUND, obj.getRepeatY()); -// assertEquals(1, obj.getTop(), 0); -// assertEquals(2, obj.getRight(), 0); -// assertEquals(3, obj.getBottom(), 0); -// assertEquals(4, obj.getLeft(), 0); -// assertEquals(5, obj.getWidth(), 0); -// assertEquals(6, obj.getHeight(), 0); -// assertTrue(obj.isProportionalHPos()); -// assertFalse(obj.isProportionalVPos()); -// assertTrue(obj.isProportionalWidth()); -// assertFalse(obj.isProportionalHeight()); -// assertTrue(obj.isContain()); -// assertFalse(obj.isCover()); -// } -// -// @Test public void valuesAreSetCorrectly2() { -// Image image = new Image("http://dummyUrl", true); -// BackgroundImage obj = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, false, true, false, true, false, true); -// -// assertEquals(image, obj.getImage()); -// assertEquals(Repeat.SPACE, obj.getRepeatX()); -// assertEquals(Repeat.ROUND, obj.getRepeatY()); -// assertEquals(1, obj.getTop(), 0); -// assertEquals(2, obj.getRight(), 0); -// assertEquals(3, obj.getBottom(), 0); -// assertEquals(4, obj.getLeft(), 0); -// assertEquals(5, obj.getWidth(), 0); -// assertEquals(6, obj.getHeight(), 0); -// assertFalse(obj.isProportionalHPos()); -// assertTrue(obj.isProportionalVPos()); -// assertFalse(obj.isProportionalWidth()); -// assertTrue(obj.isProportionalHeight()); -// assertFalse(obj.isContain()); -// assertTrue(obj.isCover()); -// } -// -// @Test public void hashingReturnsSameObject() { -// Map map = new HashMap(); -// Image image = new Image("http://dummyUrl", true); -// BackgroundImage obj = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, true, false, true, false, true, false); -// map.put(obj, "YES"); -// assertEquals("YES", map.get(obj)); -// -// BackgroundImage equivalent = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, true, false, true, false, true, false); -// assertEquals("YES", map.get(equivalent)); -// -// BackgroundImage different = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, false, true, false, true, false, true); -// assertFalse(map.containsKey(different)); -// } -// -// @Test public void equality() { -// Image image = new Image("http://dummyUrl", true); -// BackgroundImage obj = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, true, false, true, false, true, false); -// -// BackgroundImage equivalent = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, true, false, true, false, true, false); -// -// assertEquals(obj, equivalent); -// -// BackgroundImage different = new BackgroundImage(image, Repeat.SPACE, Repeat.ROUND, -// 1, 2, 3, 4, 5, 6, false, true, false, true, false, true); -// assertFalse(obj.equals(different)); -// } -} diff -r adcb59265f40 modules/graphics/src/test/java/javafx/scene/layout/BackgroundTest.java --- a/modules/graphics/src/test/java/javafx/scene/layout/BackgroundTest.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/test/java/javafx/scene/layout/BackgroundTest.java Mon Nov 25 12:35:17 2013 -0500 @@ -253,7 +253,7 @@ }; Background b = new Background(fills, null); - assertEquals(new Insets(7, 2, 8, 8), b.getOutsets()); + assertEquals(new Insets(7, 2, 8, 8), b.getOutsets(1,1)); } @Test public void backgroundImagesDoNotContributeToOutsets() { @@ -264,7 +264,7 @@ }; Background b = new Background(null, images); - assertEquals(Insets.EMPTY, b.getOutsets()); + assertEquals(Insets.EMPTY, b.getOutsets(1,1)); } @Test public void equivalent() { diff -r adcb59265f40 modules/graphics/src/test/java/javafx/scene/layout/BorderTest.java --- a/modules/graphics/src/test/java/javafx/scene/layout/BorderTest.java Mon Nov 25 10:00:45 2013 -0500 +++ b/modules/graphics/src/test/java/javafx/scene/layout/BorderTest.java Mon Nov 25 12:35:17 2013 -0500 @@ -62,6 +62,9 @@ new BorderImage(IMAGE_4, new BorderWidths(3), Insets.EMPTY, new BorderWidths(3, 4, 5, 6), true, STRETCH, SPACE) }; + private static final int width = 0; + private static final int height = 0; + @Test public void instanceCreation() { Border b = new Border(STROKES_1, IMAGES_1); assertEquals(STROKES_1.length, b.getStrokes().size(), 0); @@ -254,9 +257,9 @@ Border border = new Border(new BorderStroke[] { stroke }, null); // This is a 2 pixel solid stroke painted on the OUTSIDE. This means that the // outsets should be 2 pixel. - assertEquals(new Insets(2), border.getOutsets()); + assertEquals(new Insets(2), border.getOutsets(width,height)); // The insets should be 0, because the stroke is on the OUTSIDE - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelOuterStroke() { @@ -265,9 +268,9 @@ Border border = new Border(new BorderStroke[] { stroke }, null); // This is a 1 pixel solid stroke painted on the OUTSIDE. This means that the // outsets should be 1 pixel. - assertEquals(new Insets(1), border.getOutsets()); + assertEquals(new Insets(1), border.getOutsets(width,height)); // The insets should be 0, because the stroke is on the OUTSIDE - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelCenteredStroke() { @@ -276,9 +279,9 @@ Border border = new Border(new BorderStroke[] { stroke }, null); // This is a 1 pixel solid stroke painted CENTERED. This means that the // outsets should be .5 pixel. - assertEquals(new Insets(.5), border.getOutsets()); + assertEquals(new Insets(.5), border.getOutsets(width,height)); // The insets should be .5, because the stroke is CENTERED - assertEquals(new Insets(.5), border.getInsets()); + assertEquals(new Insets(.5), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelInnerStroke() { @@ -287,101 +290,101 @@ Border border = new Border(new BorderStroke[] { stroke }, null); // This is a 1 pixel solid stroke painted on the INSIDE. This means that the // outsets should be 0 pixel. - assertEquals(new Insets(0), border.getOutsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); // The insets should be 1, because the stroke is on the INSIDE - assertEquals(new Insets(1), border.getInsets()); + assertEquals(new Insets(1), border.getInsets(width,height)); } @Test public void insetsAndOutsets_twoPixelOuterStroke_PositiveInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.OUTSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(2), new Insets(1, 2, 3, 4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(1, 0, 0, 0), border.getOutsets()); - assertEquals(new Insets(1, 2, 3, 4), border.getInsets()); + assertEquals(new Insets(1, 0, 0, 0), border.getOutsets(width,height)); + assertEquals(new Insets(1, 2, 3, 4), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelOuterStroke_PositiveInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.OUTSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(1, 2, 3, 4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(0), border.getOutsets()); - assertEquals(new Insets(1, 2, 3, 4), border.getInsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); + assertEquals(new Insets(1, 2, 3, 4), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelCenteredStroke_PositiveInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.CENTERED, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(1, 2, 3, 4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(0), border.getOutsets()); - assertEquals(new Insets(1.5, 2.5, 3.5, 4.5), border.getInsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); + assertEquals(new Insets(1.5, 2.5, 3.5, 4.5), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelInnerStroke_PositiveInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.INSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(1, 2, 3, 4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(0), border.getOutsets()); - assertEquals(new Insets(2, 3, 4, 5), border.getInsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); + assertEquals(new Insets(2, 3, 4, 5), border.getInsets(width,height)); } @Test public void insetsAndOutsets_twoPixelOuterStroke_NegativeInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.OUTSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(2), new Insets(-1, -2, -3, -4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(3, 4, 5, 6), border.getOutsets()); - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(3, 4, 5, 6), border.getOutsets(width,height)); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelOuterStroke_NegativeInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.OUTSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(-1, -2, -3, -4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(2, 3, 4, 5), border.getOutsets()); - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(2, 3, 4, 5), border.getOutsets(width,height)); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelCenteredStroke_NegativeInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.CENTERED, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(-1, -2, -3, -4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(1.5, 2.5, 3.5, 4.5), border.getOutsets()); - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(1.5, 2.5, 3.5, 4.5), border.getOutsets(width,height)); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelInnerStroke_NegativeInsets() { BorderStrokeStyle style = new BorderStrokeStyle(StrokeType.INSIDE, null, null, 0, 0, null); BorderStroke stroke = new BorderStroke(Color.ORANGE, style, new CornerRadii(5), new BorderWidths(1), new Insets(-1, -2, -3, -4)); Border border = new Border(new BorderStroke[] { stroke }, null); - assertEquals(new Insets(1, 2, 3, 4), border.getOutsets()); - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(1, 2, 3, 4), border.getOutsets(width,height)); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelImageWidthNoInsets() { BorderImage image = new BorderImage(IMAGE_1, new BorderWidths(1), new Insets(0), null, false, null, null); Border border = new Border(null, new BorderImage[] { image }); - assertEquals(new Insets(0), border.getOutsets()); - assertEquals(new Insets(1), border.getInsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); + assertEquals(new Insets(1), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelImageWidthWithPositiveInsets() { BorderImage image = new BorderImage(IMAGE_1, new BorderWidths(1), new Insets(10), null, false, null, null); Border border = new Border(null, new BorderImage[] { image }); - assertEquals(new Insets(0), border.getOutsets()); - assertEquals(new Insets(11), border.getInsets()); + assertEquals(new Insets(0), border.getOutsets(width,height)); + assertEquals(new Insets(11), border.getInsets(width,height)); } @Test public void insetsAndOutsets_singlePixelImageWidthWithNegativeInsets() { BorderImage image = new BorderImage(IMAGE_1, new BorderWidths(1), new Insets(-10), null, false, null, null); Border border = new Border(null, new BorderImage[] { image }); - assertEquals(new Insets(10), border.getOutsets()); - assertEquals(new Insets(0), border.getInsets()); + assertEquals(new Insets(10), border.getOutsets(width,height)); + assertEquals(new Insets(0), border.getInsets(width,height)); } @Test public void insetsAndOutsets_triplePixelImageWidthWithNegativeInsets() { BorderImage image = new BorderImage(IMAGE_1, new BorderWidths(3), new Insets(-1), null, false, null, null); Border border = new Border(null, new BorderImage[] { image }); - assertEquals(new Insets(1), border.getOutsets()); - assertEquals(new Insets(2), border.getInsets()); + assertEquals(new Insets(1), border.getOutsets(width,height)); + assertEquals(new Insets(2), border.getInsets(width,height)); } @Test public void equivalent() {