aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/org/apache/poi/ddf/EscherProperties.java30
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawFreeformShape.java36
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawSimpleShape.java8
-rw-r--r--src/java/org/apache/poi/sl/draw/geom/Context.java22
-rw-r--r--src/java/org/apache/poi/sl/usermodel/FreeformShape.java15
-rw-r--r--src/java/org/apache/poi/util/Units.java2
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java33
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java1
-rw-r--r--src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java4
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java395
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java49
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java264
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java23
-rw-r--r--src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java6
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java1
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java2
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java1
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java (renamed from src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java)2
-rw-r--r--test-data/slideshow/customGeo.pptbin0 -> 3333632 bytes
-rw-r--r--test-data/slideshow/customGeo.pptxbin0 -> 1046067 bytes
20 files changed, 529 insertions, 365 deletions
diff --git a/src/java/org/apache/poi/ddf/EscherProperties.java b/src/java/org/apache/poi/ddf/EscherProperties.java
index acff6241c2..482bce95c5 100644
--- a/src/java/org/apache/poi/ddf/EscherProperties.java
+++ b/src/java/org/apache/poi/ddf/EscherProperties.java
@@ -26,6 +26,7 @@ import java.util.Map;
*
* @author Glen Stampoultzis (glens at apache.org)
*/
+@SuppressWarnings("WeakerAccess")
public final class EscherProperties {
// Property constants
@@ -117,6 +118,15 @@ public final class EscherProperties {
public static final short GEOMETRY__ADJUST8VALUE = 334;
public static final short GEOMETRY__ADJUST9VALUE = 335;
public static final short GEOMETRY__ADJUST10VALUE = 336;
+ public static final short GEOMETRY__PCONNECTIONSITES = 337;
+ public static final short GEOMETRY__PCONNECTIONSITESDIR = 338;
+ public static final short GEOMETRY__XLIMO = 339;
+ public static final short GEOMETRY__YLIMO = 340;
+ public static final short GEOMETRY__PADJUSTHANDLES = 341;
+ public static final short GEOMETRY__PGUIDES = 342;
+ public static final short GEOMETRY__PINSCRIBE = 343;
+ public static final short GEOMETRY__CXK = 344;
+ public static final short GEOMETRY__PFRAGMENTS = 345;
public static final short GEOMETRY__SHADOWok = 378;
public static final short GEOMETRY__3DOK = 379;
public static final short GEOMETRY__LINEOK = 380;
@@ -333,6 +343,9 @@ public final class EscherProperties {
private static final Map<Short, EscherPropertyMetaData> properties = initProps();
+ private EscherProperties() {
+ }
+
private static Map<Short, EscherPropertyMetaData> initProps() {
Map<Short, EscherPropertyMetaData> m = new HashMap<>();
addProp(m, TRANSFORM__ROTATION, "transform.rotation");
@@ -423,6 +436,15 @@ public final class EscherProperties {
addProp(m, GEOMETRY__ADJUST8VALUE, "geometry.adjust8value");
addProp(m, GEOMETRY__ADJUST9VALUE, "geometry.adjust9value");
addProp(m, GEOMETRY__ADJUST10VALUE, "geometry.adjust10value");
+ addProp(m, GEOMETRY__PCONNECTIONSITES, "geometry.pConnectionSites");
+ addProp(m, GEOMETRY__PCONNECTIONSITESDIR, "geometry.pConnectionSitesDir");
+ addProp(m, GEOMETRY__XLIMO, "geometry.xLimo");
+ addProp(m, GEOMETRY__YLIMO, "geometry.yLimo");
+ addProp(m, GEOMETRY__PADJUSTHANDLES, "geometry.pAdjustHandles");
+ addProp(m, GEOMETRY__PGUIDES, "geometry.pGuides");
+ addProp(m, GEOMETRY__PINSCRIBE, "geometry.pInscribe");
+ addProp(m, GEOMETRY__CXK, "geometry.cxk");
+ addProp(m, GEOMETRY__PFRAGMENTS, "geometry.pFragments");
addProp(m, GEOMETRY__SHADOWok, "geometry.shadowOK");
addProp(m, GEOMETRY__3DOK, "geometry.3dok");
addProp(m, GEOMETRY__LINEOK, "geometry.lineok");
@@ -641,20 +663,20 @@ public final class EscherProperties {
}
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName) {
- m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName));
+ m.put((short) s, new EscherPropertyMetaData(propName));
}
private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName, byte type) {
- m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName, type));
+ m.put((short) s, new EscherPropertyMetaData(propName, type));
}
public static String getPropertyName(short propertyId) {
- EscherPropertyMetaData o = properties.get(Short.valueOf(propertyId));
+ EscherPropertyMetaData o = properties.get(propertyId);
return o == null ? "unknown" : o.getDescription();
}
public static byte getPropertyType(short propertyId) {
- EscherPropertyMetaData escherPropertyMetaData = properties.get(Short.valueOf(propertyId));
+ EscherPropertyMetaData escherPropertyMetaData = properties.get(propertyId);
return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
}
}
diff --git a/src/java/org/apache/poi/sl/draw/DrawFreeformShape.java b/src/java/org/apache/poi/sl/draw/DrawFreeformShape.java
index 6eb60dfb52..be18f037ab 100644
--- a/src/java/org/apache/poi/sl/draw/DrawFreeformShape.java
+++ b/src/java/org/apache/poi/sl/draw/DrawFreeformShape.java
@@ -17,43 +17,11 @@
package org.apache.poi.sl.draw;
-import java.awt.Graphics2D;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.poi.sl.draw.geom.Outline;
-import org.apache.poi.sl.draw.geom.Path;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.FreeformShape;
+@SuppressWarnings("WeakerAccess")
public class DrawFreeformShape extends DrawAutoShape {
public DrawFreeformShape(FreeformShape<?,?> shape) {
super(shape);
}
-
- protected Collection<Outline> computeOutlines(Graphics2D graphics) {
- List<Outline> lst = new ArrayList<>();
- FreeformShape<?,?> fsh = (FreeformShape<?, ?>) getShape();
- Path2D sh = fsh.getPath();
-
- AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
- if (tx == null) {
- tx = new AffineTransform();
- }
-
- java.awt.Shape canvasShape = tx.createTransformedShape(sh);
-
- FillStyle fs = fsh.getFillStyle();
- StrokeStyle ss = fsh.getStrokeStyle();
- Path path = new Path(fs != null, ss != null);
- lst.add(new Outline(canvasShape, path));
- return lst;
- }
-
- @Override
- protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() {
- return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape;
- }
}
diff --git a/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java b/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
index 7ed1d35da2..35c3aa1207 100644
--- a/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
+++ b/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
@@ -410,14 +410,20 @@ public class DrawSimpleShape extends DrawShape {
}
for (Path p : geom) {
- double w = p.getW(), h = p.getH(), scaleX = Units.toPoints(1), scaleY = scaleX;
+ double w = p.getW(), h = p.getH(), scaleX, scaleY;
if (w == -1) {
w = Units.toEMU(anchor.getWidth());
+ scaleX = Units.toPoints(1);
+ } else if (anchor.getWidth() == 0) {
+ scaleX = 1;
} else {
scaleX = anchor.getWidth() / w;
}
if (h == -1) {
h = Units.toEMU(anchor.getHeight());
+ scaleY = Units.toPoints(1);
+ } else if (anchor.getHeight() == 0) {
+ scaleY = 1;
} else {
scaleY = anchor.getHeight() / h;
}
diff --git a/src/java/org/apache/poi/sl/draw/geom/Context.java b/src/java/org/apache/poi/sl/draw/geom/Context.java
index 31847ceeff..3ed84b3d18 100644
--- a/src/java/org/apache/poi/sl/draw/geom/Context.java
+++ b/src/java/org/apache/poi/sl/draw/geom/Context.java
@@ -22,11 +22,18 @@ package org.apache.poi.sl.draw.geom;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
+import java.util.regex.Pattern;
public class Context {
- final Map<String, Double> _ctx = new HashMap<>();
- final IAdjustableShape _props;
- final Rectangle2D _anchor;
+ private static final Pattern DOUBLE_PATTERN = Pattern.compile(
+ "[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)" +
+ "([eE][+-]?(\\p{Digit}+))?)|(\\.(\\p{Digit}+)([eE][+-]?(\\p{Digit}+))?)|" +
+ "(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))" +
+ "[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");
+
+ private final Map<String, Double> _ctx = new HashMap<>();
+ private final IAdjustableShape _props;
+ private final Rectangle2D _anchor;
public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){
_props = props;
@@ -39,23 +46,22 @@ public class Context {
}
}
- public Rectangle2D getShapeAnchor(){
+ Rectangle2D getShapeAnchor(){
return _anchor;
}
- public Guide getAdjustValue(String name){
+ Guide getAdjustValue(String name){
// ignore HSLF props for now ... the results with default value are usually better - see #59004
return (_props.getClass().getName().contains("hslf")) ? null : _props.getAdjustValue(name);
}
public double getValue(String key){
- if(key.matches("(\\+|-)?\\d+")){
+ if(DOUBLE_PATTERN.matcher(key).matches()){
return Double.parseDouble(key);
}
- Double val = _ctx.get(key);
// BuiltInGuide throws IllegalArgumentException if key is not defined
- return (val != null) ? val : evaluate(BuiltInGuide.valueOf("_"+key));
+ return _ctx.containsKey(key) ? _ctx.get(key) : evaluate(BuiltInGuide.valueOf("_"+key));
}
public double evaluate(Formula fmla){
diff --git a/src/java/org/apache/poi/sl/usermodel/FreeformShape.java b/src/java/org/apache/poi/sl/usermodel/FreeformShape.java
index 2a1580a7da..42ae10ae9a 100644
--- a/src/java/org/apache/poi/sl/usermodel/FreeformShape.java
+++ b/src/java/org/apache/poi/sl/usermodel/FreeformShape.java
@@ -24,16 +24,15 @@ public interface FreeformShape<
P extends TextParagraph<S,P,? extends TextRun>
> extends AutoShape<S,P> {
/**
- * Gets the shape path.
- * <p>
- * The path is translated in the shape's coordinate system, i.e.
- * freeform.getPath().getBounds2D() equals to freeform.getAnchor()
- * (small discrepancies are possible due to rounding errors)
- * </p>
+ * Gets the shape path.<p>
+ *
+ * The path is translated in the shape's coordinate system, i.e.
+ * freeform.getPath2D().getBounds2D() equals to freeform.getAnchor()
+ * (small discrepancies are possible due to rounding errors)
*
* @return the path
*/
- Path2D.Double getPath();
+ Path2D getPath();
/**
* Set the shape path
@@ -41,5 +40,5 @@ public interface FreeformShape<
* @param path shape outline
* @return the number of points written
*/
- int setPath(Path2D.Double path);
+ int setPath(Path2D path);
}
diff --git a/src/java/org/apache/poi/util/Units.java b/src/java/org/apache/poi/util/Units.java
index da0a877cf4..709e3f10cc 100644
--- a/src/java/org/apache/poi/util/Units.java
+++ b/src/java/org/apache/poi/util/Units.java
@@ -127,7 +127,7 @@ public class Units {
points /= MASTER_DPI;
return points;
}
-
+
public static int pointsToMaster(double points) {
points *= MASTER_DPI;
points /= POINT_DPI;
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
index 54acd2b7ba..8c41fe1b93 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
@@ -24,6 +24,12 @@ import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.poi.ooxml.POIXMLTypeLoader;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
@@ -31,6 +37,7 @@ import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.main.CTAdjPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomRect;
@@ -61,7 +68,7 @@ public class XSLFFreeformShape extends XSLFAutoShape
}
@Override
- public int setPath(final Path2D.Double path) {
+ public int setPath(final Path2D path) {
final CTPath2D ctPath = CTPath2D.Factory.newInstance();
final Rectangle2D bounds = path.getBounds2D();
@@ -117,6 +124,30 @@ public class XSLFFreeformShape extends XSLFAutoShape
return numPoints;
}
+ /**
+ * @return definition of the shape geometry
+ */
+ @Override
+ public CustomGeometry getGeometry() {
+ final XmlObject xo = getShapeProperties();
+ if (!(xo instanceof CTShapeProperties)) {
+ return null;
+ }
+
+ XmlOptions xop = new XmlOptions(POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
+ xop.setSaveOuter();
+
+ XMLStreamReader staxReader = ((CTShapeProperties)xo).getCustGeom().newXMLStreamReader(xop);
+ CustomGeometry custGeo = PresetGeometries.convertCustomGeometry(staxReader);
+ try {
+ staxReader.close();
+ } catch (XMLStreamException e) {
+ LOG.log(POILogger.WARN,
+ "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
+ }
+
+ return custGeo;
+ }
@Override
public Path2D.Double getPath() {
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
index 4e54712a77..89f312327b 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
@@ -716,7 +716,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
}
/**
- *
* @return definition of the shape geometry
*/
@Override
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
index 199a9f6286..9a206a48ca 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
@@ -47,7 +47,9 @@ public class TestPPTX2PNG {
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
private static final File basedir = null;
private static final String files =
- "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx";
+ "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
+ "backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
+ "customGeo.pptx, customGeo.ppt";
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
index 910c8a0adc..3a3fa7afb3 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
@@ -17,21 +17,122 @@
package org.apache.poi.hslf.usermodel;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.ddf.EscherProperty;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
+import org.apache.poi.sl.draw.binding.CTPath2D;
+import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
+import org.apache.poi.sl.draw.binding.CTPath2DCubicBezierTo;
+import org.apache.poi.sl.draw.binding.CTPath2DLineTo;
+import org.apache.poi.sl.draw.binding.CTPath2DList;
+import org.apache.poi.sl.draw.binding.CTPath2DMoveTo;
+import org.apache.poi.sl.draw.binding.ObjectFactory;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.ShapeTypes;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
/**
- * Represents an AutoShape.
- * <p>
+ * Represents an AutoShape.<p>
+ *
* AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
* See {@link ShapeTypes}
- * </p>
- *
- * @author Yegor Kozlov
*/
public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,HSLFTextParagraph> {
+ private static final POILogger LOG = POILogFactory.getLogger(HSLFAutoShape.class);
+
+ static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
+ static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
+ static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
+ static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
+ static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
+ // OpenOffice inserts 0xB3 instead of 0xAD.
+ // protected static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
+ static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
+ static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
+
+ private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
+ private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
+
+ enum PathInfo {
+ lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
+ private final int flag;
+ PathInfo(int flag) {
+ this.flag = flag;
+ }
+ public int getFlag() {
+ return flag;
+ }
+ static PathInfo valueOf(int flag) {
+ for (PathInfo v : values()) {
+ if (v.flag == flag) {
+ return v;
+ }
+ }
+ return null;
+ }
+ }
+
+ enum EscapeInfo {
+ EXTENSION(0x0000),
+ ANGLE_ELLIPSE_TO(0x0001),
+ ANGLE_ELLIPSE(0x0002),
+ ARC_TO(0x0003),
+ ARC(0x0004),
+ CLOCKWISE_ARC_TO(0x0005),
+ CLOCKWISE_ARC(0x0006),
+ ELLIPTICAL_QUADRANT_X(0x0007),
+ ELLIPTICAL_QUADRANT_Y(0x0008),
+ QUADRATIC_BEZIER(0x0009),
+ NO_FILL(0X000A),
+ NO_LINE(0X000B),
+ AUTO_LINE(0X000C),
+ AUTO_CURVE(0X000D),
+ CORNER_LINE(0X000E),
+ CORNER_CURVE(0X000F),
+ SMOOTH_LINE(0X0010),
+ SMOOTH_CURVE(0X0011),
+ SYMMETRIC_LINE(0X0012),
+ SYMMETRIC_CURVE(0X0013),
+ FREEFORM(0X0014),
+ FILL_COLOR(0X0015),
+ LINE_COLOR(0X0016);
+
+ private final int flag;
+ EscapeInfo(int flag) {
+ this.flag = flag;
+ }
+ public int getFlag() {
+ return flag;
+ }
+ static EscapeInfo valueOf(int flag) {
+ for (EscapeInfo v : values()) {
+ if (v.flag == flag) {
+ return v;
+ }
+ }
+ return null;
+ }
+ }
protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
super(escherRecord, parent);
@@ -72,13 +173,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
}
/**
- * Gets adjust value which controls smart resizing of the auto-shape.
+ * Gets adjust value which controls smart resizing of the auto-shape.<p>
*
- * <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
- * </p>
*
* @param idx the adjust index in the [0, 9] range
* @return the adjustment value
@@ -90,13 +189,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
}
/**
- * Sets adjust value which controls smart resizing of the auto-shape.
+ * Sets adjust value which controls smart resizing of the auto-shape.<p>
*
- * <p>
* The adjustment values are given in shape coordinates:
* the origin is at the top-left, positive-x is to the right, positive-y is down.
* The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
- * </p>
*
* @param idx the adjust index in the [0, 9] range
* @param val the adjustment value
@@ -106,4 +203,278 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
}
+
+ @Override
+ public CustomGeometry getGeometry() {
+ return getGeometry(new Path2D.Double());
+ }
+
+ CustomGeometry getGeometry(Path2D path2D) {
+ final ObjectFactory of = new ObjectFactory();
+ final CTCustomGeometry2D cusGeo = of.createCTCustomGeometry2D();
+ cusGeo.setAvLst(of.createCTGeomGuideList());
+ cusGeo.setGdLst(of.createCTGeomGuideList());
+ cusGeo.setAhLst(of.createCTAdjustHandleList());
+ cusGeo.setCxnLst(of.createCTConnectionSiteList());
+
+ final AbstractEscherOptRecord opt = getEscherOptRecord();
+
+ EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
+ EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
+
+ // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
+
+ //sanity check
+ if(verticesProp == null) {
+ LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
+ return super.getGeometry();
+ }
+ if(segmentsProp == null) {
+ LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
+ return super.getGeometry();
+ }
+
+ final Iterator<byte[]> vertIter = verticesProp.iterator();
+ final Iterator<byte[]> segIter = segmentsProp.iterator();
+ final int[] xyPoints = new int[2];
+ boolean isClosed = false;
+
+ final CTPath2DList pathLst = of.createCTPath2DList();
+ final CTPath2D pathCT = of.createCTPath2D();
+ final List<Object> moveLst = pathCT.getCloseOrMoveToOrLnTo();
+ pathLst.getPath().add(pathCT);
+ cusGeo.setPathLst(pathLst);
+
+ while (segIter.hasNext()) {
+ byte[] segElem = segIter.next();
+ HSLFFreeformShape.PathInfo pi = getPathInfo(segElem);
+ if (pi == null) {
+ continue;
+ }
+ switch (pi) {
+ case escape: {
+ handleEscapeInfo(pathCT, path2D, segElem, vertIter);
+ break;
+ }
+ case moveTo:
+ if (vertIter.hasNext()) {
+ final CTPath2DMoveTo m = of.createCTPath2DMoveTo();
+ m.setPt(fillPoint(vertIter.next(), xyPoints));
+ moveLst.add(m);
+ path2D.moveTo(xyPoints[0], xyPoints[1]);
+ }
+ break;
+ case lineTo:
+ if (vertIter.hasNext()) {
+ final CTPath2DLineTo m = of.createCTPath2DLineTo();
+ m.setPt(fillPoint(vertIter.next(), xyPoints));
+ moveLst.add(m);
+ path2D.lineTo(xyPoints[0], xyPoints[1]);
+ }
+ break;
+ case curveTo: {
+ final CTPath2DCubicBezierTo m = of.createCTPath2DCubicBezierTo();
+ List<CTAdjPoint2D> mLst = m.getPt();
+
+ int[] pts = new int[6];
+
+ for (int i=0; vertIter.hasNext() && i<3; i++) {
+ mLst.add(fillPoint(vertIter.next(), xyPoints));
+ pts[i*2] = xyPoints[0];
+ pts[i*2+1] = xyPoints[1];
+ if (i == 2) {
+ moveLst.add(m);
+ path2D.curveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+ }
+ }
+ break;
+ }
+ case close:
+ moveLst.add(of.createCTPath2DClose());
+ path2D.closePath();
+ isClosed = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
+ HSLFFreeformShape.ShapePath sp = HSLFFreeformShape.ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
+ if ((sp == HSLFFreeformShape.ShapePath.LINES_CLOSED || sp == HSLFFreeformShape.ShapePath.CURVES_CLOSED) && !isClosed) {
+ moveLst.add(of.createCTPath2DClose());
+ path2D.closePath();
+ }
+
+ EscherSimpleProperty geoLeft = getShapeProp(opt, EscherProperties.GEOMETRY__LEFT);
+ EscherSimpleProperty geoRight = getShapeProp(opt, EscherProperties.GEOMETRY__RIGHT);
+ EscherSimpleProperty geoTop = getShapeProp(opt, EscherProperties.GEOMETRY__TOP);
+ EscherSimpleProperty geoBottom = getShapeProp(opt, EscherProperties.GEOMETRY__BOTTOM);
+
+ final Rectangle2D bounds;
+ if (geoLeft != null && geoRight != null && geoTop != null && geoBottom != null) {
+ bounds = new Rectangle2D.Double();
+ bounds.setFrameFromDiagonal(
+ new Point2D.Double(geoLeft.getPropertyValue(), geoTop.getPropertyValue()),
+ new Point2D.Double(geoRight.getPropertyValue(), geoBottom.getPropertyValue())
+ );
+ } else {
+ bounds = path2D.getBounds2D();
+ }
+
+ pathCT.setW((int)Math.rint(bounds.getWidth()));
+ pathCT.setH((int)Math.rint(bounds.getHeight()));
+
+ return new CustomGeometry(cusGeo);
+ }
+
+ private void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
+ final ObjectFactory of = new ObjectFactory();
+ HSLFFreeformShape.EscapeInfo ei = getEscapeInfo(segElem);
+ switch (ei) {
+ case EXTENSION:
+ break;
+ case ANGLE_ELLIPSE_TO:
+ break;
+ case ANGLE_ELLIPSE:
+ break;
+ case ARC_TO: {
+ // The first two POINT values specify the bounding rectangle of the ellipse.
+ // The second two POINT values specify the radial vectors for the ellipse.
+ // The radial vectors are cast from the center of the bounding rectangle.
+ // The path starts at the POINT where the first radial vector intersects the
+ // bounding rectangle and goes to the POINT where the second radial vector
+ // intersects the bounding rectangle. The drawing direction is always counterclockwise.
+ // If the path has already been started, a line is drawn from the last POINT to
+ // the starting POINT of the arc; otherwise, a new path is started.
+ // The number of arc segments drawn equals the number of segments divided by four.
+
+ int[] r1 = new int[2], r2 = new int[2], start = new int[2], end = new int[2];
+ fillPoint(vertIter.next(), r1);
+ fillPoint(vertIter.next(), r2);
+ fillPoint(vertIter.next(), start);
+ fillPoint(vertIter.next(), end);
+
+ Arc2D arc2D = new Arc2D.Double();
+ Rectangle2D.Double bounds = new Rectangle2D.Double();
+ bounds.setFrameFromDiagonal(xy2p(r1), xy2p(r2));
+ arc2D.setFrame(bounds);
+ arc2D.setAngles(xy2p(start), xy2p(end));
+ path2D.append(arc2D, true);
+
+
+ CTPath2DArcTo arcTo = of.createCTPath2DArcTo();
+ arcTo.setHR(d2s(bounds.getHeight()/2.0));
+ arcTo.setWR(d2s(bounds.getWidth()/2.0));
+
+ arcTo.setStAng(d2s(-arc2D.getAngleStart()*60000.));
+ arcTo.setSwAng(d2s(-arc2D.getAngleExtent()*60000.));
+
+ pathCT.getCloseOrMoveToOrLnTo().add(arcTo);
+
+ break;
+ }
+ case ARC:
+ break;
+ case CLOCKWISE_ARC_TO:
+ break;
+ case CLOCKWISE_ARC:
+ break;
+ case ELLIPTICAL_QUADRANT_X:
+ break;
+ case ELLIPTICAL_QUADRANT_Y:
+ break;
+ case QUADRATIC_BEZIER:
+ break;
+ case NO_FILL:
+ break;
+ case NO_LINE:
+ break;
+ case AUTO_LINE:
+ break;
+ case AUTO_CURVE:
+ break;
+ case CORNER_LINE:
+ break;
+ case CORNER_CURVE:
+ break;
+ case SMOOTH_LINE:
+ break;
+ case SMOOTH_CURVE:
+ break;
+ case SYMMETRIC_LINE:
+ break;
+ case SYMMETRIC_CURVE:
+ break;
+ case FREEFORM:
+ break;
+ case FILL_COLOR:
+ break;
+ case LINE_COLOR:
+ break;
+ default:
+ break;
+ }
+ }
+
+ private static String d2s(double d) {
+ return Integer.toString((int)Math.rint(d));
+ }
+
+ private static Point2D xy2p(int[] xyPoints) {
+ return new Point2D.Double(xyPoints[0],xyPoints[1]);
+ }
+
+ private static HSLFFreeformShape.PathInfo getPathInfo(byte[] elem) {
+ int elemUS = LittleEndian.getUShort(elem, 0);
+ int pathInfo = PATH_INFO.getValue(elemUS);
+ return HSLFFreeformShape.PathInfo.valueOf(pathInfo);
+ }
+
+ private static HSLFFreeformShape.EscapeInfo getEscapeInfo(byte[] elem) {
+ int elemUS = LittleEndian.getUShort(elem, 0);
+ int escInfo = ESCAPE_INFO.getValue(elemUS);
+ return HSLFFreeformShape.EscapeInfo.valueOf(escInfo);
+ }
+
+
+ private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
+ T prop = getEscherProperty(opt, (short)(propId + 0x4000));
+ if (prop == null) {
+ prop = getEscherProperty(opt, propId);
+ }
+ return prop;
+ }
+
+ private CTAdjPoint2D fillPoint(byte[] xyMaster, int[] xyPoints) {
+ if (xyMaster == null || xyPoints == null) {
+ LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
+ return null;
+ }
+ if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
+ LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
+ return null;
+ }
+
+ int x, y;
+ if (xyMaster.length == 4) {
+ x = LittleEndian.getShort(xyMaster, 0);
+ y = LittleEndian.getShort(xyMaster, 2);
+ } else {
+ x = LittleEndian.getInt(xyMaster, 0);
+ y = LittleEndian.getInt(xyMaster, 4);
+ }
+
+ xyPoints[0] = x;
+ xyPoints[1] = y;
+
+ return toPoint(xyPoints);
+ }
+
+ private static CTAdjPoint2D toPoint(int[] xyPoints) {
+ CTAdjPoint2D pt = new CTAdjPoint2D();
+ pt.setX(Integer.toString(xyPoints[0]));
+ pt.setY(Integer.toString(xyPoints[1]));
+ return pt;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
index ee0a2d0731..63885af3f3 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
@@ -49,60 +49,61 @@ import org.apache.poi.util.Units;
/**
* Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
*/
+@SuppressWarnings("WeakerAccess")
public final class HSLFFill {
private static final POILogger LOG = POILogFactory.getLogger(HSLFFill.class);
/**
* Fill with a solid color
*/
- public static final int FILL_SOLID = 0;
+ static final int FILL_SOLID = 0;
/**
* Fill with a pattern (bitmap)
*/
- public static final int FILL_PATTERN = 1;
+ static final int FILL_PATTERN = 1;
/**
* A texture (pattern with its own color map)
*/
- public static final int FILL_TEXTURE = 2;
+ static final int FILL_TEXTURE = 2;
/**
* Center a picture in the shape
*/
- public static final int FILL_PICTURE = 3;
+ static final int FILL_PICTURE = 3;
/**
* Shade from start to end points
*/
- public static final int FILL_SHADE = 4;
+ static final int FILL_SHADE = 4;
/**
* Shade from bounding rectangle to end point
*/
- public static final int FILL_SHADE_CENTER = 5;
+ static final int FILL_SHADE_CENTER = 5;
/**
* Shade from shape outline to end point
*/
- public static final int FILL_SHADE_SHAPE = 6;
+ static final int FILL_SHADE_SHAPE = 6;
/**
* Similar to FILL_SHADE, but the fill angle
* is additionally scaled by the aspect ratio of
* the shape. If shape is square, it is the same as FILL_SHADE
*/
- public static final int FILL_SHADE_SCALE = 7;
+ static final int FILL_SHADE_SCALE = 7;
/**
* shade to title
*/
- public static final int FILL_SHADE_TITLE = 8;
+ static final int FILL_SHADE_TITLE = 8;
/**
* Use the background fill color/pattern
*/
- public static final int FILL_BACKGROUND = 9;
+ static final int FILL_BACKGROUND = 9;
/**
* A bit that specifies whether the RecolorFillAsPicture bit is set.
@@ -214,7 +215,7 @@ public final class HSLFFill {
private HSLFShape shape;
/**
- * Construct a <code>Fill</code> object for a shape.
+ * Construct a {@code Fill} object for a shape.
* Fill information will be read from shape's escher properties.
*
* @param shape the shape this background applies to
@@ -279,7 +280,7 @@ public final class HSLFFill {
@Override
public ColorStyle[] getGradientColors() {
- ColorStyle cs[];
+ ColorStyle[] cs;
if (colorCnt == 0) {
cs = new ColorStyle[2];
cs[0] = wrapColor(getBackgroundColor());
@@ -288,7 +289,7 @@ public final class HSLFFill {
cs = new ColorStyle[colorCnt];
int idx = 0;
// TODO: handle palette colors and alpha(?) value
- for (byte data[] : ep) {
+ for (byte[] data : ep) {
EscherColorRef ecr = new EscherColorRef(data, 0, 4);
cs[idx++] = wrapColor(shape.getColor(ecr));
}
@@ -302,13 +303,13 @@ public final class HSLFFill {
@Override
public float[] getGradientFractions() {
- float frc[];
+ float[] frc;
if (colorCnt == 0) {
frc = new float[]{0, 1};
} else {
frc = new float[colorCnt];
int idx = 0;
- for (byte data[] : ep) {
+ for (byte[] data : ep) {
double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4));
frc[idx++] = (float)pos;
}
@@ -354,7 +355,7 @@ public final class HSLFFill {
/**
* Returns fill type.
- * Must be one of the <code>FILL_*</code> constants defined in this class.
+ * Must be one of the {@code FILL_*} constants defined in this class.
*
* @return type of fill
*/
@@ -364,9 +365,7 @@ public final class HSLFFill {
return prop == null ? FILL_SOLID : prop.getPropertyValue();
}
- /**
- */
- protected void afterInsert(HSLFSheet sh){
+ void afterInsert(HSLFSheet sh){
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
if(p != null) {
@@ -379,7 +378,7 @@ public final class HSLFFill {
}
@SuppressWarnings("resource")
- protected EscherBSERecord getEscherBSERecord(int idx){
+ EscherBSERecord getEscherBSERecord(int idx){
HSLFSheet sheet = shape.getSheet();
if(sheet == null) {
LOG.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet");
@@ -399,7 +398,7 @@ public final class HSLFFill {
/**
* Sets fill type.
- * Must be one of the <code>FILL_*</code> constants defined in this class.
+ * Must be one of the {@code FILL_*} constants defined in this class.
*
* @param type type of the fill
*/
@@ -415,10 +414,10 @@ public final class HSLFFill {
AbstractEscherOptRecord opt = shape.getEscherOptRecord();
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
int propVal = (p == null) ? 0 : p.getPropertyValue();
-
+
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
? null
- : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+ : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY);
}
/**
@@ -462,7 +461,7 @@ public final class HSLFFill {
return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
? null
- : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+ : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY);
}
/**
@@ -480,7 +479,7 @@ public final class HSLFFill {
}
/**
- * <code>PictureData</code> object used in a texture, pattern of picture fill.
+ * {@code PictureData} object used in a texture, pattern of picture fill.
*/
@SuppressWarnings("resource")
public HSLFPictureData getPictureData(){
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
index 0b2d322b63..10eeb7b19c 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
@@ -23,20 +23,16 @@ import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.sl.usermodel.FreeformShape;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@@ -53,79 +49,6 @@ import org.apache.poi.util.Units;
public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformShape<HSLFShape,HSLFTextParagraph> {
private static final POILogger LOG = POILogFactory.getLogger(HSLFFreeformShape.class);
- private static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40};
- private static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC};
- private static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00};
- private static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20};
- private static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD};
- // OpenOffice inserts 0xB3 instead of 0xAD.
- // private static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
- private static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60};
- private static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80};
-
- private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
- // private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
-
- enum PathInfo {
- lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
- private final int flag;
- PathInfo(int flag) {
- this.flag = flag;
- }
- public int getFlag() {
- return flag;
- }
- static PathInfo valueOf(int flag) {
- for (PathInfo v : values()) {
- if (v.flag == flag) {
- return v;
- }
- }
- return null;
- }
- }
-
- enum EscapeInfo {
- EXTENSION(0x0000),
- ANGLE_ELLIPSE_TO(0x0001),
- ANGLE_ELLIPSE(0x0002),
- ARC_TO(0x0003),
- ARC(0x0004),
- CLOCKWISE_ARC_TO(0x0005),
- CLOCKWISE_ARC(0x0006),
- ELLIPTICAL_QUADRANT_X(0x0007),
- ELLIPTICAL_QUADRANT_Y(0x0008),
- QUADRATIC_BEZIER(0x0009),
- NO_FILL(0X000A),
- NO_LINE(0X000B),
- AUTO_LINE(0X000C),
- AUTO_CURVE(0X000D),
- CORNER_LINE(0X000E),
- CORNER_CURVE(0X000F),
- SMOOTH_LINE(0X0010),
- SMOOTH_CURVE(0X0011),
- SYMMETRIC_LINE(0X0012),
- SYMMETRIC_CURVE(0X0013),
- FREEFORM(0X0014),
- FILL_COLOR(0X0015),
- LINE_COLOR(0X0016);
-
- private final int flag;
- EscapeInfo(int flag) {
- this.flag = flag;
- }
- public int getFlag() {
- return flag;
- }
- static EscapeInfo valueOf(int flag) {
- for (EscapeInfo v : values()) {
- if (v.flag == flag) {
- return v;
- }
- }
- return null;
- }
- }
enum ShapePath {
LINES(0),
@@ -182,9 +105,9 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
}
@Override
- public int setPath(Path2D.Double path) {
+ public int setPath(Path2D path) {
Rectangle2D bounds = path.getBounds2D();
- PathIterator it = path.getPathIterator(new AffineTransform());
+ PathIterator it = path.getPathIterator(null);
List<byte[]> segInfo = new ArrayList<>();
List<Point2D.Double> pntInfo = new ArrayList<>();
@@ -275,187 +198,24 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
}
@Override
- public Path2D.Double getPath(){
- AbstractEscherOptRecord opt = getEscherOptRecord();
-
- EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
- EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
-
- // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
- Path2D.Double path = new Path2D.Double();
+ public Path2D getPath(){
+ Path2D path2D = new Path2D.Double();
+ getGeometry(path2D);
- //sanity check
- if(verticesProp == null) {
- LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
- return path;
- }
- if(segmentsProp == null) {
- LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
- return path;
- }
-
- Iterator<byte[]> vertIter = verticesProp.iterator();
- Iterator<byte[]> segIter = segmentsProp.iterator();
- double xyPoints[] = new double[2];
-
- while (vertIter.hasNext() && segIter.hasNext()) {
- byte[] segElem = segIter.next();
- PathInfo pi = getPathInfo(segElem);
- if (pi != null) {
- switch (pi) {
- case escape: {
- // handleEscapeInfo(path, segElem, vertIter);
- break;
- }
- case moveTo: {
- fillPoint(vertIter.next(), xyPoints);
- double x = xyPoints[0];
- double y = xyPoints[1];
- path.moveTo(x, y);
- break;
- }
- case curveTo: {
- fillPoint(vertIter.next(), xyPoints);
- double x1 = xyPoints[0];
- double y1 = xyPoints[1];
- fillPoint(vertIter.next(), xyPoints);
- double x2 = xyPoints[0];
- double y2 = xyPoints[1];
- fillPoint(vertIter.next(), xyPoints);
- double x3 = xyPoints[0];
- double y3 = xyPoints[1];
- path.curveTo(x1, y1, x2, y2, x3, y3);
- break;
- }
- case lineTo:
- if (vertIter.hasNext()) {
- fillPoint(vertIter.next(), xyPoints);
- double x = xyPoints[0];
- double y = xyPoints[1];
- path.lineTo(x, y);
- }
- break;
- case close:
- path.closePath();
- break;
- default:
- break;
- }
- }
- }
-
- EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
- ShapePath sp = ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
- if (sp == ShapePath.LINES_CLOSED || sp == ShapePath.CURVES_CLOSED) {
- path.closePath();
- }
-
+ Rectangle2D bounds = path2D.getBounds2D();
Rectangle2D anchor = getAnchor();
- Rectangle2D bounds = path.getBounds2D();
AffineTransform at = new AffineTransform();
at.translate(anchor.getX(), anchor.getY());
at.scale(
anchor.getWidth()/bounds.getWidth(),
anchor.getHeight()/bounds.getHeight()
);
- return new Path2D.Double(at.createTransformedShape(path));
- }
-
- private void fillPoint(byte xyMaster[], double xyPoints[]) {
- if (xyMaster == null || xyPoints == null) {
- LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
- return;
- }
- if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
- LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
- return;
- }
-
- int x, y;
- if (xyMaster.length == 4) {
- x = LittleEndian.getShort(xyMaster, 0);
- y = LittleEndian.getShort(xyMaster, 2);
- } else {
- x = LittleEndian.getInt(xyMaster, 0);
- y = LittleEndian.getInt(xyMaster, 4);
- }
-
- xyPoints[0] = Units.masterToPoints(x);
- xyPoints[1] = Units.masterToPoints(y);
- }
-
- private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
- T prop = getEscherProperty(opt, (short)(propId + 0x4000));
- if (prop == null) {
- prop = getEscherProperty(opt, propId);
- }
- return prop;
- }
-
-// private void handleEscapeInfo(Path2D path, byte segElem[], Iterator<byte[]> vertIter) {
-// EscapeInfo ei = getEscapeInfo(segElem);
-// switch (ei) {
-// case EXTENSION:
-// break;
-// case ANGLE_ELLIPSE_TO:
-// break;
-// case ANGLE_ELLIPSE:
-// break;
-// case ARC_TO:
-// break;
-// case ARC:
-// break;
-// case CLOCKWISE_ARC_TO:
-// break;
-// case CLOCKWISE_ARC:
-// break;
-// case ELLIPTICAL_QUADRANT_X:
-// break;
-// case ELLIPTICAL_QUADRANT_Y:
-// break;
-// case QUADRATIC_BEZIER:
-// break;
-// case NO_FILL:
-// break;
-// case NO_LINE:
-// break;
-// case AUTO_LINE:
-// break;
-// case AUTO_CURVE:
-// break;
-// case CORNER_LINE:
-// break;
-// case CORNER_CURVE:
-// break;
-// case SMOOTH_LINE:
-// break;
-// case SMOOTH_CURVE:
-// break;
-// case SYMMETRIC_LINE:
-// break;
-// case SYMMETRIC_CURVE:
-// break;
-// case FREEFORM:
-// break;
-// case FILL_COLOR:
-// break;
-// case LINE_COLOR:
-// break;
-// default:
-// break;
-// }
-// }
-
- private static PathInfo getPathInfo(byte elem[]) {
- int elemUS = LittleEndian.getUShort(elem, 0);
- int pathInfo = PATH_INFO.getValue(elemUS);
- return PathInfo.valueOf(pathInfo);
+ path2D.transform(at);
+
+
+ return path2D;
}
-
-// private static EscapeInfo getEscapeInfo(byte elem[]) {
-// int elemUS = LittleEndian.getUShort(elem, 0);
-// int escInfo = ESCAPE_INFO.getValue(elemUS);
-// return EscapeInfo.valueOf(escInfo);
-// }
+
+
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
index 085d617eb8..f1f2c22406 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
@@ -358,17 +358,18 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
_sheet = sheet;
}
- Color getColor(short colorProperty, short opacityProperty, int defaultColor){
- AbstractEscherOptRecord opt = getEscherOptRecord();
- EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
- if(p == null && defaultColor == -1) return null;
-
- int val = (p == null) ? defaultColor : p.getPropertyValue();
-
- EscherColorRef ecr = new EscherColorRef(val);
- Color col = getColor(ecr);
- if (col == null) {
- return null;
+ Color getColor(short colorProperty, short opacityProperty){
+ final AbstractEscherOptRecord opt = getEscherOptRecord();
+ final EscherSimpleProperty colProp = getEscherProperty(opt, colorProperty);
+ final Color col;
+ if (colProp == null) {
+ col = Color.WHITE;
+ } else {
+ EscherColorRef ecr = new EscherColorRef(colProp.getPropertyValue());
+ col = getColor(ecr);
+ if (col == null) {
+ return null;
+ }
}
double alpha = getAlpha(opacityProperty);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
index f9cf74c263..acabc68715 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
@@ -164,7 +164,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
return null;
}
- Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY);
return clr == null ? null : clr;
}
@@ -179,7 +179,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
return null;
}
- Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY);
return clr == null ? null : clr;
}
@@ -385,7 +385,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
* @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
*/
public Color getShadowColor(){
- Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
+ Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY);
return clr == null ? Color.black : clr;
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
index 14301af2ba..26b30ea53c 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
@@ -25,7 +25,6 @@ import org.junit.runners.Suite;
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
- TestBackground.class,
TestFreeform.class,
TestHeadersFooters.class,
TestHyperlink.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
index 91d23664d8..1e3c52ddee 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
@@ -87,7 +87,7 @@ public final class TestFreeform {
public void test54188() {
HSLFFreeformShape p = new HSLFFreeformShape();
- Path2D.Double path = p.getPath();
+ Path2D path = p.getPath();
Path2D.Double emptyPath = new Path2D.Double();
assertEquals(emptyPath.getBounds2D(), path.getBounds2D());
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
index 0354d9b46c..cf8dc7658d 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
@@ -26,6 +26,7 @@ import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestAddingSlides.class,
+ TestBackground.class,
TestBugs.class,
TestCounts.class,
TestMostRecentRecords.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java
index faf61fbc52..2732d16183 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hslf.model;
+package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/test-data/slideshow/customGeo.ppt b/test-data/slideshow/customGeo.ppt
new file mode 100644
index 0000000000..fdb80edcbc
--- /dev/null
+++ b/test-data/slideshow/customGeo.ppt
Binary files differ
diff --git a/test-data/slideshow/customGeo.pptx b/test-data/slideshow/customGeo.pptx
new file mode 100644
index 0000000000..c30e33140b
--- /dev/null
+++ b/test-data/slideshow/customGeo.pptx
Binary files differ