diff options
author | Tamás Zolnai <tamas.zolnai@collabora.com> | 2017-08-17 21:47:22 +0200 |
---|---|---|
committer | Tamás Zolnai <tamas.zolnai@collabora.com> | 2017-08-17 23:11:15 +0200 |
commit | c0cc02e2934aeb12dda44818955e5964496c186a (patch) | |
tree | 16f450bbe38e14d336bdbac3220b642b9a302a87 /oox | |
parent | 8c0cc5cd7befffc6e8e6361ba67807a799cc997f (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
Change-Id: I38bb2b2ffd2676c5459b61ec2549c31348bab41c
Signed-off-by: Tamás Zolnai <tamas.zolnai@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/41256
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'oox')
-rw-r--r-- | oox/source/export/preset-definitions-to-shape-types.pl | 2 | ||||
-rw-r--r-- | oox/source/export/vmlexport.cxx | 93 | ||||
-rw-r--r-- | oox/source/ole/olehelper.cxx | 45 | ||||
-rw-r--r-- | oox/source/token/tokens.txt | 2 |
4 files changed, 100 insertions, 42 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 b91d72e218e9..3ee2711f8e5f 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,8 @@ VMLExport::VMLExport( ::sax_fastparser::FSHelperPtr const & pSerializer, VMLText , m_nShapeFlags(0) , m_ShapeStyle( 200 ) , m_aShapeTypeWritten( ESCHER_ShpInst_COUNT ) + , m_bSkipwzName( false ) + , m_bUseHashMarkForType( false ) { mnGroupLevel = 1; } @@ -181,19 +184,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 ); } } @@ -849,7 +854,7 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& 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; @@ -939,12 +944,18 @@ void VMLExport::AddRectangleDimensions( OStringBuffer& rBuffer, const tools::Rec 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 ) @@ -1031,6 +1042,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_aShapeTypeWritten[ 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_aShapeTypeWritten[ 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_aShapeTypeWritten[ 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_aShapeTypeWritten[ m_nShapeType ] = true; + } + break; + } default: if ( m_nShapeType < ESCHER_ShpInst_COUNT ) { @@ -1137,7 +1204,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() ); } @@ -1210,7 +1280,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; @@ -1219,6 +1289,15 @@ void VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 m_eVRel = eVRel; m_pNdTopLeft = pNdTopLeft; EscherEx::AddSdrObject(rObj, bOOxmlExport); + return m_sShapeId; +} + +OString VMLExport::AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport ) +{ + m_pSdrObject = &rObj; + 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 1a6e7df17a5e..f2df54a833a0 100644 --- a/oox/source/ole/olehelper.cxx +++ b/oox/source/ole/olehelper.cxx @@ -329,35 +329,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 ); @@ -404,14 +376,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 ); @@ -426,13 +402,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 00577f862890..653050ea9ba2 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -740,6 +740,7 @@ avLst average avg avgSubtotal +ax axId axPos axis @@ -5808,6 +5809,7 @@ xmlPr xmlns xpath xrange +xsc xscale xsi xy |