summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorTamás Zolnai <tamas.zolnai@collabora.com>2017-08-23 17:46:30 +0200
committerAndras Timar <andras.timar@collabora.com>2017-08-25 15:31:15 +0200
commit9b40796fd3e8f724d69a343e0444220b69a6d6ab (patch)
tree777eeff0e42ce26e6011cf01c014dcba144f29cc /oox
parent8170245a9d9b9aeff913e0b3477fc2a9d508af80 (diff)
tdf#50097: DOCX: export form controls as MSO ActiveX controls
* Use the same structure for export what MSO uses ** Position and size information are exported as VML shape properties ** Different handling of inline and floating controls (pict or object) ** Do some changes on VML shape export to match how MSO exports these controls ** Write out activeX.xml and activeX.bin to store control properties ** Use persistStorage storage type defined in activeX.xml * Drop grabbaging of activex.XML and activeX.bin * Cleanup control related test code Signed-off-by: Tamás Zolnai <tamas.zolnai@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/41256 Tested-by: Jenkins <ci@libreoffice.org> (cherry picked from commit c0cc02e2934aeb12dda44818955e5964496c186a) Change-Id: I38bb2b2ffd2676c5459b61ec2549c31348bab41c This test intended to be an export test Change-Id: Ib233bd603185efdb85ed30f3d00c28512d57a0ac Reviewed-on: https://gerrit.libreoffice.org/41355 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com> (cherry picked from commit a7e8c5304b740cb4e03e25b7217ce6071c29c09b) Fix two issues in ActiveX DOCX import / export code * Inline anchored VML shape had wrong vertical position ** In MSO inline shapes are positioned to the top of the baseline * During export all shape ids were the same (shape_0) ** VML shapes used to be exported only as fallback, I guess that's why it did not cause any issue before. ** Override the shapeid generator with a new one, which actually generates unique shapeids. Reviewed-on: https://gerrit.libreoffice.org/41319 Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com> Tested-by: Tamás Zolnai <tamas.zolnai@collabora.com> (cherry picked from commit 2d1fe7fb67ec1ff1b96912c0945d17d54aecb12e) Change-Id: I752f39d092d0b61d91824141655dae662dbeafbc DOCX: Fix an other test case of ActiveX control export When LO control is anchored to the end of the run, it is exported into a new run. Reviewed-on: https://gerrit.libreoffice.org/41472 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com> (cherry picked from commit b129421764ae78a1422812169fce8eb4914a6b22) Change-Id: I9269fd1b34924780aad61c452d1e2094dc8e4aad Reviewed-on: https://gerrit.libreoffice.org/41484 Reviewed-by: Andras Timar <andras.timar@collabora.com> Tested-by: Andras Timar <andras.timar@collabora.com>
Diffstat (limited to 'oox')
-rw-r--r--oox/source/export/preset-definitions-to-shape-types.pl2
-rw-r--r--oox/source/export/vmlexport.cxx125
-rw-r--r--oox/source/ole/olehelper.cxx45
-rw-r--r--oox/source/token/tokens.txt2
-rw-r--r--oox/source/vml/vmlshape.cxx2
5 files changed, 133 insertions, 43 deletions
diff --git a/oox/source/export/preset-definitions-to-shape-types.pl b/oox/source/export/preset-definitions-to-shape-types.pl
index 2fe929705746..b41dd58953e8 100644
--- a/oox/source/export/preset-definitions-to-shape-types.pl
+++ b/oox/source/export/preset-definitions-to-shape-types.pl
@@ -287,7 +287,7 @@ my %shapes_ids = (
198 => 'actionButtonDocument',
199 => 'actionButtonSound',
200 => 'actionButtonMovie',
- 201 => 'hostControl', # should not be used
+ 201 => 'hostControl',
202 => 'textBox'
);
# An error occurred, we have to ignore this shape
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 33c112e0c287..cf6e5d6234f2 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -59,6 +59,7 @@ VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLText
, m_eVOri( 0 )
, m_eHRel( 0 )
, m_eVRel( 0 )
+ , m_bInline( false )
, m_pNdTopLeft( nullptr )
, m_pSdrObject( nullptr )
, m_pShapeAttrList( nullptr )
@@ -66,6 +67,10 @@ VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLText
, m_nShapeFlags(0)
, m_pShapeStyle( new OStringBuffer( 200 ) )
, m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] )
+ , m_bSkipwzName( false )
+ , m_bUseHashMarkForType( false )
+ , m_bOverrideShapeIdGeneration( false )
+ , m_nShapeIDCounter( 0 )
{
mnGroupLevel = 1;
memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) );
@@ -188,19 +193,21 @@ void VMLExport::AddShape( sal_uInt32 nShapeType, sal_uInt32 nShapeFlags, sal_uIn
{
m_nShapeType = nShapeType;
m_nShapeFlags = nShapeFlags;
+
+ m_sShapeId = ShapeIdString( nShapeId );
// If shape is a watermark object - should keep the original shape's name
// because Microsoft detects if it is a watermark by the actual name
if (!IsWaterMarkShape(m_pSdrObject->GetName()))
{
// Not a watermark object
- m_pShapeAttrList->add( XML_id, ShapeIdString( nShapeId ) );
+ m_pShapeAttrList->add( XML_id, m_sShapeId );
}
else
{
// A watermark object - store the optional shape ID
m_pShapeAttrList->add( XML_id, OUStringToOString(m_pSdrObject->GetName(), RTL_TEXTENCODING_UTF8) );
// also ('o:spid')
- m_pShapeAttrList->addNS( XML_o, XML_spid, ShapeIdString( nShapeId ) );
+ m_pShapeAttrList->addNS( XML_o, XML_spid, m_sShapeId );
}
}
@@ -214,6 +221,18 @@ bool VMLExport::IsWaterMarkShape(const OUString& rStr)
return false;
}
+void VMLExport::OverrideShapeIDGen(bool bOverrideShapeIdGen, const OString sShapeIDPrefix)
+{
+ m_bOverrideShapeIdGeneration = bOverrideShapeIdGen;
+ if(bOverrideShapeIdGen)
+ {
+ assert(!sShapeIDPrefix.isEmpty());
+ m_sShapeIDPrefix = sShapeIDPrefix;
+ }
+ else
+ m_sShapeIDPrefix.clear();
+}
+
static void impl_AddArrowHead( sax_fastparser::FastAttributeList *pAttrList, sal_Int32 nElement, sal_uInt32 nValue )
{
if ( !pAttrList )
@@ -859,7 +878,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
aStream.Seek(0);
OUString idStr = SvxMSDffManager::MSDFFReadZString(aStream, it->nPropSize, true);
aStream.Seek(0);
- if (!IsWaterMarkShape(m_pSdrObject->GetName()))
+ if (!IsWaterMarkShape(m_pSdrObject->GetName()) && !m_bSkipwzName)
m_pShapeAttrList->add(XML_ID, OUStringToOString(idStr, RTL_TEXTENCODING_UTF8).getStr());
bAlreadyWritten[ESCHER_Prop_wzName] = true;
@@ -890,7 +909,10 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
OString VMLExport::ShapeIdString( sal_uInt32 nId )
{
- return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
+ if(m_bOverrideShapeIdGeneration)
+ return OStringBuffer( 20 ).append( m_sShapeIDPrefix ).append( sal_Int64( nId ) ).makeStringAndClear();
+ else
+ return OStringBuffer( 20 ).append( "shape_" ).append( sal_Int64( nId ) ).makeStringAndClear();
}
void VMLExport::AddFlipXY( )
@@ -949,12 +971,18 @@ void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const Rectangle&
if ( !rBuffer.isEmpty() )
rBuffer.append( ";" );
- if (rbAbsolutePos)
+ if (rbAbsolutePos && !m_bInline)
{
rBuffer.append( "position:absolute;" );
}
- if ( mnGroupLevel == 1 )
+ if(m_bInline)
+ {
+ rBuffer.append( "width:" ).append( double( rRectangle.Right() - rRectangle.Left() ) / 20 )
+ .append( "pt;height:" ).append( double( rRectangle.Bottom() - rRectangle.Top() ) / 20 )
+ .append( "pt" );
+ }
+ else if ( mnGroupLevel == 1 )
{
rBuffer.append( "margin-left:" ).append( double( rRectangle.Left() ) / 20 )
.append( "pt;margin-top:" ).append( double( rRectangle.Top() ) / 20 )
@@ -1025,6 +1053,14 @@ OUString lcl_getAnchorIdFromGrabBag(const SdrObject* pSdrObject)
return aResult;
}
+sal_uInt32 VMLExport::GenerateShapeId()
+{
+ if(!m_bOverrideShapeIdGeneration)
+ return EscherEx::GenerateShapeId();
+ else
+ return m_nShapeIDCounter++;
+}
+
sal_Int32 VMLExport::StartShape()
{
if ( m_nShapeType == ESCHER_ShpInst_Nil )
@@ -1041,6 +1077,62 @@ sal_Int32 VMLExport::StartShape()
case ESCHER_ShpInst_Ellipse: nShapeElement = XML_oval; break;
case ESCHER_ShpInst_Arc: nShapeElement = XML_arc; break;
case ESCHER_ShpInst_Line: nShapeElement = XML_line; break;
+ case ESCHER_ShpInst_HostControl:
+ {
+ // We don't have a shape definition for host control in presetShapeDefinitions.xml
+ // So use a definition copied from DOCX file created with MSO
+ bReferToShapeType = true;
+ nShapeElement = XML_shape;
+ if ( !m_pShapeTypeWritten[ m_nShapeType ] )
+ {
+ OStringBuffer sShapeType;
+ sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)).
+ append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)).
+ append("\" path=\"m,l,21600l21600,21600l21600,xe\">\n").
+ append("<v:stroke joinstyle=\"miter\"/>\n"
+ "<v:path shadowok=\"f\" o:extrusionok=\"f\" strokeok=\"f\" fillok=\"f\" o:connecttype=\"rect\"/>\n"
+ "<o:lock v:ext=\"edit\" shapetype=\"t\"/>\n"
+ "</v:shapetype>");
+ m_pSerializer->write(sShapeType.makeStringAndClear().getStr());
+ m_pShapeTypeWritten[ m_nShapeType ] = true;
+ }
+ break;
+ }
+ case ESCHER_ShpInst_PictureFrame:
+ {
+ // We don't have a shape definition for picture frame in presetShapeDefinitions.xml
+ // So use a definition copied from DOCX file created with MSO
+ bReferToShapeType = true;
+ nShapeElement = XML_shape;
+ if ( !m_pShapeTypeWritten[ m_nShapeType ] )
+ {
+ OStringBuffer sShapeType;
+ sShapeType.append("<v:shapetype id=\"shapetype_").append(OString::number(m_nShapeType)).
+ append("\" coordsize=\"21600,21600\" o:spt=\"").append(OString::number(m_nShapeType)).
+ append("\" o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">\n").
+ append("<v:stroke joinstyle=\"miter\"/>\n"
+ "<v:formulas>\n"
+ "<v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>\n"
+ "<v:f eqn=\"sum @0 1 0\"/>\n"
+ "<v:f eqn=\"sum 0 0 @1\"/>\n"
+ "<v:f eqn=\"prod @2 1 2\"/>\n"
+ "<v:f eqn=\"prod @3 21600 pixelWidth\"/>\n"
+ "<v:f eqn=\"prod @3 21600 pixelHeight\"/>\n"
+ "<v:f eqn=\"sum @0 0 1\"/>\n"
+ "<v:f eqn=\"prod @6 1 2\"/>\n"
+ "<v:f eqn=\"prod @7 21600 pixelWidth\"/>\n"
+ "<v:f eqn=\"sum @8 21600 0\"/>\n"
+ "<v:f eqn=\"prod @7 21600 pixelHeight\"/>\n"
+ "<v:f eqn=\"sum @10 21600 0\"/>\n"
+ "</v:formulas>\n"
+ "<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\n"
+ "<o:lock v:ext=\"edit\" aspectratio=\"t\"/>\n"
+ "</v:shapetype>");
+ m_pSerializer->write(sShapeType.makeStringAndClear().getStr());
+ m_pShapeTypeWritten[ m_nShapeType ] = true;
+ }
+ break;
+ }
default:
if ( m_nShapeType < ESCHER_ShpInst_COUNT )
{
@@ -1147,7 +1239,10 @@ sal_Int32 VMLExport::StartShape()
if ( nShapeElement >= 0 && !m_pShapeAttrList->hasAttribute( XML_type ) && bReferToShapeType )
{
- m_pShapeAttrList->add( XML_type, OStringBuffer( 20 )
+ OStringBuffer sTypeBuffer( 20 );
+ if (m_bUseHashMarkForType)
+ sTypeBuffer.append("#");
+ m_pShapeAttrList->add( XML_type, sTypeBuffer
.append( "shapetype_" ).append( sal_Int32( m_nShapeType ) )
.makeStringAndClear() );
}
@@ -1220,7 +1315,7 @@ void VMLExport::EndShape( sal_Int32 nShapeElement )
}
}
-void VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport )
+OString VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const Point* pNdTopLeft, const bool bOOxmlExport )
{
m_pSdrObject = &rObj;
m_eHOri = eHOri;
@@ -1228,7 +1323,21 @@ void VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16
m_eHRel = eHRel;
m_eVRel = eVRel;
m_pNdTopLeft = pNdTopLeft;
+ m_bInline = false;
+ EscherEx::AddSdrObject(rObj, bOOxmlExport);
+ return m_sShapeId;
+}
+
+OString VMLExport::AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport )
+{
+ m_pSdrObject = &rObj;
+ m_eHOri = -1;
+ m_eVOri = -1;
+ m_eHRel = -1;
+ m_eVRel = -1;
+ m_bInline = true;
EscherEx::AddSdrObject(rObj, bOOxmlExport);
+ return m_sShapeId;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/ole/olehelper.cxx b/oox/source/ole/olehelper.cxx
index bb1ed9ce4f67..d78a3ac8e8eb 100644
--- a/oox/source/ole/olehelper.cxx
+++ b/oox/source/ole/olehelper.cxx
@@ -330,35 +330,7 @@ Reference< css::frame::XFrame > lcl_getFrame( const Reference< css::frame::XMod
return xFrame;
}
-class OleFormCtrlExportHelper final
-{
- ::oox::ole::EmbeddedControl maControl;
- ::oox::ole::ControlModelBase* mpModel;
- ::oox::GraphicHelper maGrfHelper;
- Reference< XModel > mxDocModel;
- Reference< XControlModel > mxControlModel;
-
- OUString maName;
- OUString maTypeName;
- OUString maFullName;
- OUString maGUID;
-public:
- OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& xDocModel, const Reference< XControlModel >& xModel );
- OUString getGUID()
- {
- OUString sResult;
- if ( maGUID.getLength() > 2 )
- sResult = maGUID.copy(1, maGUID.getLength() - 2 );
- return sResult;
- }
- const OUString& getFullName() { return maFullName; }
- const OUString& getTypeName() { return maTypeName; }
- bool isValid() { return mpModel != nullptr; }
- void exportName( const Reference< XOutputStream >& rxOut );
- void exportCompObj( const Reference< XOutputStream >& rxOut );
- void exportControl( const Reference< XOutputStream >& rxOut, const css::awt::Size& rSize );
-};
-OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& rxDocModel, const Reference< XControlModel >& xCntrlModel ) : maControl( "Unknown" ), mpModel( nullptr ), maGrfHelper( rxCtx, lcl_getFrame( rxDocModel ), StorageRef() ), mxDocModel( rxDocModel ), mxControlModel( xCntrlModel )
+OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentContext >& rxCtx, const Reference< XModel >& rxDocModel, const Reference< XControlModel >& xCntrlModel ) : mpControl(nullptr), mpModel( nullptr ), maGrfHelper( rxCtx, lcl_getFrame( rxDocModel ), StorageRef() ), mxDocModel( rxDocModel ), mxControlModel( xCntrlModel )
{
// try to get the guid
Reference< css::beans::XPropertySet > xProps( xCntrlModel, UNO_QUERY );
@@ -405,14 +377,18 @@ OleFormCtrlExportHelper::OleFormCtrlExportHelper( const Reference< XComponentCo
aPropSet.getProperty(maName, PROP_Name );
maTypeName = OUString::createFromAscii( it->second.sName );
maFullName = "Microsoft Forms 2.0 " + maTypeName;
- maControl = EmbeddedControl( maName );
+ mpControl.reset(new EmbeddedControl( maName ));
maGUID = OUString::createFromAscii( it->second.sGUID );
- mpModel = maControl.createModelFromGuid( maGUID );
+ mpModel = mpControl->createModelFromGuid( maGUID );
}
}
}
}
+OleFormCtrlExportHelper::~OleFormCtrlExportHelper()
+{
+}
+
void OleFormCtrlExportHelper::exportName( const Reference< XOutputStream >& rxOut )
{
oox::BinaryXOutputStream aOut( rxOut, false );
@@ -427,13 +403,14 @@ void OleFormCtrlExportHelper::exportCompObj( const Reference< XOutputStream >& r
mpModel->exportCompObj( aOut );
}
-void OleFormCtrlExportHelper::exportControl( const Reference< XOutputStream >& rxOut, const Size& rSize )
+void OleFormCtrlExportHelper::exportControl( const Reference< XOutputStream >& rxOut, const Size& rSize, bool bAutoClose )
{
- oox::BinaryXOutputStream aOut( rxOut, false );
+ oox::BinaryXOutputStream aOut( rxOut, bAutoClose );
if ( mpModel )
{
::oox::ole::ControlConverter aConv( mxDocModel, maGrfHelper );
- maControl.convertFromProperties( mxControlModel, aConv );
+ if(mpControl)
+ mpControl->convertFromProperties( mxControlModel, aConv );
mpModel->maSize.first = rSize.Width;
mpModel->maSize.second = rSize.Height;
mpModel->exportBinaryModel( aOut );
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index 6d4fcb8a47f5..99ff379230be 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -745,6 +745,7 @@ avLst
average
avg
avgSubtotal
+ax
axId
axPos
axis
@@ -5808,6 +5809,7 @@ xmlPr
xmlns
xpath
xrange
+xsc
xscale
xsi
xy
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx
index 9f9903a04e88..814835fae503 100644
--- a/oox/source/vml/vmlshape.cxx
+++ b/oox/source/vml/vmlshape.cxx
@@ -623,6 +623,8 @@ void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel,
else // static (is the default) means anchored inline
{
rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
+ // Use top orientation, this one seems similar to what MSO uses as inline
+ rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
}
lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
}