* @param shape the shape to render
* @return {@code true} if HSLF implementation is used
*/
- protected static boolean isHSLF(Shape<?,?> shape) {
- return shape.getClass().getCanonicalName().toLowerCase(Locale.ROOT).contains("hslf");
+ static boolean isHSLF(Object shape) {
+ return shape.getClass().getName().toLowerCase(Locale.ROOT).contains("hslf");
}
/**
return;
}
- PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
+ final PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
final boolean isHSLF = isHSLF(shape);
- AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
- if (tx == null) {
- tx = new AffineTransform();
- }
- // we saw one document failing here, probably the format is slightly broken, but
- // maybe better to try to handle it more gracefully
- java.awt.Shape transformedShape = tx.createTransformedShape(ps.getAnchor());
- if(transformedShape == null) {
- return;
+ final Rectangle2D anchor = getAnchor(graphics, ps);
+
+ if (shape.getShapeName().startsWith("rotate")) {
+ System.out.println(String.format("%s x: %.3f y: %.3f cx: %.3f cy: %.3f / x: %.3f y: %.3f cx: %.3f cy: %.3f ",
+ shape.getShapeName(), shape.getAnchor().getX(), shape.getAnchor().getY(),
+ shape.getAnchor().getWidth(), shape.getAnchor().getHeight(),
+ anchor.getX(), anchor.getY(), anchor.getWidth(), anchor.getHeight()
+ ));
}
- final Rectangle2D anchor = transformedShape.getBounds2D();
char cmds[] = isHSLF ? new char[]{ 'h','v','r' } : new char[]{ 'r','h','v' };
for (char ch : cmds) {
double centerX = anchor.getCenterX();
double centerY = anchor.getCenterY();
- // normalize rotation
- rotation %= 360.;
- if (rotation < 0) {
- rotation += 360.;
- }
-
- int quadrant = (((int)rotation+45)/90)%4;
- double scaleX = 1.0, scaleY = 1.0;
-
- // scale to bounding box (bug #53176)
- if (quadrant == 1 || quadrant == 3) {
- // In quadrant 1 and 3, which is basically a shape in a more or less portrait orientation
- // (45-135 degrees and 225-315 degrees), we need to first rotate the shape by a multiple
- // of 90 degrees and then resize the bounding box to its original bbox. After that we can
- // rotate the shape to the exact rotation amount.
- // It's strange that you'll need to rotate the shape back and forth again, but you can
- // think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might
- // be already (differently) scaled, so you can paint the shape in its default orientation
- // and later on, turn it around again to compare it with its original size ...
-
- AffineTransform txs;
- if (isHSLF) {
- txs = new AffineTransform(tx);
- } else {
- // this handling is only based on try and error ... not sure why xslf is handled differently.
- txs = new AffineTransform();
- txs.translate(centerX, centerY);
- txs.rotate(Math.PI/2.); // actually doesn't matter if +/- 90 degrees
- txs.translate(-centerX, -centerY);
- txs.concatenate(tx);
- }
-
- txs.translate(centerX, centerY);
- txs.rotate(Math.PI/2.);
- txs.translate(-centerX, -centerY);
-
- Rectangle2D anchor2 = txs.createTransformedShape(ps.getAnchor()).getBounds2D();
-
- scaleX = safeScale(anchor.getWidth(), anchor2.getWidth());
- scaleY = safeScale(anchor.getHeight(), anchor2.getHeight());
- } else {
- quadrant = 0;
- }
// transformation is applied reversed ...
graphics.translate(centerX, centerY);
- double rot = Math.toRadians(rotation-quadrant*90.);
- if (rot != 0) {
- graphics.rotate(rot);
- }
- graphics.scale(scaleX, scaleY);
- rot = Math.toRadians(quadrant*90.);
- if (rot != 0) {
- graphics.rotate(rot);
- }
+ graphics.rotate(Math.toRadians(rotation));
graphics.translate(-centerX, -centerY);
}
break;
}
public static Rectangle2D getAnchor(Graphics2D graphics, PlaceableShape<?,?> shape) {
- return getAnchor(graphics, shape.getAnchor());
+// return getAnchor(graphics, shape.getAnchor());
+
+ final boolean isHSLF = isHSLF(shape);
+ AffineTransform tx = graphics == null ? null : (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
+ if (tx == null) {
+ tx = new AffineTransform();
+ }
+
+ final double rotation = ((shape.getRotation() % 360.) + 360.) % 360.;
+ final int quadrant = (((int)rotation+45)/90)%4;
+
+ final Rectangle2D normalizedShape;
+
+ // scale to bounding box (bug #53176)
+ if (quadrant == 1 || quadrant == 3) {
+ // In a rotated quadrant 1 (=45-135 degrees) and 3 (=225-315 degrees), which is basically a shape in a
+ // more or less portrait orientation, Powerpoint doesn't use the normal shape anchor,
+ // but rotate it 90 degress and apply the group transformations.
+ // We try to revert that distortion and return the normalized anchor.
+ // It's strange that you'll need to rotate the shape back and forth again, but you can
+ // think of it, as if you paint the shape on a canvas. First you rotate the canvas, which might
+ // be already (differently) scaled, so you can paint the shape in its default orientation
+ // and later on, turn it around again to compare it with its original size ...
+
+
+ final Rectangle2D shapeAnchor = shape.getAnchor();
+ final Rectangle2D anchorO = tx.createTransformedShape(shapeAnchor).getBounds2D();
+
+ final Rectangle2D anchorT;
+ {
+ final double centerX = anchorO.getCenterX();
+ final double centerY = anchorO.getCenterY();
+ final AffineTransform txs2 = new AffineTransform();
+
+ // this handling is only based on try and error ... not sure why h/xslf is handled differently.
+
+ if (!isHSLF) {
+ txs2.translate(centerX, centerY);
+ txs2.quadrantRotate(1);
+ txs2.translate(-centerX, -centerY);
+ txs2.concatenate(tx);
+ }
+
+ txs2.translate(centerX, centerY);
+ txs2.quadrantRotate(3);
+ txs2.translate(-centerX, -centerY);
+
+ if (isHSLF) {
+ txs2.concatenate(tx);
+ }
+
+ anchorT = txs2.createTransformedShape(shapeAnchor).getBounds2D();
+ }
+
+ final double scaleX2 = safeScale(anchorO.getWidth(), anchorT.getWidth());
+ final double scaleY2 = safeScale(anchorO.getHeight(), anchorT.getHeight());
+
+ {
+ double centerX = shapeAnchor.getCenterX();
+ double centerY = shapeAnchor.getCenterY();
+ final AffineTransform txs2 = new AffineTransform();
+ txs2.translate(centerX, centerY);
+ // no need to rotate back and forth, just apply scaling inverted
+ txs2.scale(scaleY2, scaleX2);
+ txs2.translate(-centerX, -centerY);
+
+ normalizedShape = txs2.createTransformedShape(shapeAnchor).getBounds2D();
+ }
+ } else {
+ normalizedShape = shape.getAnchor();
+ }
+
+ if (tx.isIdentity()) {
+ return normalizedShape;
+ }
+
+
+ final java.awt.Shape anc = tx.createTransformedShape(normalizedShape);
+ return (anc != null) ? anc.getBounds2D() : normalizedShape;
}
public static Rectangle2D getAnchor(Graphics2D graphics, Rectangle2D anchor) {