From: Andreas Beeker Date: Mon, 12 Nov 2018 23:21:18 +0000 (+0000) Subject: #60656 - Support export file that contains emf and render it correctly X-Git-Tag: REL_4_1_0~189^2~5 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=940daf0d923f84a5ea8cc02397060c84d4f90ae7;p=poi.git #60656 - Support export file that contains emf and render it correctly git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1846472 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java index c439fc926f..a428943699 100644 --- a/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java +++ b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java @@ -22,6 +22,8 @@ package org.apache.poi.sl.draw; import java.awt.Font; import java.awt.Graphics2D; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import org.apache.poi.common.usermodel.fonts.FontInfo; import org.apache.poi.sl.draw.Drawable.DrawableHint; @@ -33,6 +35,13 @@ import org.apache.poi.sl.draw.Drawable.DrawableHint; */ public class DrawFontManagerDefault implements DrawFontManager { + protected final Set knownSymbolFonts = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + + public DrawFontManagerDefault() { + knownSymbolFonts.add("Wingdings"); + knownSymbolFonts.add("Symbol"); + } + @Override public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) { return getFontWithFallback(graphics, Drawable.FONT_MAP, fontInfo); @@ -49,25 +58,35 @@ public class DrawFontManagerDefault implements DrawFontManager { public String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, String text) { // TODO: find a real charset mapping solution instead of hard coding for Wingdings - String attStr = text; - if (fontInfo != null && "Wingdings".equalsIgnoreCase(fontInfo.getTypeface())) { - // wingdings doesn't contain high-surrogates, so chars are ok - boolean changed = false; - char chrs[] = attStr.toCharArray(); - for (int i=0; i = : - // m00 (scaleX) = eM11 (Horizontal scaling component) - // m11 (scaleY) = eM22 (Vertical scaling component) - // m01 (shearX) = eM12 (Horizontal proportionality constant) - // m10 (shearY) = eM21 (Vertical proportionality constant) - // m02 (translateX) = eDx (The horizontal translation component, in logical units.) - // m12 (translateY) = eDy (The vertical translation component, in logical units.) + // mapping = - // A 32-bit floating-point value of the transform matrix. - double eM11 = leis.readFloat(); + // m00 (scaleX) = eM11 (Horizontal scaling component) + double m00 = leis.readFloat(); - // A 32-bit floating-point value of the transform matrix. - double eM12 = leis.readFloat(); + // m01 (shearX) = eM12 (Horizontal proportionality constant) + double m01 = leis.readFloat(); - // A 32-bit floating-point value of the transform matrix. - double eM21 = leis.readFloat(); + // m10 (shearY) = eM21 (Vertical proportionality constant) + double m10 = leis.readFloat(); - // A 32-bit floating-point value of the transform matrix. - double eM22 = leis.readFloat(); + // m11 (scaleY) = eM22 (Vertical scaling component) + double m11 = leis.readFloat(); - // A 32-bit floating-point value that contains a horizontal translation component, in logical units. - double eDx = leis.readFloat(); + // m02 (translateX) = eDx (The horizontal translation component, in logical units.) + double m02 = leis.readFloat(); - // A 32-bit floating-point value that contains a vertical translation component, in logical units. - double eDy = leis.readFloat(); + // m12 (translateY) = eDy (The vertical translation component, in logical units.) + double m12 = leis.readFloat(); - xform.setTransform(eM11, eM21, eM12, eM22, eDx, eDy); + xform.setTransform(m00, m10, m01, m11, m02, m12); return 6 * LittleEndian.INT_SIZE; } diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java index ea3eb7754e..a7eb4c8b1c 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java @@ -273,15 +273,15 @@ public class HemfFont extends HwmfFont { // An 8-bit unsigned integer that specifies an italic font if set to 0x01; // otherwise, it MUST be set to 0x00. - italic = (leis.readUByte() == 0x01); + italic = (leis.readUByte() != 0x00); // An 8-bit unsigned integer that specifies an underlined font if set to 0x01; // otherwise, it MUST be set to 0x00. - underline = (leis.readUByte() == 0x01); + underline = (leis.readUByte() != 0x00); // An 8-bit unsigned integer that specifies a strikeout font if set to 0x01; // otherwise, it MUST be set to 0x00. - strikeOut = (leis.readUByte() == 0x01); + strikeOut = (leis.readUByte() != 0x00); // An 8-bit unsigned integer that specifies the set of character glyphs. // It MUST be a value in the WMF CharacterSet enumeration. @@ -441,7 +441,8 @@ public class HemfFont extends HwmfFont { // A 32-bit unsigned integer that MUST be set to the value 0x08007664. int signature = leis.readInt(); - assert (signature == 0x08007664); + // some non-conformant applications don't write the magic code in + // assert (signature == 0x08007664); // A 32-bit unsigned integer that specifies the number of elements in the // Values array. It MUST be in the range 0 to 16, inclusive. diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java index 206b7d3162..55d8c4cc23 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java @@ -27,7 +27,9 @@ import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.function.Function; import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hwmf.draw.HwmfDrawProperties; @@ -443,8 +445,6 @@ public class HemfMisc { protected HwmfBrushStyle brushStyle; protected HwmfHatchStyle hatchStyle; - protected int[] styleEntry; - protected final HwmfBitmapDib bitmap = new HwmfBitmapDib(); @@ -477,7 +477,8 @@ public class HemfMisc { // A 32-bit unsigned integer that specifies the PenStyle. // The value MUST be defined from the PenStyle enumeration table - penStyle = HwmfPenStyle.valueOf((int) leis.readUInt()); + final HemfPenStyle emfPS = HemfPenStyle.valueOf((int) leis.readUInt()); + penStyle = emfPS; // A 32-bit unsigned integer that specifies the width of the line drawn by the pen. // If the pen type in the PenStyle field is PS_GEOMETRIC, this value is the width in logical @@ -517,10 +518,14 @@ public class HemfMisc { // If the pen type in the PenStyle field is PS_GEOMETRIC, the lengths are specified in logical // units; otherwise, the lengths are specified in device units. - styleEntry = new int[numStyleEntries]; + float[] dashPattern = new float[numStyleEntries]; for (int i = 0; i < numStyleEntries; i++) { - styleEntry[i] = (int) leis.readUInt(); + dashPattern[i] = (int) leis.readUInt(); + } + + if (penStyle.getLineDash() == HwmfLineDash.USERSTYLE) { + emfPS.setLineDashes(dashPattern); } size += numStyleEntries * LittleEndianConsts.INT_SIZE; @@ -533,8 +538,11 @@ public class HemfMisc { @Override public String toString() { // TODO: add style entries + bmp - return super.toString().replaceFirst("\\{", - "{ brushStyle: '"+brushStyle+"', hatchStyle: '"+hatchStyle+"', "); + return + "{ brushStyle: '"+brushStyle+"'"+ + ", hatchStyle: '"+hatchStyle+"'"+ + ", dashPattern: "+ Arrays.toString(penStyle.getLineDashes())+ + ", "+super.toString().substring(1); } } @@ -602,7 +610,8 @@ public class HemfMisc { @Override public void draw(HemfGraphics ctx) { - AffineTransform tx = ctx.getInitTransform(); + ctx.updateWindowMapMode(); + AffineTransform tx = ctx.getTransform(); tx.concatenate(xForm); ctx.setTransform(tx); } @@ -649,30 +658,46 @@ public class HemfMisc { return; } + final AffineTransform tx; switch (modifyWorldTransformMode) { - case MWT_IDENTITY: - ctx.setTransform(ctx.getInitTransform()); + case MWT_LEFTMULTIPLY: + tx = ctx.getTransform(); + tx.concatenate(adaptXForm(tx)); break; - case MWT_LEFTMULTIPLY: { - AffineTransform tx = new AffineTransform(xForm); - tx.concatenate(ctx.getTransform()); - ctx.setTransform(tx); + case MWT_RIGHTMULTIPLY: + tx = ctx.getTransform(); + tx.preConcatenate(adaptXForm(tx)); break; - } - case MWT_RIGHTMULTIPLY: { - AffineTransform tx = new AffineTransform(xForm); - tx.preConcatenate(ctx.getTransform()); - ctx.setTransform(tx); + case MWT_IDENTITY: + ctx.updateWindowMapMode(); + tx = ctx.getTransform(); break; - } default: - case MWT_SET: { - AffineTransform tx = ctx.getInitTransform(); - tx.concatenate(xForm); - ctx.setTransform(tx); + case MWT_SET: + ctx.updateWindowMapMode(); + tx = ctx.getTransform(); + tx.concatenate(adaptXForm(tx)); break; - } } + ctx.setTransform(tx); + } + + /** + * adapt xform depending on the base transformation (... experimental ...) + */ + private AffineTransform adaptXForm(AffineTransform other) { + // normalize signed zero + Function nn = (d) -> (d == 0. ? 0. : d); + double yDiff = Math.signum(nn.apply(xForm.getTranslateY())) == Math.signum(nn.apply(other.getTranslateY())) ? 1. : -1.; + double xDiff = Math.signum(nn.apply(xForm.getTranslateX())) == Math.signum(nn.apply(other.getTranslateX())) ? 1. : -1.; + return new AffineTransform( + xForm.getScaleX() == 0 ? 1. : xForm.getScaleX(), + yDiff * xForm.getShearY(), + xDiff * xForm.getShearX(), + xForm.getScaleY() == 0. ? 1. : xForm.getScaleY(), + xForm.getTranslateX(), + xForm.getTranslateY() + ); } @Override diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPenStyle.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPenStyle.java new file mode 100644 index 0000000000..74e9459923 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPenStyle.java @@ -0,0 +1,45 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hemf.record.emf; + +import org.apache.poi.hwmf.record.HwmfPenStyle; + +public class HemfPenStyle extends HwmfPenStyle { + + private float[] dashPattern; + + public static HemfPenStyle valueOf(int flag) { + HemfPenStyle ps = new HemfPenStyle(); + ps.flag = flag; + return ps; + } + + @Override + public float[] getLineDashes() { + return (getLineDash() == HwmfLineDash.USERSTYLE) ? dashPattern : super.getLineDashes(); + } + + public void setLineDashes(float[] dashPattern) { + this.dashPattern = (dashPattern == null) ? null : dashPattern.clone(); + } + + @Override + public HemfPenStyle clone() { + return (HemfPenStyle)super.clone(); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java index 4f11906bbd..4fb2cc22d4 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java @@ -43,6 +43,10 @@ public interface HemfRecord { */ long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException; + /** + * Draws the record, the default redirects to the parent WMF record drawing + * @param ctx the drawing context + */ default void draw(HemfGraphics ctx) { if (this instanceof HwmfRecord) { ((HwmfRecord) this).draw(ctx); diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java index 207c8ee830..dfa68670e1 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java @@ -54,6 +54,8 @@ public class HemfRecordIterator implements Iterator { return null; } + final int readIndex = stream.getReadIndex(); + final long recordId, recordSize; try { recordId = stream.readUInt(); @@ -65,7 +67,7 @@ public class HemfRecordIterator implements Iterator { HemfRecordType type = HemfRecordType.getById(recordId); if (type == null) { - throw new RecordFormatException("Undefined record of type:"+recordId); + throw new RecordFormatException("Undefined record of type: "+recordId+" at "+Integer.toHexString(readIndex)); } final HemfRecord record = type.constructor.get(); diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java index f62155d182..7e785315c0 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java @@ -141,14 +141,12 @@ public class HemfText { dx.add((int) leis.readUInt()); size += LittleEndianConsts.INT_SIZE; } - } else { - // if there are no dx entries, reset the string end - strEnd = (int)recordSize; } if (dx.size() < stringLength) { // invalid dx array dx.clear(); } + strEnd = (int)recordSize; break; } default: diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java index dadb091699..dd189a0f55 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java @@ -31,6 +31,7 @@ import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Dimension2D; +import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; @@ -43,6 +44,7 @@ import java.util.NoSuchElementException; import java.util.TreeMap; import org.apache.commons.codec.Charsets; +import org.apache.poi.common.usermodel.fonts.FontCharset; import org.apache.poi.common.usermodel.fonts.FontInfo; import org.apache.poi.hwmf.record.HwmfBrushStyle; import org.apache.poi.hwmf.record.HwmfFont; @@ -57,6 +59,7 @@ import org.apache.poi.hwmf.record.HwmfText; import org.apache.poi.hwmf.record.HwmfText.WmfExtTextOutOptions; import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFontManager; +import org.apache.poi.sl.draw.DrawFontManagerDefault; import org.apache.poi.util.LocaleUtil; public class HwmfGraphics { @@ -152,7 +155,7 @@ public class HwmfGraphics { int cap = ps.getLineCap().awtFlag; int join = ps.getLineJoin().awtFlag; float miterLimit = (float)getProperties().getPenMiterLimit(); - float dashes[] = ps.getLineDash().dashes; + float dashes[] = ps.getLineDashes(); boolean dashAlt = ps.isAlternateDash(); // This value is not an integer index into the dash pattern array. // Instead, it is a floating-point value that specifies a linear distance. @@ -370,6 +373,17 @@ public class HwmfGraphics { public void drawString(byte[] text, int length, Point2D reference, Dimension2D scale, Rectangle2D clip, WmfExtTextOutOptions opts, List dx, boolean isUnicode) { final HwmfDrawProperties prop = getProperties(); + final AffineTransform at = graphicsCtx.getTransform(); + if (at.getScaleX() == 0. || at.getScaleY() == 0.) { + return; + } + + try { + at.createInverse(); + } catch (NoninvertibleTransformException e) { + return; + } + HwmfFont font = prop.getFont(); if (font == null || text == null || text.length == 0) { return; @@ -390,11 +404,19 @@ public class HwmfGraphics { } String textString = new String(text, charset).substring(0,length).trim(); + if (textString.isEmpty()) { return; } + + DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx); + FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font); + if (fontInfo.getCharset() == FontCharset.SYMBOL) { + textString = DrawFontManagerDefault.mapSymbolChars(textString); + } + AttributedString as = new AttributedString(textString); - addAttributes(as, font); + addAttributes(as, font, fontInfo.getTypeface()); // disabled for the time being, as the results aren't promising /* @@ -473,7 +495,6 @@ public class HwmfGraphics { tx.transform(src, dst); final Shape clipShape = graphicsCtx.getClip(); - final AffineTransform at = graphicsCtx.getTransform(); try { if (clip != null) { graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY()); @@ -503,11 +524,8 @@ public class HwmfGraphics { } } - private void addAttributes(AttributedString as, HwmfFont font) { - DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx); - FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font); - - as.addAttribute(TextAttribute.FAMILY, fontInfo.getTypeface()); + private void addAttributes(AttributedString as, HwmfFont font, String typeface) { + as.addAttribute(TextAttribute.FAMILY, typeface); as.addAttribute(TextAttribute.SIZE, getFontHeight(font)); if (font.isStrikeOut()) { as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON); @@ -669,4 +687,11 @@ public class HwmfGraphics { graphicsCtx.setTransform(at); } } + + /** + * @return the bounding box + */ + public Rectangle2D getBbox() { + return (Rectangle2D)bbox.clone(); + } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java index e353750bd9..3b420e401d 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java @@ -499,8 +499,8 @@ public class HwmfFill { if (bitmap.isValid()) { ctx.drawImage(getImage(), srcBounds, dstBounds); } else if (!dstBounds.isEmpty()) { - BufferedImage bi = new BufferedImage((int)dstBounds.getWidth(), (int)dstBounds.getHeight(), BufferedImage.TYPE_INT_ARGB); - ctx.drawImage(bi, dstBounds, dstBounds); + BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); + ctx.drawImage(bi, new Rectangle2D.Double(0,0,100,100), dstBounds); } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java index 5366b3fb24..776d48a3e7 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java @@ -142,7 +142,7 @@ public class HwmfPenStyle implements Cloneable { private static final BitField SUBSECTION_JOIN = BitFieldFactory.getInstance(0x03000); private static final BitField SUBSECTION_GEOMETRIC = BitFieldFactory.getInstance(0x10000); - private int flag; + protected int flag; public static HwmfPenStyle valueOf(int flag) { HwmfPenStyle ps = new HwmfPenStyle(); @@ -161,7 +161,16 @@ public class HwmfPenStyle implements Cloneable { public HwmfLineDash getLineDash() { return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag)); } - + + /** + * Convienence method which should be used instead of accessing {@link HwmfLineDash#dashes} + * directly, so an subclass can provide user-style dashes + * + * @return the dash pattern + */ + public float[] getLineDashes() { + return getLineDash().dashes; + } /** * The pen sets every other pixel (this style is applicable only for cosmetic pens). diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java index 34c948df02..bbf5b9eb15 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java @@ -18,6 +18,7 @@ package org.apache.poi.hwmf.record; import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString; +import static org.apache.poi.hwmf.record.HwmfDraw.dimToString; import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds; import static org.apache.poi.hwmf.record.HwmfDraw.pointToString; import static org.apache.poi.hwmf.record.HwmfDraw.readBounds; @@ -30,6 +31,7 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; +import org.apache.poi.hwmf.draw.HwmfDrawProperties; import org.apache.poi.hwmf.draw.HwmfGraphics; import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.LittleEndianConsts; @@ -56,8 +58,14 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - ctx.getProperties().setViewportOrg(origin.getX(), origin.getY()); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D old = prop.getViewport(); + double oldX = (old == null ? 0 : old.getX()); + double oldY = (old == null ? 0 : old.getY()); + if (oldX != origin.getX() || oldY != origin.getY()) { + prop.setViewportOrg(origin.getX(), origin.getY()); + ctx.updateWindowMapMode(); + } } @Override @@ -91,13 +99,19 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - ctx.getProperties().setViewportExt(extents.getWidth(), extents.getHeight()); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D old = prop.getViewport(); + double oldW = (old == null ? 0 : old.getWidth()); + double oldH = (old == null ? 0 : old.getHeight()); + if (oldW != extents.getWidth() || oldH != extents.getHeight()) { + prop.setViewportExt(extents.getWidth(), extents.getHeight()); + ctx.updateWindowMapMode(); + } } @Override public String toString() { - return "{ width: "+extents.getWidth()+", height: "+extents.getHeight()+" }"; + return dimToString(extents); } } @@ -121,10 +135,14 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D viewport = ctx.getProperties().getViewport(); - double x = (viewport == null) ? 0 : viewport.getX(); - double y = (viewport == null) ? 0 : viewport.getY(); - ctx.getProperties().setViewportOrg(x+offset.getX(), y+offset.getY()); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D viewport = prop.getViewport(); + if (offset.getX() != 0 || offset.getY() != 0) { + double x = (viewport == null) ? 0 : viewport.getX(); + double y = (viewport == null) ? 0 : viewport.getY(); + prop.setViewportOrg(x + offset.getX(), y + offset.getY()); + ctx.updateWindowMapMode(); + } } @Override @@ -152,8 +170,14 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - ctx.getProperties().setWindowOrg(getX(), getY()); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + final Rectangle2D old = prop.getWindow(); + double oldX = (old == null ? 0 : old.getX()); + double oldY = (old == null ? 0 : old.getY()); + if (oldX != getX() || oldY != getY()) { + prop.setWindowOrg(getX(), getY()); + ctx.updateWindowMapMode(); + } } public double getY() { @@ -195,8 +219,14 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - ctx.getProperties().setWindowExt(size.getWidth(), size.getHeight()); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D old = prop.getWindow(); + double oldW = (old == null ? 0 : old.getWidth()); + double oldH = (old == null ? 0 : old.getHeight()); + if (oldW != size.getWidth() || oldH != size.getHeight()) { + prop.setWindowExt(size.getWidth(), size.getHeight()); + ctx.updateWindowMapMode(); + } } public Dimension2D getSize() { @@ -205,7 +235,7 @@ public class HwmfWindowing { @Override public String toString() { - return "{ width: "+size.getWidth()+", height: "+size.getHeight()+" }"; + return dimToString(size); } } @@ -229,9 +259,12 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D window = ctx.getProperties().getWindow(); - ctx.getProperties().setWindowOrg(window.getX()+offset.getX(), window.getY()+offset.getY()); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D old = prop.getWindow(); + if (offset.getX() != 0 || offset.getY() != 0) { + prop.setWindowOrg(old.getX() + offset.getX(), old.getY() + offset.getY()); + ctx.updateWindowMapMode(); + } } @Override @@ -275,11 +308,14 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D window = ctx.getProperties().getWindow(); - double width = window.getWidth() * scale.getWidth(); - double height = window.getHeight() * scale.getHeight(); - ctx.getProperties().setWindowExt(width, height); - ctx.updateWindowMapMode(); + final HwmfDrawProperties prop = ctx.getProperties(); + Rectangle2D old = prop.getWindow(); + if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) { + double width = old.getWidth() * scale.getWidth(); + double height = old.getHeight() * scale.getHeight(); + ctx.getProperties().setWindowExt(width, height); + ctx.updateWindowMapMode(); + } } @Override @@ -325,13 +361,15 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D viewport = ctx.getProperties().getViewport(); - if (viewport == null) { - viewport = ctx.getProperties().getWindow(); + final HwmfDrawProperties prop = ctx.getProperties(); + final Rectangle2D old = prop.getViewport() == null ? prop.getWindow() : prop.getViewport(); + + if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) { + double width = old.getWidth() * scale.getWidth(); + double height = old.getHeight() * scale.getHeight(); + prop.setViewportExt(width, height); + ctx.updateWindowMapMode(); } - double width = viewport.getWidth() * scale.getWidth(); - double height = viewport.getHeight() * scale.getHeight(); - ctx.getProperties().setViewportExt(width, height); } @Override