Java Code Examples for java.awt.geom.AffineTransform#transform()

The following examples show how to use java.awt.geom.AffineTransform#transform() . These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source Project: TrakEM2   File: Treeline.java    License: GNU General Public License v3.0 6 votes vote down vote up
/** A list of calibrated radii, one per node in the path.*/
@Override
protected List<Float> calibratedData() {
	final ArrayList<Float> data = new ArrayList<Float>();
	final AffineTransform aff = new AffineTransform(Treeline.this.at);
	final Calibration cal = layer_set.getCalibration();
	aff.preConcatenate(new AffineTransform(cal.pixelWidth, 0, 0, cal.pixelHeight, 0, 0));
	final float[] fp = new float[4];
	for (final Node<Float> nd : super.path) {
		final Float r = nd.getData();
		if (null == r) data.add(null);
		fp[0] = nd.x;
		fp[1] = nd.y;
		fp[2] = nd.x + r.floatValue();
		fp[3] = nd.y;
		aff.transform(fp, 0, fp, 0, 2);
		data.add((float)Math.sqrt(Math.pow(fp[2] - fp[0], 2) + Math.pow(fp[3] - fp[1], 2)));
	}
	return data;
}
 
Example 2
public static Dimension scaleForTransform(AffineTransform at,
                                          Dimension dim)
{
    int w = dim.width;
    int h = dim.height;
    Point2D.Double ptd = new Point2D.Double(0, 0);
    at.transform(ptd, ptd);
    double ox = ptd.getX();
    double oy = ptd.getY();
    if (ox < 0 || ox > w || oy < 0 || oy > h) {
        throw new InternalError("origin outside destination");
    }
    double scalex = scaleForPoint(at, ox, oy, w, h, w, h);
    double scaley = scalex;
    scalex = Math.min(scaleForPoint(at, ox, oy, w, 0, w, h), scalex);
    scaley = Math.min(scaleForPoint(at, ox, oy, 0, h, w, h), scaley);
    if (scalex < 0 || scaley < 0) {
        throw new InternalError("could not fit dims to transform");
    }
    return new Dimension((int) Math.floor(w * scalex),
                         (int) Math.floor(h * scaley));
}
 
Example 3
public static Dimension scaleForTransform(AffineTransform at,
                                          Dimension dim)
{
    int w = dim.width;
    int h = dim.height;
    Point2D.Double ptd = new Point2D.Double(0, 0);
    at.transform(ptd, ptd);
    double ox = ptd.getX();
    double oy = ptd.getY();
    if (ox < 0 || ox > w || oy < 0 || oy > h) {
        throw new InternalError("origin outside destination");
    }
    double scalex = scaleForPoint(at, ox, oy, w, h, w, h);
    double scaley = scalex;
    scalex = Math.min(scaleForPoint(at, ox, oy, w, 0, w, h), scalex);
    scaley = Math.min(scaleForPoint(at, ox, oy, 0, h, w, h), scaley);
    if (scalex < 0 || scaley < 0) {
        throw new InternalError("could not fit dims to transform");
    }
    return new Dimension((int) Math.floor(w * scalex),
                         (int) Math.floor(h * scaley));
}
 
Example 4
public static double scaleForPoint(AffineTransform at,
                                   double xorig, double yorig,
                                   double x, double y,
                                   int w, int h)
{
    Point2D.Double ptd = new Point2D.Double(x, y);
    at.transform(ptd, ptd);
    x = ptd.getX();
    y = ptd.getY();
    double scale = 1.0;
    if (x < 0) {
        scale = Math.min(scale, xorig / (xorig - x));
    } else if (x > w) {
        scale = Math.min(scale, (w - xorig) / (x - xorig));
    }
    if (y < 0) {
        scale = Math.min(scale, yorig / (yorig - y));
    } else if (y > h) {
        scale = Math.min(scale, (h - yorig) / (y - yorig));
    }
    return scale;
}
 
Example 5
/**
 * !!! not used currently, but might be by getPixelbounds?
 */
