Merge
This commit is contained in:
commit
da6966ded5
@ -49,9 +49,11 @@ import java.beans.ConstructorProperties;
|
|||||||
* from the focus point to the circumference will thus span all the gradient
|
* from the focus point to the circumference will thus span all the gradient
|
||||||
* colors.
|
* colors.
|
||||||
* <p>
|
* <p>
|
||||||
* Specifying a focus point outside of the circle's radius will result in the
|
* Specifying a focus point outside of the radius of the circle will cause
|
||||||
* focus being set to the intersection point of the focus-center line and the
|
* the rings of the gradient pattern to be centered on the point just inside
|
||||||
* perimeter of the circle.
|
* the edge of the circle in the direction of the focus point.
|
||||||
|
* The rendering will internally use this modified location as if it were
|
||||||
|
* the specified focus point.
|
||||||
* <p>
|
* <p>
|
||||||
* The user must provide an array of floats specifying how to distribute the
|
* The user must provide an array of floats specifying how to distribute the
|
||||||
* colors along the gradient. These values should range from 0.0 to 1.0 and
|
* colors along the gradient. These values should range from 0.0 to 1.0 and
|
||||||
@ -621,6 +623,11 @@ public final class RadialGradientPaint extends MultipleGradientPaint {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of the focus point of the radial gradient.
|
* Returns a copy of the focus point of the radial gradient.
|
||||||
|
* Note that if the focus point specified when the radial gradient
|
||||||
|
* was constructed lies outside of the radius of the circle, this
|
||||||
|
* method will still return the original focus point even though
|
||||||
|
* the rendering may center the rings of color on a different
|
||||||
|
* point that lies inside the radius.
|
||||||
*
|
*
|
||||||
* @return a {@code Point2D} object that is a copy of the focus point
|
* @return a {@code Point2D} object that is a copy of the focus point
|
||||||
*/
|
*/
|
||||||
|
@ -681,7 +681,7 @@ public abstract class Arc2D extends RectangularShape {
|
|||||||
* @see java.awt.geom.Arc2D.Float
|
* @see java.awt.geom.Arc2D.Float
|
||||||
* @see java.awt.geom.Arc2D.Double
|
* @see java.awt.geom.Arc2D.Double
|
||||||
*/
|
*/
|
||||||
Arc2D() {
|
protected Arc2D() {
|
||||||
this(OPEN);
|
this(OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +732,7 @@ public abstract class Path2D implements Shape, Cloneable {
|
|||||||
*
|
*
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public PathIterator getPathIterator(AffineTransform at) {
|
public final PathIterator getPathIterator(AffineTransform at) {
|
||||||
if (at == null) {
|
if (at == null) {
|
||||||
return new CopyIterator(this);
|
return new CopyIterator(this);
|
||||||
} else {
|
} else {
|
||||||
@ -1461,7 +1461,7 @@ public abstract class Path2D implements Shape, Cloneable {
|
|||||||
* of this {@code Shape}'s outline
|
* of this {@code Shape}'s outline
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public PathIterator getPathIterator(AffineTransform at) {
|
public final PathIterator getPathIterator(AffineTransform at) {
|
||||||
if (at == null) {
|
if (at == null) {
|
||||||
return new CopyIterator(this);
|
return new CopyIterator(this);
|
||||||
} else {
|
} else {
|
||||||
@ -2342,7 +2342,7 @@ public abstract class Path2D implements Shape, Cloneable {
|
|||||||
*
|
*
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public PathIterator getPathIterator(AffineTransform at,
|
public final PathIterator getPathIterator(AffineTransform at,
|
||||||
double flatness)
|
double flatness)
|
||||||
{
|
{
|
||||||
return new FlatteningPathIterator(getPathIterator(at), flatness);
|
return new FlatteningPathIterator(getPathIterator(at), flatness);
|
||||||
|
@ -27,6 +27,8 @@ package sun.java2d.pisces;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import static java.lang.Math.ulp;
|
||||||
|
import static java.lang.Math.sqrt;
|
||||||
|
|
||||||
import sun.awt.geom.PathConsumer2D;
|
import sun.awt.geom.PathConsumer2D;
|
||||||
|
|
||||||
@ -130,7 +132,7 @@ final class Stroker implements PathConsumer2D {
|
|||||||
private static void computeOffset(final float lx, final float ly,
|
private static void computeOffset(final float lx, final float ly,
|
||||||
final float w, final float[] m)
|
final float w, final float[] m)
|
||||||
{
|
{
|
||||||
final float len = (float)Math.sqrt(lx*lx + ly*ly);
|
final float len = (float) sqrt(lx*lx + ly*ly);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
m[0] = m[1] = 0;
|
m[0] = m[1] = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +219,7 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// this normal's length is at least 0.5 and at most sqrt(2)/2 (because
|
// this normal's length is at least 0.5 and at most sqrt(2)/2 (because
|
||||||
// we know the angle of the arc is > 90 degrees).
|
// we know the angle of the arc is > 90 degrees).
|
||||||
float nx = my - omy, ny = omx - mx;
|
float nx = my - omy, ny = omx - mx;
|
||||||
float nlen = (float)Math.sqrt(nx*nx + ny*ny);
|
float nlen = (float) sqrt(nx*nx + ny*ny);
|
||||||
float scale = lineWidth2/nlen;
|
float scale = lineWidth2/nlen;
|
||||||
float mmx = nx * scale, mmy = ny * scale;
|
float mmx = nx * scale, mmy = ny * scale;
|
||||||
|
|
||||||
@ -246,8 +248,8 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// define the bezier curve we're computing.
|
// define the bezier curve we're computing.
|
||||||
// It is computed using the constraints that P1-P0 and P3-P2 are parallel
|
// It is computed using the constraints that P1-P0 and P3-P2 are parallel
|
||||||
// to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
|
// to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
|
||||||
float cv = (float)((4.0 / 3.0) * Math.sqrt(0.5-cosext2) /
|
float cv = (float) ((4.0 / 3.0) * sqrt(0.5-cosext2) /
|
||||||
(1.0 + Math.sqrt(cosext2+0.5)));
|
(1.0 + sqrt(cosext2+0.5)));
|
||||||
// if clockwise, we need to negate cv.
|
// if clockwise, we need to negate cv.
|
||||||
if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
|
if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
|
||||||
cv = -cv;
|
cv = -cv;
|
||||||
@ -284,9 +286,10 @@ final class Stroker implements PathConsumer2D {
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the intersection point of the lines (x0, y0) -> (x1, y1)
|
// Put the intersection point of the lines (x0, y0) -> (x1, y1)
|
||||||
// and (x0p, y0p) -> (x1p, y1p) in m[0] and m[1]
|
// and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1].
|
||||||
private void computeMiter(final float x0, final float y0,
|
// If the lines are parallel, it will put a non finite number in m.
|
||||||
|
private void computeIntersection(final float x0, final float y0,
|
||||||
final float x1, final float y1,
|
final float x1, final float y1,
|
||||||
final float x0p, final float y0p,
|
final float x0p, final float y0p,
|
||||||
final float x1p, final float y1p,
|
final float x1p, final float y1p,
|
||||||
@ -297,15 +300,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
float x10p = x1p - x0p;
|
float x10p = x1p - x0p;
|
||||||
float y10p = y1p - y0p;
|
float y10p = y1p - y0p;
|
||||||
|
|
||||||
// if this is 0, the lines are parallel. If they go in the
|
|
||||||
// same direction, there is no intersection so m[off] and
|
|
||||||
// m[off+1] will contain infinity, so no miter will be drawn.
|
|
||||||
// If they go in the same direction that means that the start of the
|
|
||||||
// current segment and the end of the previous segment have the same
|
|
||||||
// tangent, in which case this method won't even be involved in
|
|
||||||
// miter drawing because it won't be called by drawMiter (because
|
|
||||||
// (mx == omx && my == omy) will be true, and drawMiter will return
|
|
||||||
// immediately).
|
|
||||||
float den = x10*y10p - x10p*y10;
|
float den = x10*y10p - x10p*y10;
|
||||||
float t = x10p*(y0-y0p) - y10p*(x0-x0p);
|
float t = x10p*(y0-y0p) - y10p*(x0-x0p);
|
||||||
t /= den;
|
t /= den;
|
||||||
@ -321,7 +315,8 @@ final class Stroker implements PathConsumer2D {
|
|||||||
{
|
{
|
||||||
if ((mx == omx && my == omy) ||
|
if ((mx == omx && my == omy) ||
|
||||||
(pdx == 0 && pdy == 0) ||
|
(pdx == 0 && pdy == 0) ||
|
||||||
(dx == 0 && dy == 0)) {
|
(dx == 0 && dy == 0))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,12 +327,17 @@ final class Stroker implements PathConsumer2D {
|
|||||||
my = -my;
|
my = -my;
|
||||||
}
|
}
|
||||||
|
|
||||||
computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
|
computeIntersection((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
|
||||||
(dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
|
(dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
|
||||||
miter, 0);
|
miter, 0);
|
||||||
|
|
||||||
float lenSq = (miter[0]-x0)*(miter[0]-x0) + (miter[1]-y0)*(miter[1]-y0);
|
float lenSq = (miter[0]-x0)*(miter[0]-x0) + (miter[1]-y0)*(miter[1]-y0);
|
||||||
|
|
||||||
|
// If the lines are parallel, lenSq will be either NaN or +inf
|
||||||
|
// (actually, I'm not sure if the latter is possible. The important
|
||||||
|
// thing is that -inf is not possible, because lenSq is a square).
|
||||||
|
// For both of those values, the comparison below will fail and
|
||||||
|
// no miter will be drawn, which is correct.
|
||||||
if (lenSq < miterLimitSq) {
|
if (lenSq < miterLimitSq) {
|
||||||
emitLineTo(miter[0], miter[1], rev);
|
emitLineTo(miter[0], miter[1], rev);
|
||||||
}
|
}
|
||||||
@ -566,8 +566,8 @@ final class Stroker implements PathConsumer2D {
|
|||||||
|
|
||||||
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
|
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
|
||||||
// in which case ignore if p1 == p2
|
// in which case ignore if p1 == p2
|
||||||
final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
|
final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * ulp(y2));
|
||||||
final boolean p3eqp4 = within(x3,y3,x4,y4, 6 * Math.ulp(y4));
|
final boolean p3eqp4 = within(x3,y3,x4,y4, 6 * ulp(y4));
|
||||||
if (p1eqp2 && p3eqp4) {
|
if (p1eqp2 && p3eqp4) {
|
||||||
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
||||||
return 4;
|
return 4;
|
||||||
@ -583,7 +583,7 @@ final class Stroker implements PathConsumer2D {
|
|||||||
float dotsq = (dx1 * dx4 + dy1 * dy4);
|
float dotsq = (dx1 * dx4 + dy1 * dy4);
|
||||||
dotsq = dotsq * dotsq;
|
dotsq = dotsq * dotsq;
|
||||||
float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
|
float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
|
||||||
if (Helpers.within(dotsq, l1sq * l4sq, 4 * Math.ulp(dotsq))) {
|
if (Helpers.within(dotsq, l1sq * l4sq, 4 * ulp(dotsq))) {
|
||||||
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@ -693,8 +693,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute offset curves using bezier spline through t=0.5 (i.e.
|
|
||||||
// ComputedCurve(0.5) == IdealParallelCurve(0.5))
|
|
||||||
// return the kind of curve in the right and left arrays.
|
// return the kind of curve in the right and left arrays.
|
||||||
private int computeOffsetQuad(float[] pts, final int off,
|
private int computeOffsetQuad(float[] pts, final int off,
|
||||||
float[] leftOff, float[] rightOff)
|
float[] leftOff, float[] rightOff)
|
||||||
@ -703,58 +701,69 @@ final class Stroker implements PathConsumer2D {
|
|||||||
final float x2 = pts[off + 2], y2 = pts[off + 3];
|
final float x2 = pts[off + 2], y2 = pts[off + 3];
|
||||||
final float x3 = pts[off + 4], y3 = pts[off + 5];
|
final float x3 = pts[off + 4], y3 = pts[off + 5];
|
||||||
|
|
||||||
float dx3 = x3 - x2;
|
final float dx3 = x3 - x2;
|
||||||
float dy3 = y3 - y2;
|
final float dy3 = y3 - y2;
|
||||||
float dx1 = x2 - x1;
|
final float dx1 = x2 - x1;
|
||||||
float dy1 = y2 - y1;
|
final float dy1 = y2 - y1;
|
||||||
|
|
||||||
// if p1=p2 or p3=p4 it means that the derivative at the endpoint
|
// this computes the offsets at t = 0, 1
|
||||||
// vanishes, which creates problems with computeOffset. Usually
|
|
||||||
// this happens when this stroker object is trying to winden
|
|
||||||
// a curve with a cusp. What happens is that curveTo splits
|
|
||||||
// the input curve at the cusp, and passes it to this function.
|
|
||||||
// because of inaccuracies in the splitting, we consider points
|
|
||||||
// equal if they're very close to each other.
|
|
||||||
|
|
||||||
// if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
|
|
||||||
// in which case ignore.
|
|
||||||
final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
|
|
||||||
final boolean p2eqp3 = within(x2,y2,x3,y3, 6 * Math.ulp(y3));
|
|
||||||
if (p1eqp2 || p2eqp3) {
|
|
||||||
getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
|
|
||||||
float dotsq = (dx1 * dx3 + dy1 * dy3);
|
|
||||||
dotsq = dotsq * dotsq;
|
|
||||||
float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
|
|
||||||
if (Helpers.within(dotsq, l1sq * l3sq, 4 * Math.ulp(dotsq))) {
|
|
||||||
getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this computes the offsets at t=0, 0.5, 1, using the property that
|
|
||||||
// for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
|
|
||||||
// the (dx/dt, dy/dt) vectors at the endpoints.
|
|
||||||
computeOffset(dx1, dy1, lineWidth2, offset[0]);
|
computeOffset(dx1, dy1, lineWidth2, offset[0]);
|
||||||
computeOffset(dx3, dy3, lineWidth2, offset[1]);
|
computeOffset(dx3, dy3, lineWidth2, offset[1]);
|
||||||
float x1p = x1 + offset[0][0]; // start
|
|
||||||
float y1p = y1 + offset[0][1]; // point
|
|
||||||
float x3p = x3 + offset[1][0]; // end
|
|
||||||
float y3p = y3 + offset[1][1]; // point
|
|
||||||
|
|
||||||
computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
|
leftOff[0] = x1 + offset[0][0]; leftOff[1] = y1 + offset[0][1];
|
||||||
leftOff[0] = x1p; leftOff[1] = y1p;
|
leftOff[4] = x3 + offset[1][0]; leftOff[5] = y3 + offset[1][1];
|
||||||
leftOff[4] = x3p; leftOff[5] = y3p;
|
rightOff[0] = x1 - offset[0][0]; rightOff[1] = y1 - offset[0][1];
|
||||||
x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
|
rightOff[4] = x3 - offset[1][0]; rightOff[5] = y3 - offset[1][1];
|
||||||
x3p = x3 - offset[1][0]; y3p = y3 - offset[1][1];
|
|
||||||
computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
|
float x1p = leftOff[0]; // start
|
||||||
rightOff[0] = x1p; rightOff[1] = y1p;
|
float y1p = leftOff[1]; // point
|
||||||
rightOff[4] = x3p; rightOff[5] = y3p;
|
float x3p = leftOff[4]; // end
|
||||||
|
float y3p = leftOff[5]; // point
|
||||||
|
|
||||||
|
// Corner cases:
|
||||||
|
// 1. If the two control vectors are parallel, we'll end up with NaN's
|
||||||
|
// in leftOff (and rightOff in the body of the if below), so we'll
|
||||||
|
// do getLineOffsets, which is right.
|
||||||
|
// 2. If the first or second two points are equal, then (dx1,dy1)==(0,0)
|
||||||
|
// or (dx3,dy3)==(0,0), so (x1p, y1p)==(x1p+dx1, y1p+dy1)
|
||||||
|
// or (x3p, y3p)==(x3p-dx3, y3p-dy3), which means that
|
||||||
|
// computeIntersection will put NaN's in leftOff and right off, and
|
||||||
|
// we will do getLineOffsets, which is right.
|
||||||
|
computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
|
||||||
|
float cx = leftOff[2];
|
||||||
|
float cy = leftOff[3];
|
||||||
|
|
||||||
|
if (!(isFinite(cx) && isFinite(cy))) {
|
||||||
|
// maybe the right path is not degenerate.
|
||||||
|
x1p = rightOff[0];
|
||||||
|
y1p = rightOff[1];
|
||||||
|
x3p = rightOff[4];
|
||||||
|
y3p = rightOff[5];
|
||||||
|
computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
|
||||||
|
cx = rightOff[2];
|
||||||
|
cy = rightOff[3];
|
||||||
|
if (!(isFinite(cx) && isFinite(cy))) {
|
||||||
|
// both are degenerate. This curve is a line.
|
||||||
|
getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
// {left,right}Off[0,1,4,5] are already set to the correct values.
|
||||||
|
leftOff[2] = 2*x2 - cx;
|
||||||
|
leftOff[3] = 2*y2 - cy;
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rightOff[2,3] = (x2,y2) - ((left_x2, left_y2) - (x2, y2))
|
||||||
|
// == 2*(x2, y2) - (left_x2, left_y2)
|
||||||
|
rightOff[2] = 2*x2 - cx;
|
||||||
|
rightOff[3] = 2*y2 - cy;
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFinite(float x) {
|
||||||
|
return (Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
// This is where the curve to be processed is put. We give it
|
// This is where the curve to be processed is put. We give it
|
||||||
// enough room to store 2 curves: one for the current subdivision, the
|
// enough room to store 2 curves: one for the current subdivision, the
|
||||||
// other for the rest of the curve.
|
// other for the rest of the curve.
|
||||||
@ -812,12 +821,12 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// if these vectors are too small, normalize them, to avoid future
|
// if these vectors are too small, normalize them, to avoid future
|
||||||
// precision problems.
|
// precision problems.
|
||||||
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxs*dxs + dys*dys);
|
float len = (float) sqrt(dxs*dxs + dys*dys);
|
||||||
dxs /= len;
|
dxs /= len;
|
||||||
dys /= len;
|
dys /= len;
|
||||||
}
|
}
|
||||||
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxf*dxf + dyf*dyf);
|
float len = (float) sqrt(dxf*dxf + dyf*dyf);
|
||||||
dxf /= len;
|
dxf /= len;
|
||||||
dyf /= len;
|
dyf /= len;
|
||||||
}
|
}
|
||||||
@ -834,7 +843,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
while(it.hasNext()) {
|
while(it.hasNext()) {
|
||||||
int curCurveOff = it.next();
|
int curCurveOff = it.next();
|
||||||
|
|
||||||
kind = 0;
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 8:
|
case 8:
|
||||||
kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
|
kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
|
||||||
@ -843,7 +851,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
|
kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (kind != 0) {
|
|
||||||
emitLineTo(lp[0], lp[1]);
|
emitLineTo(lp[0], lp[1]);
|
||||||
switch(kind) {
|
switch(kind) {
|
||||||
case 8:
|
case 8:
|
||||||
@ -861,7 +868,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
}
|
}
|
||||||
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
||||||
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
||||||
@ -887,7 +893,7 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// we rotate it so that the first vector in the control polygon is
|
// we rotate it so that the first vector in the control polygon is
|
||||||
// parallel to the x-axis. This will ensure that rotated quarter
|
// parallel to the x-axis. This will ensure that rotated quarter
|
||||||
// circles won't be subdivided.
|
// circles won't be subdivided.
|
||||||
final float hypot = (float)Math.sqrt(x12 * x12 + y12 * y12);
|
final float hypot = (float) sqrt(x12 * x12 + y12 * y12);
|
||||||
final float cos = x12 / hypot;
|
final float cos = x12 / hypot;
|
||||||
final float sin = y12 / hypot;
|
final float sin = y12 / hypot;
|
||||||
final float x1 = cos * pts[0] + sin * pts[1];
|
final float x1 = cos * pts[0] + sin * pts[1];
|
||||||
@ -976,12 +982,12 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// if these vectors are too small, normalize them, to avoid future
|
// if these vectors are too small, normalize them, to avoid future
|
||||||
// precision problems.
|
// precision problems.
|
||||||
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxs*dxs + dys*dys);
|
float len = (float) sqrt(dxs*dxs + dys*dys);
|
||||||
dxs /= len;
|
dxs /= len;
|
||||||
dys /= len;
|
dys /= len;
|
||||||
}
|
}
|
||||||
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxf*dxf + dyf*dyf);
|
float len = (float) sqrt(dxf*dxf + dyf*dyf);
|
||||||
dxf /= len;
|
dxf /= len;
|
||||||
dyf /= len;
|
dyf /= len;
|
||||||
}
|
}
|
||||||
@ -999,7 +1005,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
int curCurveOff = it.next();
|
int curCurveOff = it.next();
|
||||||
|
|
||||||
kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
|
kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
|
||||||
if (kind != 0) {
|
|
||||||
emitLineTo(lp[0], lp[1]);
|
emitLineTo(lp[0], lp[1]);
|
||||||
switch(kind) {
|
switch(kind) {
|
||||||
case 8:
|
case 8:
|
||||||
@ -1013,7 +1018,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
}
|
}
|
||||||
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
||||||
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
||||||
@ -1050,12 +1054,12 @@ final class Stroker implements PathConsumer2D {
|
|||||||
// if these vectors are too small, normalize them, to avoid future
|
// if these vectors are too small, normalize them, to avoid future
|
||||||
// precision problems.
|
// precision problems.
|
||||||
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxs*dxs + dys*dys);
|
float len = (float) sqrt(dxs*dxs + dys*dys);
|
||||||
dxs /= len;
|
dxs /= len;
|
||||||
dys /= len;
|
dys /= len;
|
||||||
}
|
}
|
||||||
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
|
||||||
float len = (float)Math.sqrt(dxf*dxf + dyf*dyf);
|
float len = (float) sqrt(dxf*dxf + dyf*dyf);
|
||||||
dxf /= len;
|
dxf /= len;
|
||||||
dyf /= len;
|
dyf /= len;
|
||||||
}
|
}
|
||||||
@ -1073,7 +1077,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
int curCurveOff = it.next();
|
int curCurveOff = it.next();
|
||||||
|
|
||||||
kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
|
kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
|
||||||
if (kind != 0) {
|
|
||||||
emitLineTo(lp[0], lp[1]);
|
emitLineTo(lp[0], lp[1]);
|
||||||
switch(kind) {
|
switch(kind) {
|
||||||
case 6:
|
case 6:
|
||||||
@ -1087,7 +1090,6 @@ final class Stroker implements PathConsumer2D {
|
|||||||
}
|
}
|
||||||
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
emitLineTo(rp[kind - 2], rp[kind - 1], true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
|
||||||
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
/* avoid extra function call in case we use fread (TVT) */
|
/* avoid extra function call in case we use fread (TVT) */
|
||||||
#define READ(_gif,_buf,_len) \
|
#define READ(_gif,_buf,_len) \
|
||||||
(((GifFilePrivateType*)_gif->Private)->Read ? \
|
(((GifFilePrivateType*)_gif->Private)->Read ? \
|
||||||
((GifFilePrivateType*)_gif->Private)->Read(_gif,_buf,_len) : \
|
(size_t)((GifFilePrivateType*)_gif->Private)->Read(_gif,_buf,_len) : \
|
||||||
fread(_buf,1,_len,((GifFilePrivateType*)_gif->Private)->File))
|
fread(_buf,1,_len,((GifFilePrivateType*)_gif->Private)->File))
|
||||||
|
|
||||||
static int DGifGetWord(GifFileType *GifFile, int *Word);
|
static int DGifGetWord(GifFileType *GifFile, int *Word);
|
||||||
|
@ -55,6 +55,7 @@ typedef Int32 hsFixed;
|
|||||||
typedef Int32 hsFract;
|
typedef Int32 hsFract;
|
||||||
typedef UInt32 Bool32;
|
typedef UInt32 Bool32;
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
#ifndef false
|
#ifndef false
|
||||||
#define false 0
|
#define false 0
|
||||||
#endif
|
#endif
|
||||||
@ -62,6 +63,7 @@ typedef UInt32 Bool32;
|
|||||||
#ifndef true
|
#ifndef true
|
||||||
#define true 1
|
#define true 1
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define kPosInfinity32 (0x7fffffff)
|
#define kPosInfinity32 (0x7fffffff)
|
||||||
#define kNegInfinity32 (0x80000000)
|
#define kNegInfinity32 (0x80000000)
|
||||||
|
@ -162,7 +162,7 @@ static le_int32 decompose(LEUnicode syllable, LEUnicode &lead, LEUnicode &vowel,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lead = LJMO_FIRST + (sIndex / HSYL_LVCNT);
|
lead = (LEUnicode)(LJMO_FIRST + (sIndex / HSYL_LVCNT));
|
||||||
vowel = VJMO_FIRST + (sIndex % HSYL_LVCNT) / TJMO_COUNT;
|
vowel = VJMO_FIRST + (sIndex % HSYL_LVCNT) / TJMO_COUNT;
|
||||||
trail = TJMO_FIRST + (sIndex % TJMO_COUNT);
|
trail = TJMO_FIRST + (sIndex % TJMO_COUNT);
|
||||||
|
|
||||||
|
@ -65,9 +65,9 @@ void MPreFixups::add(le_int32 baseIndex, le_int32 mpreIndex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& success)
|
void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& leSuccess)
|
||||||
{
|
{
|
||||||
if (LE_FAILURE(success)) {
|
if (LE_FAILURE(leSuccess)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,9 +256,9 @@ public class FcFontConfiguration extends FontConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (installedFallbackFontFiles != null) {
|
if (installedFallbackFontFiles != null) {
|
||||||
System.arraycopy(fileNames, index,
|
System.arraycopy(installedFallbackFontFiles, 0,
|
||||||
installedFallbackFontFiles,
|
fileNames, fcFonts.length,
|
||||||
0, installedFallbackFontFiles.length);
|
installedFallbackFontFiles.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
result[fontIndex * NUM_STYLES + styleIndex]
|
result[fontIndex * NUM_STYLES + styleIndex]
|
||||||
|
@ -1107,7 +1107,8 @@ Java_sun_font_FontConfigManager_getFontConfig
|
|||||||
arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
|
arrlen = (*env)->GetArrayLength(env, fcCompFontArray);
|
||||||
for (i=0; i<arrlen; i++) {
|
for (i=0; i<arrlen; i++) {
|
||||||
FcFontSet* fontset;
|
FcFontSet* fontset;
|
||||||
int fn, j, fontCount, nfonts, minGlyphs;
|
int fn, j, fontCount, nfonts;
|
||||||
|
unsigned int minGlyphs;
|
||||||
FcChar8 **family, **styleStr, **fullname, **file;
|
FcChar8 **family, **styleStr, **fullname, **file;
|
||||||
jarray fcFontArr;
|
jarray fcFontArr;
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ static int CALLBACK EnumFontFacesInFamilyProcW(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fullname = (*env)->NewString(env, lpelfe->elfFullName,
|
fullname = (*env)->NewString(env, lpelfe->elfFullName,
|
||||||
wcslen((LPWSTR)lpelfe->elfFullName));
|
(jsize)wcslen((LPWSTR)lpelfe->elfFullName));
|
||||||
fullnameLC = (*env)->CallObjectMethod(env, fullname,
|
fullnameLC = (*env)->CallObjectMethod(env, fullname,
|
||||||
fmi->toLowerCaseMID, fmi->locale);
|
fmi->toLowerCaseMID, fmi->locale);
|
||||||
(*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname);
|
(*env)->CallBooleanMethod(env, fmi->list, fmi->addMID, fullname);
|
||||||
@ -314,7 +314,7 @@ static int CALLBACK EnumFamilyNamesW(
|
|||||||
GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam;
|
GdiFontMapInfo *fmi = (GdiFontMapInfo*)lParam;
|
||||||
JNIEnv *env = fmi->env;
|
JNIEnv *env = fmi->env;
|
||||||
jstring familyLC;
|
jstring familyLC;
|
||||||
int slen;
|
size_t slen;
|
||||||
LOGFONTW lfw;
|
LOGFONTW lfw;
|
||||||
|
|
||||||
/* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */
|
/* Both Vista and XP return DEVICE_FONTTYPE for OTF fonts */
|
||||||
@ -336,7 +336,7 @@ static int CALLBACK EnumFamilyNamesW(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
slen = wcslen(lpelfe->elfLogFont.lfFaceName);
|
slen = wcslen(lpelfe->elfLogFont.lfFaceName);
|
||||||
fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, slen);
|
fmi->family = (*env)->NewString(env,lpelfe->elfLogFont.lfFaceName, (jsize)slen);
|
||||||
familyLC = (*env)->CallObjectMethod(env, fmi->family,
|
familyLC = (*env)->CallObjectMethod(env, fmi->family,
|
||||||
fmi->toLowerCaseMID, fmi->locale);
|
fmi->toLowerCaseMID, fmi->locale);
|
||||||
/* check if already seen this family with a different charset */
|
/* check if already seen this family with a different charset */
|
||||||
@ -386,10 +386,10 @@ static int CALLBACK EnumFamilyNamesW(
|
|||||||
static BOOL RegistryToBaseTTNameA(LPSTR name) {
|
static BOOL RegistryToBaseTTNameA(LPSTR name) {
|
||||||
static const char TTSUFFIX[] = " (TrueType)";
|
static const char TTSUFFIX[] = " (TrueType)";
|
||||||
static const char OTSUFFIX[] = " (OpenType)";
|
static const char OTSUFFIX[] = " (OpenType)";
|
||||||
int TTSLEN = strlen(TTSUFFIX);
|
size_t TTSLEN = strlen(TTSUFFIX);
|
||||||
char *suffix;
|
char *suffix;
|
||||||
|
|
||||||
int len = strlen(name);
|
size_t len = strlen(name);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -412,10 +412,10 @@ static BOOL RegistryToBaseTTNameA(LPSTR name) {
|
|||||||
static BOOL RegistryToBaseTTNameW(LPWSTR name) {
|
static BOOL RegistryToBaseTTNameW(LPWSTR name) {
|
||||||
static const wchar_t TTSUFFIX[] = L" (TrueType)";
|
static const wchar_t TTSUFFIX[] = L" (TrueType)";
|
||||||
static const wchar_t OTSUFFIX[] = L" (OpenType)";
|
static const wchar_t OTSUFFIX[] = L" (OpenType)";
|
||||||
int TTSLEN = wcslen(TTSUFFIX);
|
size_t TTSLEN = wcslen(TTSUFFIX);
|
||||||
wchar_t *suffix;
|
wchar_t *suffix;
|
||||||
|
|
||||||
int len = wcslen(name);
|
size_t len = wcslen(name);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -439,7 +439,7 @@ static void registerFontA(GdiFontMapInfo *fmi, jobject fontToFileMap,
|
|||||||
LPSTR ptr1, ptr2;
|
LPSTR ptr1, ptr2;
|
||||||
jstring fontStr;
|
jstring fontStr;
|
||||||
JNIEnv *env = fmi->env;
|
JNIEnv *env = fmi->env;
|
||||||
int dslen = strlen(data);
|
size_t dslen = strlen(data);
|
||||||
jstring fileStr = JNU_NewStringPlatform(env, data);
|
jstring fileStr = JNU_NewStringPlatform(env, data);
|
||||||
|
|
||||||
/* TTC or ttc means it may be a collection. Need to parse out
|
/* TTC or ttc means it may be a collection. Need to parse out
|
||||||
@ -488,8 +488,8 @@ static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap,
|
|||||||
wchar_t *ptr1, *ptr2;
|
wchar_t *ptr1, *ptr2;
|
||||||
jstring fontStr;
|
jstring fontStr;
|
||||||
JNIEnv *env = fmi->env;
|
JNIEnv *env = fmi->env;
|
||||||
int dslen = wcslen(data);
|
size_t dslen = wcslen(data);
|
||||||
jstring fileStr = (*env)->NewString(env, data, dslen);
|
jstring fileStr = (*env)->NewString(env, data, (jsize)dslen);
|
||||||
|
|
||||||
/* TTC or ttc means it may be a collection. Need to parse out
|
/* TTC or ttc means it may be a collection. Need to parse out
|
||||||
* multiple font face names separated by " & "
|
* multiple font face names separated by " & "
|
||||||
@ -510,7 +510,7 @@ static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap,
|
|||||||
while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) {
|
while ((ptr2 = wcsstr(ptr1, L" & ")) != NULL) {
|
||||||
ptr1 = ptr2+3;
|
ptr1 = ptr2+3;
|
||||||
}
|
}
|
||||||
fontStr = (*env)->NewString(env, ptr1, wcslen(ptr1));
|
fontStr = (*env)->NewString(env, ptr1, (jsize)wcslen(ptr1));
|
||||||
fontStr = (*env)->CallObjectMethod(env, fontStr,
|
fontStr = (*env)->CallObjectMethod(env, fontStr,
|
||||||
fmi->toLowerCaseMID,
|
fmi->toLowerCaseMID,
|
||||||
fmi->locale);
|
fmi->locale);
|
||||||
@ -524,7 +524,7 @@ static void registerFontW(GdiFontMapInfo *fmi, jobject fontToFileMap,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fontStr = (*env)->NewString(env, name, wcslen(name));
|
fontStr = (*env)->NewString(env, name, (jsize)wcslen(name));
|
||||||
fontStr = (*env)->CallObjectMethod(env, fontStr,
|
fontStr = (*env)->CallObjectMethod(env, fontStr,
|
||||||
fmi->toLowerCaseMID, fmi->locale);
|
fmi->toLowerCaseMID, fmi->locale);
|
||||||
(*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID,
|
(*env)->CallObjectMethod(env, fontToFileMap, fmi->putMID,
|
||||||
|
@ -0,0 +1,361 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
@test
|
||||||
|
@bug 5089429 6982632
|
||||||
|
@summary Checks that we don't crash if rendering operations and state
|
||||||
|
changes are performed on a graphics context from different threads.
|
||||||
|
|
||||||
|
@author Dmitri.Trembovetski@sun.com area=Graphics
|
||||||
|
@run main MTGraphicsAccessTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.awt.geom.*;
|
||||||
|
|
||||||
|
public class MTGraphicsAccessTest {
|
||||||
|
|
||||||
|
// in seconds
|
||||||
|
static final long STANDALONE_RUN_TIME = 20;
|
||||||
|
static final long JTREG_RUN_TIME = 7;
|
||||||
|
|
||||||
|
static boolean standaloneMode;
|
||||||
|
static boolean allowExceptions = true;
|
||||||
|
static long testRunTime;
|
||||||
|
|
||||||
|
volatile boolean done;
|
||||||
|
volatile int stillRunning;
|
||||||
|
volatile int numexceptions;
|
||||||
|
|
||||||
|
Graphics2D sharedGraphics;
|
||||||
|
BufferedImage sharedBI =
|
||||||
|
new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
|
static final Paint colors[] = {
|
||||||
|
Color.red,
|
||||||
|
new Color(0x7f, 0xff, 0x00, 0x7f),
|
||||||
|
new GradientPaint(0, 0, Color.red,
|
||||||
|
50, 50, new Color(0x7f, 0xff, 0x00, 0x7f)),
|
||||||
|
};
|
||||||
|
static final Font fonts[] = {
|
||||||
|
new Font("Dialog", Font.PLAIN, 12),
|
||||||
|
new Font("Dialog", Font.BOLD, 16),
|
||||||
|
new Font("Dialog", Font.ITALIC, 18),
|
||||||
|
};
|
||||||
|
static final AlphaComposite comps[] = {
|
||||||
|
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f),
|
||||||
|
AlphaComposite.Src,
|
||||||
|
AlphaComposite.Xor,
|
||||||
|
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f),
|
||||||
|
null,
|
||||||
|
};
|
||||||
|
static final Stroke strokes[] = {
|
||||||
|
new BasicStroke(),
|
||||||
|
new BasicStroke(0.0f),
|
||||||
|
new BasicStroke(2.0f),
|
||||||
|
new BasicStroke(2.0f, BasicStroke.CAP_ROUND,
|
||||||
|
BasicStroke.JOIN_BEVEL),
|
||||||
|
new BasicStroke(5.0f, BasicStroke.CAP_SQUARE,
|
||||||
|
BasicStroke.JOIN_ROUND),
|
||||||
|
new BasicStroke(0.0f, BasicStroke.CAP_ROUND,
|
||||||
|
BasicStroke.JOIN_ROUND, 0,
|
||||||
|
new float[]{0,6,0,6}, 0),
|
||||||
|
};
|
||||||
|
static final AffineTransform transforms[] = {
|
||||||
|
new AffineTransform(),
|
||||||
|
AffineTransform.getRotateInstance(10.0),
|
||||||
|
AffineTransform.getShearInstance(10.0, 4.0),
|
||||||
|
AffineTransform.getScaleInstance(1.1, 1.2),
|
||||||
|
AffineTransform.getScaleInstance(3.0, 2.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
public MTGraphicsAccessTest() {
|
||||||
|
BufferedImage bi =
|
||||||
|
new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
|
||||||
|
sharedGraphics = (Graphics2D)bi.getGraphics();
|
||||||
|
|
||||||
|
done = false;
|
||||||
|
numexceptions = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < (standaloneMode ? stateChangers.length : 3); i++) {
|
||||||
|
(new TesterThread(stateChangers[i])).start();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < (standaloneMode ? renderTests.length : 5); i++) {
|
||||||
|
(new TesterThread(renderTests[i])).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
mysleep(testRunTime);
|
||||||
|
done = true;
|
||||||
|
while (stillRunning > 0) { mysleep(500); }
|
||||||
|
|
||||||
|
if (numexceptions == 0) {
|
||||||
|
System.err.println("Test passed");
|
||||||
|
} else if (!allowExceptions) {
|
||||||
|
throw new RuntimeException("Test failed with "+
|
||||||
|
numexceptions+" exceptions");
|
||||||
|
} else {
|
||||||
|
System.err.println("Test finished with "+
|
||||||
|
numexceptions+" exceptions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mysleep(long time) {
|
||||||
|
try {
|
||||||
|
// add +/-5ms variance to increase randomness
|
||||||
|
Thread.sleep(time + (long)(5 - Math.random()*10));
|
||||||
|
} catch (InterruptedException e) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void usage(String message) {
|
||||||
|
if (message != null) {
|
||||||
|
System.err.println(message);
|
||||||
|
}
|
||||||
|
System.err.println("Usage: MTGraphicsAccessTest [-full] "+
|
||||||
|
"[-time N/forever] [-help]");
|
||||||
|
System.err.println(" -full: run full suite of tests "+
|
||||||
|
"(default: limited number of tests is run)");
|
||||||
|
System.err.println(" -time N: test duration in seconds/forever"+
|
||||||
|
" (default: "+JTREG_RUN_TIME+"s for the short suite, "+
|
||||||
|
STANDALONE_RUN_TIME+"s for the full suite)");
|
||||||
|
System.err.println(" -help: print this help page");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
boolean testRunSet = false;
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
if ("-full".equals(args[i])) {
|
||||||
|
standaloneMode = true;
|
||||||
|
System.err.println("Running complete list of tests");
|
||||||
|
} else if ("-noexc".equals(args[i])) {
|
||||||
|
allowExceptions = false;
|
||||||
|
} else if ("-time".equals(args[i])) {
|
||||||
|
try {
|
||||||
|
String time = args[++i];
|
||||||
|
if ("forever".equals(time)) {
|
||||||
|
testRunTime = (Long.MAX_VALUE - 20)/1000;
|
||||||
|
} else {
|
||||||
|
testRunTime = 1000*Integer.parseInt(time);
|
||||||
|
}
|
||||||
|
testRunSet = true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
usage("Can't parse number of seconds: " + args[i]);
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||||
|
usage("Missing the 'seconds' argument for -time parameter");
|
||||||
|
}
|
||||||
|
} else if ("-help".equals(args[i])) {
|
||||||
|
usage(null);
|
||||||
|
} else {
|
||||||
|
usage("Unknown argument:" + args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testRunSet) {
|
||||||
|
testRunTime = 1000 *
|
||||||
|
(standaloneMode ? STANDALONE_RUN_TIME : JTREG_RUN_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println("Approximate test run time: "+
|
||||||
|
testRunTime/1000+" seconds");
|
||||||
|
|
||||||
|
new MTGraphicsAccessTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TesterThread extends Thread {
|
||||||
|
Runnable testRunnable;
|
||||||
|
|
||||||
|
public TesterThread(Runnable testRunnable) {
|
||||||
|
stillRunning++;
|
||||||
|
this.testRunnable = testRunnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while (!done) {
|
||||||
|
try {
|
||||||
|
testRunnable.run();
|
||||||
|
yield();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
numexceptions++;
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
stillRunning--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Runnable stateChangers[] = {
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setClip(10, 10, 30, 30);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setClip(10, 10, 30, 30);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
int c = 0;
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setPaint(colors[c++ % colors.length]);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
boolean AA = false;
|
||||||
|
public void run() {
|
||||||
|
if (AA) {
|
||||||
|
sharedGraphics.setRenderingHint(
|
||||||
|
RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
} else {
|
||||||
|
sharedGraphics.setRenderingHint(
|
||||||
|
RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_OFF);
|
||||||
|
}
|
||||||
|
AA = !AA;
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
int t = 0;
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setTransform(
|
||||||
|
transforms[t++ % transforms.length]);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
int c = 0;
|
||||||
|
public void run() {
|
||||||
|
AlphaComposite comp = comps[c++ % comps.length];
|
||||||
|
if (comp == null) {
|
||||||
|
sharedGraphics.setXORMode(Color.green);
|
||||||
|
} else {
|
||||||
|
sharedGraphics.setComposite(comp);
|
||||||
|
}
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
int s = 0;
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setStroke(strokes[s++ % strokes.length]);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
int f = 0;
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.setFont(fonts[f++ % fonts.length]);
|
||||||
|
mysleep(10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
final Runnable renderTests[] = {
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawLine(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawLine(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawRect(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.fillRect(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawString("Stuff", 10, 10);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.draw3DRect(10, 10, 30, 30, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawImage(sharedBI, 10, 10, null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.fill3DRect(10, 10, 30, 30, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// REMIND: copyArea doesn't work when transform is set..
|
||||||
|
// new Runnable() {
|
||||||
|
// public void run() {
|
||||||
|
// sharedGraphics.copyArea(10, 10, 30, 30, 20, 20);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawRoundRect(10, 10, 30, 30, 20, 20);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.fillRoundRect(10, 10, 30, 30, 20, 20);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawArc(10, 10, 30, 30, 0, 90);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.fillArc(10, 10, 30, 30, 0, 90);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.drawOval(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
sharedGraphics.fillOval(10, 10, 30, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @bug 7027667, 7023591
|
* @bug 7027667 7023591 7037091
|
||||||
*
|
*
|
||||||
* @summary Verifies that aa clipped rectangles are drawn, not filled.
|
* @summary Verifies that aa clipped rectangles are drawn, not filled.
|
||||||
*
|
*
|
||||||
|
58
jdk/test/sun/java2d/pisces/Test7036754.java
Normal file
58
jdk/test/sun/java2d/pisces/Test7036754.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2011, 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 7036754
|
||||||
|
*
|
||||||
|
* @summary Verifies that there are no non-finite numbers when stroking
|
||||||
|
* certain quadratic curves.
|
||||||
|
*
|
||||||
|
* @author Jim Graham
|
||||||
|
* @run main Test7036754
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.*;
|
||||||
|
|
||||||
|
public class Test7036754 {
|
||||||
|
public static void main(String argv[]) {
|
||||||
|
Shape s = new QuadCurve2D.Float(839.24677f, 508.97888f,
|
||||||
|
839.2953f, 508.97122f,
|
||||||
|
839.3438f, 508.96353f);
|
||||||
|
s = new BasicStroke(10f).createStrokedShape(s);
|
||||||
|
float nsegs[] = {2, 2, 4, 6, 0};
|
||||||
|
float coords[] = new float[6];
|
||||||
|
PathIterator pi = s.getPathIterator(null);
|
||||||
|
while (!pi.isDone()) {
|
||||||
|
int type = pi.currentSegment(coords);
|
||||||
|
for (int i = 0; i < nsegs[type]; i++) {
|
||||||
|
float c = coords[i];
|
||||||
|
if (Float.isNaN(c) || Float.isInfinite(c)) {
|
||||||
|
throw new RuntimeException("bad value in stroke");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pi.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user