diff options
author | Eilidh McAdam <eilidh@lanedo.com> | 2012-09-19 10:01:57 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@suse.cz> | 2012-09-19 14:04:21 +0000 |
commit | 0423a6741fc08a35b123556f9b10219d090ee42a (patch) | |
tree | ad7f4b50ddd951f65cd7a79ba4d39a719982998f /oox | |
parent | 891746ed955b110960113ba0de3a51335af50d66 (diff) |
Import bezier curves from .docx.
A shape element with a path attribute is interpreted as a bezier. We can
support both curve and line commands by using the correct co-ordinate
flags when using the UNO interface (omit control points for lines).
Alternatively, curves may be specified using the to, from, control1 and
control2 attributes of a curve element.
Note that when setting the PolyPolygonBezier property of the xshape, the
shape size and position are set too large somehow. The workaround for
now is manually forcing the pre-calculated shape size and position.
Change-Id: If3563474df357d161a2ed2e7a20856d5aed80a94
Reviewed-on: https://gerrit.libreoffice.org/649
Reviewed-by: Miklos Vajna <vmiklos@suse.cz>
Tested-by: Miklos Vajna <vmiklos@suse.cz>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/inc/oox/vml/vmlshape.hxx | 19 | ||||
-rw-r--r-- | oox/inc/oox/vml/vmlshapecontext.hxx | 6 | ||||
-rw-r--r-- | oox/source/token/properties.txt | 1 | ||||
-rw-r--r-- | oox/source/vml/vmlshape.cxx | 84 | ||||
-rw-r--r-- | oox/source/vml/vmlshapecontext.cxx | 30 |
5 files changed, 138 insertions, 2 deletions
diff --git a/oox/inc/oox/vml/vmlshape.hxx b/oox/inc/oox/vml/vmlshape.hxx index 8fab5f7ec92d..5bdc2b51e486 100644 --- a/oox/inc/oox/vml/vmlshape.hxx +++ b/oox/inc/oox/vml/vmlshape.hxx @@ -185,6 +185,9 @@ struct ShapeModel ::rtl::OUString maLegacyDiagramPath;///< Legacy Diagram Fragment Path ::rtl::OUString maFrom; ///< Start point for line shape. ::rtl::OUString maTo; ///< End point for line shape. + ::rtl::OUString maControl1; ///< Bezier control point 1 + ::rtl::OUString maControl2; ///< Bezier control point 2 + ::rtl::OUString maVmlPath; ///< VML path for this shape explicit ShapeModel(); ~ShapeModel(); @@ -334,6 +337,22 @@ protected: const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes, const ::com::sun::star::awt::Rectangle& rShapeRect ) const; }; + +/** Bezier shape object that supports to, from, control1 and control2 + attribute or path attribute specification */ +class BezierShape : public SimpleShape +{ +public: + explicit BezierShape( Drawing& rDrawing ); + +protected: + /** Creates the corresponding XShape and inserts it into the passed container. */ + virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + implConvertAndInsert( + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& rxShapes, + const ::com::sun::star::awt::Rectangle& rShapeRect ) const; +}; + // ============================================================================ /** A shape object with custom geometry. */ diff --git a/oox/inc/oox/vml/vmlshapecontext.hxx b/oox/inc/oox/vml/vmlshapecontext.hxx index 358f8fedd706..e3d5d8963eb2 100644 --- a/oox/inc/oox/vml/vmlshapecontext.hxx +++ b/oox/inc/oox/vml/vmlshapecontext.hxx @@ -134,6 +134,12 @@ private: void setFrom( const ::rtl::OUString& rPoints ); /** Processes the 'to' attribute. */ void setTo( const ::rtl::OUString& rPoints ); + /** Processes the 'control1' attribute. */ + void setControl1( const ::rtl::OUString& rPoints ); + /** Processes the 'control2' attribute. */ + void setControl2( const ::rtl::OUString& rPoints ); + /** Processes the 'path' attribute. */ + void setVmlPath( const ::rtl::OUString& rPath ); protected: ShapeBase& mrShape; diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt index 5c917e9d7f29..8d5ab7d5991b 100644 --- a/oox/source/token/properties.txt +++ b/oox/source/token/properties.txt @@ -334,6 +334,7 @@ PercentageNumberFormat PersistName Perspective PolyPolygon +PolyPolygonBezier PolygonKind Position PositionBottom diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index 156730f67d01..0bd3399f3c6f 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -23,6 +23,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/awt/XControlModel.hpp> #include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> #include <com/sun/star/drawing/XShapes.hpp> #include <com/sun/star/drawing/XControlShape.hpp> @@ -553,6 +554,89 @@ Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxSh // ============================================================================ +BezierShape::BezierShape(Drawing& rDrawing) + : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape") +{ +} + +Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const +{ + Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect ); + Rectangle aCoordSys = getCoordSystem(); + + if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) ) + { + const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); + + // Bezier paths may consist of one or more sub-paths + typedef ::std::vector< ::std::vector< Point > > SubPathList; + typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList; + SubPathList aCoordLists; + FlagsList aFlagLists; + sal_Int32 nIndex = 0; + + // Curve defined by to, from, control1 and control2 attributes + if ( maShapeModel.maVmlPath.isEmpty() ) + { + aCoordLists.push_back( ::std::vector< Point >() ); + aFlagLists.push_back( ::std::vector< PolygonFlags >() ); + + // Start point + aCoordLists[ 0 ].push_back( + Point(ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) ) ); + // Control point 1 + aCoordLists[ 0 ].push_back( + Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) ) ); + // Control point 2 + aCoordLists[ 0 ].push_back( + Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) ) ); + // End point + aCoordLists[ 0 ].push_back( + Point( ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) ) ); + + // First and last points are normals, points 2 and 4 are controls + aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL ); + aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL; + aFlagLists[ 0 ].back() = PolygonFlags_NORMAL; + } + // Curve defined by path attribute + else + { + // Parse VML path string and convert to absolute coordinates + ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath ); + + for ( SubPathList::iterator aListIt = aCoordLists.begin(); aListIt != aCoordLists.end(); aListIt++ ) + for ( ::std::vector< Point >::iterator aPointIt = (*aListIt).begin(); aPointIt != (*aListIt).end(); aPointIt++) + { + (*aPointIt) = lclGetAbsPoint( (*aPointIt), rShapeRect, aCoordSys ); + } + } + + PolyPolygonBezierCoords aBezierCoords; + aBezierCoords.Coordinates.realloc( aCoordLists.size() ); + for ( unsigned int i = 0; i < aCoordLists.size(); i++ ) + aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] ); + + aBezierCoords.Flags.realloc( aFlagLists.size() ); + for ( unsigned int i = 0; i < aFlagLists.size(); i++ ) + aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] ); + + PropertySet aPropSet( xShape ); + aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords ); + } + + // Hacky way of ensuring the shape is correctly sized/positioned + xShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) ); + xShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) ); + return xShape; +} + +// ============================================================================ + CustomShape::CustomShape( Drawing& rDrawing ) : SimpleShape( rDrawing, CREATE_OUSTRING( "com.sun.star.drawing.CustomShape" ) ) { diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index b140f5a363f3..88998d1b06a4 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -216,7 +216,10 @@ ShapeContextBase::ShapeContextBase( ContextHandler2Helper& rParent ) : case VML_TOKEN( group ): return new GroupShapeContext( rParent, rShapes.createShape< GroupShape >(), rAttribs ); case VML_TOKEN( shape ): - return new ShapeContext( rParent, rShapes.createShape< ComplexShape >(), rAttribs ); + if (rAttribs.hasAttribute(XML_path)) + return new ShapeContext( rParent, rShapes.createShape< BezierShape >(), rAttribs ); + else + return new ShapeContext( rParent, rShapes.createShape< ComplexShape >(), rAttribs ); case VML_TOKEN( rect ): return new RectangleShapeContext( rParent, rAttribs, rShapes.createShape< RectangleShape >() ); case VML_TOKEN( roundrect ): @@ -227,10 +230,11 @@ ShapeContextBase::ShapeContextBase( ContextHandler2Helper& rParent ) : return new ShapeContext( rParent, rShapes.createShape< PolyLineShape >(), rAttribs ); case VML_TOKEN( line ): return new ShapeContext( rParent, rShapes.createShape< LineShape >(), rAttribs ); + case VML_TOKEN( curve ): + return new ShapeContext( rParent, rShapes.createShape< BezierShape >(), rAttribs ); // TODO: case VML_TOKEN( arc ): - case VML_TOKEN( curve ): case VML_TOKEN( diagram ): case VML_TOKEN( image ): return new ShapeContext( rParent, rShapes.createShape< ComplexShape >(), rAttribs ); @@ -379,6 +383,9 @@ ShapeContext::ShapeContext( ContextHandler2Helper& rParent, ShapeBase& rShape, c // line start and end positions setFrom(rAttribs.getString(XML_from, OUString())); setTo(rAttribs.getString(XML_to, OUString())); + setControl1(rAttribs.getString(XML_control1, OUString())); + setControl2(rAttribs.getString(XML_control2, OUString())); + setVmlPath(rAttribs.getString(XML_path, OUString())); } ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) @@ -409,6 +416,7 @@ void ShapeContext::setPoints( const OUString& rPoints ) { mrShapeModel.maPoints.clear(); sal_Int32 nIndex = 0; + while( nIndex >= 0 ) { sal_Int32 nX = rPoints.getToken( 0, ',', nIndex ).toInt32(); @@ -429,6 +437,24 @@ void ShapeContext::setTo( const OUString& rPoints ) mrShapeModel.maTo = rPoints; } +void ShapeContext::setControl1( const OUString& rPoints ) +{ + if (!rPoints.isEmpty()) + mrShapeModel.maControl1 = rPoints; +} + +void ShapeContext::setControl2( const OUString& rPoints ) +{ + if (!rPoints.isEmpty()) + mrShapeModel.maControl2 = rPoints; +} +void ShapeContext::setVmlPath( const OUString& rPath ) +{ + if (!rPath.isEmpty()) + mrShapeModel.maVmlPath = rPath; +} + + // ============================================================================ GroupShapeContext::GroupShapeContext( ContextHandler2Helper& rParent, GroupShape& rShape, const AttributeList& rAttribs ) : |