public void pixellate(FontRenderContext renderFRC, Point2D loc, Point pxResult) {
    if (renderFRC == null) {
        renderFRC = frc;
    }

    // it is a total pain that you have to copy the transform.

    AffineTransform at = renderFRC.getTransform();
    at.transform(loc, loc);
    pxResult.x = (int)loc.getX(); // but must not behave oddly around zero
    pxResult.y = (int)loc.getY();
    loc.setLocation(pxResult.x, pxResult.y);
    try {
        at.inverseTransform(loc, loc);
    }
    catch (NoninvertibleTransformException e) {
        throw new IllegalArgumentException("must be able to invert frc transform");
    }
}
 
Example 6
@Override
public java.awt.PaintContext createContext(final ColorModel COLOR_MODEL,
                                           final Rectangle DEVICE_BOUNDS,
                                           final Rectangle2D USER_BOUNDS,
                                           final AffineTransform TRANSFORM,
                                           final RenderingHints RENDERING_HINTS) {
    final Point2D TRANSFORMED_CENTER = TRANSFORM.transform(CENTER, null);
    final Point2D TRANSFORMED_RADIUS_XY = TRANSFORM.deltaTransform(RADIUS_X_Y, null);
    return new OvalGradientContext(TRANSFORMED_CENTER, TRANSFORMED_RADIUS_XY, FRACTIONS, COLORS);
}
 
Example 7
Source Project: darklaf   File: SwingXUtil.java    License: MIT License 5 votes vote down vote up
public static <T extends JComponent> Point convertPointToParent(final Component source, final JXLayer<T> layer,
                                                                final Point p) {
    if (layer != null && layer.getUI() instanceof TransformUI) {
        TransformUI ui = (TransformUI) layer.getUI();
        Point pos = SwingUtilities.convertPoint(source, p, layer);
        AffineTransform transform = ui.getPreferredTransform(layer.getSize(), layer);
        transform.transform(pos, pos);
        return pos;
    }
    return SwingUtilities.convertPoint(source, p, source.getParent());
}
 
