strokes;
/**
* The list of BorderImages which together define the images to use
* instead of stroke for this Border. If this list is specified and
* at least one image within it succeeds in loading, then any specified
* {@link #getStrokes strokes} are not drawn. If this list is null or no images
* succeeded in loading, then any specified {@code strokes} are drawn.
*
* This List is unmodifiable and immutable. It will never be null.
* It will never contain any null elements.
*/
public final List getImages() { return images; }
final List images;
/**
* 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.
*/
public final Insets getOutsets() { return outsets; }
final Insets outsets;
/**
* 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
* are strictly non-negative.
*/
public final Insets getInsets() { return insets; }
final Insets insets;
/**
* Gets whether the Border is empty. It is empty if there are no strokes or images.
* @return true if the Border is empty, false otherwise.
*/
public final boolean isEmpty() {
return strokes.isEmpty() && images.isEmpty();
}
/**
* The cached hash code computation for the Border. One very big
* reason for making Border immutable was to make it possible to
* cache and reuse the same Border instance for multiple
* Regions. To enable efficient caching, we cache the hash.
*/
private final int hash;
/**
* 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}.
*
* @param strokes The strokes. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* final List of strokes. A null array becomes an empty List.
* If both strokes and images are specified, and if any one
* of the images specified succeeds in loading, then no
* strokes are shown. In this way, strokes can be defined as
* a fallback in the case that an image failed to load.
*/
public Border(@NamedArg("strokes") BorderStroke... strokes) {
this(strokes, null);
}
/**
* 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}.
*
* @param images The images. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* final List of images. A null array becomes an empty List.
*/
public Border(@NamedArg("images") BorderImage... images) {
this(null, images);
}
/**
* 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}.
*
* @param strokes The strokes. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* final List of strokes. A null array becomes an empty List.
* If both strokes and images are specified, and if any one
* of the images specified succeeds in loading, then no
* strokes are shown. In this way, strokes can be defined as
* a fallback in the case that an image failed to load.
* @param images The images. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* final List of images. A null array becomes an empty List.
*/
public Border(@NamedArg("strokes") List strokes, @NamedArg("images") List images) {
// NOTE: This constructor had to be supplied in order to cause a Builder
// to be auto-generated, because otherwise the types of the strokes and images
// properties didn't match the types of the array based constructor parameters.
// So a Builder will use this constructor, while the CSS engine uses the
// array based constructor (for speed).
this(strokes == null ? null : strokes.toArray(new BorderStroke[strokes.size()]),
images == null ? null : images.toArray(new BorderImage[images.size()]));
}
/**
* 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}.
*
* @param strokes The strokes. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* final List of strokes. A null array becomes an empty List.
* If both strokes and images are specified, and if any one
* of the images specified succeeds in loading, then no
* strokes are shown. In this way, strokes can be defined as
* a fallback in the case that an image failed to load.
* @param images The images. This may be null, and may contain nulls. Any
* contained nulls are filtered out and not included in the
* 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;
if (strokes == null || strokes.length == 0) {
this.strokes = Collections.emptyList();
} else {
final BorderStroke[] noNulls = new BorderStroke[strokes.length];
int size = 0;
for (int i=0; i= 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;
}
}
this.strokes = new UnmodifiableArrayList(noNulls, size);
}
if (images == null || images.length == 0) {
this.images = Collections.emptyList();
} else {
final BorderImage[] noNulls = new BorderImage[images.length];
int size = 0;
for (int i=0; i= 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!
int result = this.strokes.hashCode();
result = 31 * result + this.images.hashCode();
hash = result;
}
/**
* @inheritDoc
*/
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Border border = (Border) o;
if (this.hash != border.hash) return false;
if (!images.equals(border.images)) return false;
if (!strokes.equals(border.strokes)) return false;
return true;
}
/**
* @inheritDoc
*/
@Override public int hashCode() {
return hash;
}
}