Example 8
protected static Shape transformShape(AffineTransform tx, Shape clip) {
    if (clip == null) {
        return null;
    }

    if (clip instanceof Rectangle2D &&
        (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
    {
        Rectangle2D rect = (Rectangle2D) clip;
        double matrix[] = new double[4];
        matrix[0] = rect.getX();
        matrix[1] = rect.getY();
        matrix[2] = matrix[0] + rect.getWidth();
        matrix[3] = matrix[1] + rect.getHeight();
        tx.transform(matrix, 0, matrix, 0, 2);
        fixRectangleOrientation(matrix, rect);
        return new Rectangle2D.Double(matrix[0], matrix[1],
                                      matrix[2] - matrix[0],
                                      matrix[3] - matrix[1]);
    }

    if (tx.isIdentity()) {
        return cloneShape(clip);
    }

    return tx.createTransformedShape(clip);
}
 
Example 9
protected static Shape transformShape(AffineTransform tx, Shape clip) {
    if (clip == null) {
        return null;
    }

    if (clip instanceof Rectangle2D &&
        (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
    {
        Rectangle2D rect = (Rectangle2D) clip;
        double matrix[] = new double[4];
        matrix[0] = rect.getX();
        matrix[1] = rect.getY();
        matrix[2] = matrix[0] + rect.getWidth();
        matrix[3] = matrix[1] + rect.getHeight();
        tx.transform(matrix, 0, matrix, 0, 2);
        fixRectangleOrientation(matrix, rect);
        return new Rectangle2D.Double(matrix[0], matrix[1],
                                      matrix[2] - matrix[0],
                                      matrix[3] - matrix[1]);
    }

    if (tx.isIdentity()) {
        return cloneShape(clip);
    }

    return tx.createTransformedShape(clip);
}
 
Example 10
Source Project: Bytecoder   File: DrawImage.java    License: Apache License 2.0 5 votes vote down vote up
protected void transformImage(SunGraphics2D sg, Image img,
                              AffineTransform tx, int interpType,
                              int sx1, int sy1, int sx2, int sy2,
                              Color bgColor)
{
    // Transform 3 source corners by tx and analyze them
    // for simplified operations (Copy or Scale).  Using
    // 3 points lets us analyze any kind of transform,
    // even transforms that involve very tiny amounts of
    // rotation or skew to see if they degenerate to a
    // simple scale or copy operation within the allowable
    // error bounds.
    // Note that we use (0,0,w,h) instead of (sx1,sy1,sx2,sy2)
    // because the transform is already translated such that
    // the origin is where sx1, sy1 should go.
    double[] coords = new double[6];
    /* index:  0  1    2  3    4  5  */
    /* coord: (0, 0), (w, h), (0, h) */
    coords[2] = sx2 - sx1;
    coords[3] = coords[5] = sy2 - sy1;
    tx.transform(coords, 0, coords, 0, 3);
    // First test if the X coords of the transformed UL
    // and LL points match and that the Y coords of the
    // transformed LR and LL points also match.
    // If they do then it is a "rectilinear" transform and
    // tryCopyOrScale will make sure it is upright and
    // integer-based.
    if (Math.abs(coords[0] - coords[4]) < MAX_TX_ERROR &&
        Math.abs(coords[3] - coords[5]) < MAX_TX_ERROR &&
        tryCopyOrScale(sg, img, sx1, sy1, sx2, sy2,
                       bgColor, interpType, coords))
    {
        return;
    }

    renderImageXform(sg, img, tx, interpType, sx1, sy1, sx2, sy2, bgColor);
}
 
Example 11
@Override
protected void deviceFillRect(int x, int y, int width, int height,
                              Color color) {
    /*
     * Transform to device coordinates
     */
    AffineTransform deviceTransform = getTransform();

    /* check if rotated or sheared */
    int transformType = deviceTransform.getType();
    boolean usePath =  ((transformType &
                           (AffineTransform.TYPE_GENERAL_ROTATION |
                            AffineTransform.TYPE_GENERAL_TRANSFORM)) != 0);
    if (usePath) {
        fill(new Rectangle2D.Float(x, y, width, height));
        return;
    }

    Point2D.Float tlc_pos = new Point2D.Float(x, y);
    deviceTransform.transform(tlc_pos, tlc_pos);

    Point2D.Float brc_pos = new Point2D.Float(x+width, y+height);
    deviceTransform.transform(brc_pos, brc_pos);

    float deviceWidth = (float) (brc_pos.getX() - tlc_pos.getX());
    float deviceHeight = (float)(brc_pos.getY() - tlc_pos.getY());

    WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();
    wPrinterJob.fillRect((float)tlc_pos.getX(), (float)tlc_pos.getY(),
                         deviceWidth, deviceHeight, color);
}
 
Example 12
private void relayoutNonFixed(NodeWidget w) {
    Point masterPoint = new Point();
    masterPoint.setLocation(w.locX, w.locY);
    double r;
    double theta;
    double thetaStep = Math.PI / 5;
    r = 30;
    theta = 0;
    w.setFixed(false);
    while (true) {
        AffineTransform tr = AffineTransform.getRotateInstance(theta);
        Point2D d2point = tr.transform(new Point2D.Double(0, r), null);
        Point point = new Point((int)d2point.getX() + masterPoint.x, (int)d2point.getY() + masterPoint.y);
        w.locX = point.getX();
        w.locY = point.getY();
        if (isThereFreeSpaceNonFixedSpace(w)) {
            w.setFixed(true);
            return;
        }
        theta = theta + thetaStep;
        if (theta > (Math.PI * 2 - Math.PI / 10)) {
            r = r + 30;
            theta = theta - Math.PI * 2;
            thetaStep = thetaStep * 3 / 4; 
        }
    }
    
}
 
Example 13
public static BufferedImage rotateImage(BufferedImage image, double theta)
{
    int degrees = (int) Math.abs(Math.toDegrees(theta));
    double xCenter = image.getWidth() / 2;
    double yCenter = image.getHeight() / 2;
    AffineTransform rotateTransform = AffineTransform.getRotateInstance(-theta, xCenter, yCenter);

    // Translation adjustments so image still centered after rotate width/height changes
    if (image.getHeight() != image.getWidth() && degrees != 180 && degrees != 0)
    {
        Point2D origin = new Point2D.Double(0.0, 0.0);
        origin = rotateTransform.transform(origin, null);
        double yTranslate = origin.getY();

        Point2D yMax = new Point2D.Double(0, image.getHeight());
        yMax = rotateTransform.transform(yMax, null);
        double xTranslate = yMax.getX();

        AffineTransform translationAdjustment = AffineTransform.getTranslateInstance(-xTranslate, -yTranslate);
        rotateTransform.preConcatenate(translationAdjustment);
    }

    AffineTransformOp op = new AffineTransformOp(rotateTransform, AffineTransformOp.TYPE_BILINEAR);
    // Have to recopy image because of JDK bug #4723021, AffineTransformationOp throwing exception sometimes
    image = copyImage(image, BufferedImage.TYPE_INT_ARGB);

    // Need to create filter dest image ourselves since AffineTransformOp's own dest image creation
    // throws exceptions in some cases.
    Rectangle bounds = op.getBounds2D(image).getBounds();
    BufferedImage finalImage =
            new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(), BufferedImage.TYPE_INT_ARGB);

    return op.filter(image, finalImage);
}
 
Example 14
/**
 * Ensure that the positions array exists and holds position data.
 * If the array is null, this allocates it and sets default positions.
 */
private void initPositions() {
    if (positions == null) {
        setFRCTX();

        positions = new float[glyphs.length * 2 + 2];

        Point2D.Float trackPt = null;
        float track = getTracking(font);
        if (track != 0) {
            track *= font.getSize2D();
            trackPt = new Point2D.Float(track, 0); // advance delta
        }

        Point2D.Float pt = new Point2D.Float(0, 0);
        if (font.isTransformed()) {
            AffineTransform at = font.getTransform();
            at.transform(pt, pt);
            positions[0] = pt.x;
            positions[1] = pt.y;

            if (trackPt != null) {
                at.deltaTransform(trackPt, trackPt);
            }
        }
        for (int i = 0, n = 2; i < glyphs.length; ++i, n += 2) {
            getGlyphStrike(i).addDefaultGlyphAdvance(glyphs[i], pt);
            if (trackPt != null) {
                pt.x += trackPt.x;
                pt.y += trackPt.y;
            }
            positions[n] = pt.x;
            positions[n+1] = pt.y;
        }
    }
}
 
Example 15
/**
 * Draw a line using a pen created using the specified color
 * and current stroke properties.
 */
@Override
protected void deviceDrawLine(int xBegin, int yBegin, int xEnd, int yEnd,
                              Color color) {
    Stroke stroke = getStroke();

    if (stroke instanceof BasicStroke) {
        BasicStroke lineStroke = (BasicStroke) stroke;

        if (lineStroke.getDashArray() != null) {
            draw(new Line2D.Float(xBegin, yBegin, xEnd, yEnd));
            return;
        }

        float lineWidth = lineStroke.getLineWidth();
        Point2D.Float penSize = new Point2D.Float(lineWidth, lineWidth);

        AffineTransform deviceTransform = getTransform();
        deviceTransform.deltaTransform(penSize, penSize);

        float deviceLineWidth = Math.min(Math.abs(penSize.x),
                                         Math.abs(penSize.y));

        Point2D.Float begin_pos = new Point2D.Float(xBegin, yBegin);
        deviceTransform.transform(begin_pos, begin_pos);

        Point2D.Float end_pos = new Point2D.Float(xEnd, yEnd);
        deviceTransform.transform(end_pos, end_pos);

        int endCap = lineStroke.getEndCap();
        int lineJoin = lineStroke.getLineJoin();

        /* check if it's a one-pixel line */
        if ((end_pos.getX() == begin_pos.getX())
            && (end_pos.getY() == begin_pos.getY())) {

            /* endCap other than Round will not print!
             * due to Windows GDI limitation, force it to CAP_ROUND
             */
            endCap = BasicStroke.CAP_ROUND;
        }


        WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();

        /* call native function that creates pen with style */
        if (wPrinterJob.selectStylePen(endCap, lineJoin,
                                       deviceLineWidth, color)) {
            wPrinterJob.moveTo((float)begin_pos.getX(),
                               (float)begin_pos.getY());
            wPrinterJob.lineTo((float)end_pos.getX(),
                               (float)end_pos.getY());
        }
        /* selectStylePen is not supported, must be Win 9X */
        else {

            /* let's see if we can use a a default pen
             *  if it's round end (Windows' default style)
             *  or it's vertical/horizontal
             *  or stroke is too thin.
             */
            double lowerRes = Math.min(wPrinterJob.getXRes(),
                                       wPrinterJob.getYRes());

            if ((endCap == BasicStroke.CAP_ROUND) ||
             (((xBegin == xEnd) || (yBegin == yEnd)) &&
             (deviceLineWidth/lowerRes < MAX_THINLINE_INCHES))) {

                wPrinterJob.selectPen(deviceLineWidth, color);
                wPrinterJob.moveTo((float)begin_pos.getX(),
                                   (float)begin_pos.getY());
                wPrinterJob.lineTo((float)end_pos.getX(),
                                   (float)end_pos.getY());
            }
            else {
                draw(new Line2D.Float(xBegin, yBegin, xEnd, yEnd));
            }
        }
    }
}
 
Example 16
/**
 * This method calculates six m** values and a focusX value that
 * are used by the native fragment shader.  These techniques are
 * based on a whitepaper by Daniel Rice on radial gradient performance
 * (attached to the bug report for 6521533).  One can refer to that
 * document for the complete set of formulas and calculations, but
 * the basic goal is to compose a transform that will convert an
 * (x,y) position in device space into a "u" value that represents
 * the relative distance to the gradient focus point.  The resulting
 * value can be used to look up the appropriate color by linearly
 * interpolating between the two nearest colors in the gradient.
 */
private static void setRadialGradientPaint(RenderQueue rq,
                                           SunGraphics2D sg2d,
                                           RadialGradientPaint paint,
                                           boolean useMask)
{
    boolean linear =
        (paint.getColorSpace() == ColorSpaceType.LINEAR_RGB);
    int cycleMethod = paint.getCycleMethod().ordinal();
    float[] fractions = paint.getFractions();
    Color[] colors = paint.getColors();
    int numStops = colors.length;
    int[] pixels = convertToIntArgbPrePixels(colors, linear);
    Point2D center = paint.getCenterPoint();
    Point2D focus = paint.getFocusPoint();
    float radius = paint.getRadius();

    // save original (untransformed) center and focus points
    double cx = center.getX();
    double cy = center.getY();
    double fx = focus.getX();
    double fy = focus.getY();

    // transform from gradient coords to device coords
    AffineTransform at = paint.getTransform();
    at.preConcatenate(sg2d.transform);
    focus = at.transform(focus, focus);

    // transform unit circle to gradient coords; we start with the
    // unit circle (center=(0,0), focus on positive x-axis, radius=1)
    // and then transform into gradient space
    at.translate(cx, cy);
    at.rotate(fx - cx, fy - cy);
    at.scale(radius, radius);

    // invert to get mapping from device coords to unit circle
    try {
        at.invert();
    } catch (Exception e) {
        at.setToScale(0.0, 0.0);
    }
    focus = at.transform(focus, focus);

    // clamp the focus point so that it does not rest on, or outside
    // of, the circumference of the gradient circle
    fx = Math.min(focus.getX(), 0.99);

    // assert rq.lock.isHeldByCurrentThread();
    rq.ensureCapacity(20 + 28 + (numStops*4*2));
    RenderBuffer buf = rq.getBuffer();
    buf.putInt(SET_RADIAL_GRADIENT_PAINT);
    buf.putInt(useMask ? 1 : 0);
    buf.putInt(linear  ? 1 : 0);
    buf.putInt(numStops);
    buf.putInt(cycleMethod);
    buf.putFloat((float)at.getScaleX());
    buf.putFloat((float)at.getShearX());
    buf.putFloat((float)at.getTranslateX());
    buf.putFloat((float)at.getShearY());
    buf.putFloat((float)at.getScaleY());
    buf.putFloat((float)at.getTranslateY());
    buf.putFloat((float)fx);
    buf.put(fractions);
    buf.put(pixels);
}
 
Example 17
public void adjustPositions(AffineTransform invdtx) {
    invdtx.transform(_positions, 0, _positions, 0, _count);
}
 
Example 18
/**
* Draw the bounding rectangle using transformed coordinates.
*/
@Override
protected void deviceFrameRect(int x, int y, int width, int height,
                                Color color) {

   AffineTransform deviceTransform = getTransform();

   /* check if rotated or sheared */
   int transformType = deviceTransform.getType();
   boolean usePath = ((transformType &
                      (AffineTransform.TYPE_GENERAL_ROTATION |
                       AffineTransform.TYPE_GENERAL_TRANSFORM)) != 0);

   if (usePath) {
       draw(new Rectangle2D.Float(x, y, width, height));
       return;
   }

   Stroke stroke = getStroke();

   if (stroke instanceof BasicStroke) {
       BasicStroke lineStroke = (BasicStroke) stroke;

       int endCap = lineStroke.getEndCap();
       int lineJoin = lineStroke.getLineJoin();


       /* check for default style and try to optimize it by
        * calling the frameRect native function instead of using paths.
        */
       if ((endCap == BasicStroke.CAP_SQUARE) &&
           (lineJoin == BasicStroke.JOIN_MITER) &&
           (lineStroke.getMiterLimit() ==10.0f)) {

           float lineWidth = lineStroke.getLineWidth();
           Point2D.Float penSize = new Point2D.Float(lineWidth,
                                                     lineWidth);

           deviceTransform.deltaTransform(penSize, penSize);
           float deviceLineWidth = Math.min(Math.abs(penSize.x),
                                            Math.abs(penSize.y));

           /* transform upper left coordinate */
           Point2D.Float ul_pos = new Point2D.Float(x, y);
           deviceTransform.transform(ul_pos, ul_pos);

           /* transform lower right coordinate */
           Point2D.Float lr_pos = new Point2D.Float(x + width,
                                                    y + height);
           deviceTransform.transform(lr_pos, lr_pos);

           float w = (float) (lr_pos.getX() - ul_pos.getX());
           float h = (float)(lr_pos.getY() - ul_pos.getY());

           WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();

           /* use selectStylePen, if supported */
           if (wPrinterJob.selectStylePen(endCap, lineJoin,
                                      deviceLineWidth, color) == true)  {
               wPrinterJob.frameRect((float)ul_pos.getX(),
                                     (float)ul_pos.getY(), w, h);
           }
           /* not supported, must be a Win 9x */
           else {

               double lowerRes = Math.min(wPrinterJob.getXRes(),
                                          wPrinterJob.getYRes());

               if ((deviceLineWidth/lowerRes) < MAX_THINLINE_INCHES) {
                   /* use the default pen styles for thin pens. */
                   wPrinterJob.selectPen(deviceLineWidth, color);
                   wPrinterJob.frameRect((float)ul_pos.getX(),
                                         (float)ul_pos.getY(), w, h);
               }
               else {
                   draw(new Rectangle2D.Float(x, y, width, height));
               }
           }
       }
       else {
           draw(new Rectangle2D.Float(x, y, width, height));
       }
   }
}
 
Example 19
/**
 * The strike cache works like this.
 *
 * -Each glyph is thought of as having a transform, usually identity.
 * -Each request for a strike is based on a device transform, either the
 * one in the frc or the rendering transform.
 * -For general info, strikes are held with soft references.
 * -When rendering, strikes must be held with hard references for the
 * duration of the rendering call.  GlyphList will have to hold this
 * info along with the image and position info, but toss the strike info
 * when done.
 * -Build the strike cache as needed.  If the dev transform we want to use
 * has changed from the last time it is built, the cache is flushed by
 * the caller before these methods are called.
 *
 * Use a tx that doesn't include translation components of dst tx.
 */
Object setupGlyphImages(long[] images, float[] positions, AffineTransform tx) {
    int len = sgv.glyphs.length;

    GlyphStrike[] sl = getAllStrikes();
    for (int i = 0; i < len; ++i) {
        GlyphStrike gs = sl[indices[i]];
        int glyphID = sgv.glyphs[i];
        images[i] = gs.strike.getGlyphImagePtr(glyphID);

        gs.getGlyphPosition(glyphID, i*2, sgv.positions, positions);
    }
    tx.transform(positions, 0, positions, 0, len);

    return sl;
}
 
Example 20
/**
* Draw the bounding rectangle using transformed coordinates.
*/
@Override
protected void deviceFrameRect(int x, int y, int width, int height,
                                Color color) {

   AffineTransform deviceTransform = getTransform();

   /* check if rotated or sheared */
   int transformType = deviceTransform.getType();
   boolean usePath = ((transformType &
                      (AffineTransform.TYPE_GENERAL_ROTATION |
                       AffineTransform.TYPE_GENERAL_TRANSFORM)) != 0);

   if (usePath) {
       draw(new Rectangle2D.Float(x, y, width, height));
       return;
   }

   Stroke stroke = getStroke();

   if (stroke instanceof BasicStroke) {
       BasicStroke lineStroke = (BasicStroke) stroke;

       int endCap = lineStroke.getEndCap();
       int lineJoin = lineStroke.getLineJoin();


       /* check for default style and try to optimize it by
        * calling the frameRect native function instead of using paths.
        */
       if ((endCap == BasicStroke.CAP_SQUARE) &&
           (lineJoin == BasicStroke.JOIN_MITER) &&
           (lineStroke.getMiterLimit() ==10.0f)) {

           float lineWidth = lineStroke.getLineWidth();
           Point2D.Float penSize = new Point2D.Float(lineWidth,
                                                     lineWidth);

           deviceTransform.deltaTransform(penSize, penSize);
           float deviceLineWidth = Math.min(Math.abs(penSize.x),
                                            Math.abs(penSize.y));

           /* transform upper left coordinate */
           Point2D.Float ul_pos = new Point2D.Float(x, y);
           deviceTransform.transform(ul_pos, ul_pos);

           /* transform lower right coordinate */
           Point2D.Float lr_pos = new Point2D.Float(x + width,
                                                    y + height);
           deviceTransform.transform(lr_pos, lr_pos);

           float w = (float) (lr_pos.getX() - ul_pos.getX());
           float h = (float)(lr_pos.getY() - ul_pos.getY());

           WPrinterJob wPrinterJob = (WPrinterJob) getPrinterJob();

           /* use selectStylePen, if supported */
           if (wPrinterJob.selectStylePen(endCap, lineJoin,
                                      deviceLineWidth, color) == true)  {
               wPrinterJob.frameRect((float)ul_pos.getX(),
                                     (float)ul_pos.getY(), w, h);
           }
           /* not supported, must be a Win 9x */
           else {

               double lowerRes = Math.min(wPrinterJob.getXRes(),
                                          wPrinterJob.getYRes());

               if ((deviceLineWidth/lowerRes) < MAX_THINLINE_INCHES) {
                   /* use the default pen styles for thin pens. */
                   wPrinterJob.selectPen(deviceLineWidth, color);
                   wPrinterJob.frameRect((float)ul_pos.getX(),
                                         (float)ul_pos.getY(), w, h);
               }
               else {
                   draw(new Rectangle2D.Float(x, y, width, height));
               }
           }
       }
       else {
           draw(new Rectangle2D.Float(x, y, width, height));
       }
   }
}