diff options
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/table-cell-margin.docx (renamed from sw/qa/extras/ooxmlexport/data/table-position.docx) | bin | 13708 -> 13708 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/table-position-14.docx | bin | 0 -> 13708 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/table-position-15.docx | bin | 0 -> 13683 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport2.cxx | 35 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport8.cxx | 76 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 62 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapperTableHandler.cxx | 39 |
7 files changed, 169 insertions, 43 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/table-position.docx b/sw/qa/extras/ooxmlexport/data/table-cell-margin.docx Binary files differindex f59a5da11a95..f59a5da11a95 100644 --- a/sw/qa/extras/ooxmlexport/data/table-position.docx +++ b/sw/qa/extras/ooxmlexport/data/table-cell-margin.docx diff --git a/sw/qa/extras/ooxmlexport/data/table-position-14.docx b/sw/qa/extras/ooxmlexport/data/table-position-14.docx Binary files differnew file mode 100644 index 000000000000..f59a5da11a95 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/table-position-14.docx diff --git a/sw/qa/extras/ooxmlexport/data/table-position-15.docx b/sw/qa/extras/ooxmlexport/data/table-position-15.docx Binary files differnew file mode 100644 index 000000000000..d3dcaec40e78 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/table-position-15.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx index a0bd7e490320..3b4445f8585e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx @@ -363,41 +363,6 @@ DECLARE_OOXMLEXPORT_TEST(testTable, "table.odt") assertXPath(parseExport("word/styles.xml"), "//w:style[@w:styleId='Normal']/w:qFormat", 1); } -DECLARE_OOXMLEXPORT_TEST(testTablePosition, "table-position.docx") -{ - sal_Int32 aXCoordsFromOffice[] = { 2500, -1000, 0, 0 }; - sal_Int32 cellLeftMarginFromOffice[] = { 250, 100, 0, 0 }; - - uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY); - uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); - uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables( ), uno::UNO_QUERY); - - for (int i=0; i<4; i++) { - uno::Reference<text::XTextTable> xTable1 (xTables->getByIndex(i), uno::UNO_QUERY); - // Verify X coord - uno::Reference<view::XSelectionSupplier> xCtrl(xModel->getCurrentController(), uno::UNO_QUERY); - xCtrl->select(uno::makeAny(xTable1)); - uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(xCtrl, uno::UNO_QUERY); - uno::Reference<text::XTextViewCursor> xCursor(xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY); - awt::Point pos = xCursor->getPosition(); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect X coord computed from docx", - aXCoordsFromOffice[i], pos.X, 1); - - // Verify left margin of 1st cell : - // * Office left margins are measured relative to the right of the border - // * LO left spacing is measured from the center of the border - uno::Reference<table::XCell> xCell = xTable1->getCellByName("A1"); - uno::Reference< beans::XPropertySet > xPropSet(xCell, uno::UNO_QUERY_THROW); - sal_Int32 aLeftMargin = -1; - xPropSet->getPropertyValue("LeftBorderDistance") >>= aLeftMargin; - uno::Any aLeftBorder = xPropSet->getPropertyValue("LeftBorder"); - table::BorderLine2 aLeftBorderLine; - aLeftBorder >>= aLeftBorderLine; - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect left spacing computed from docx cell margin", - cellLeftMarginFromOffice[i], aLeftMargin - 0.5 * aLeftBorderLine.LineWidth, 1); - } -} - struct SingleLineBorders { sal_Int16 top, bottom, left, right; SingleLineBorders(int t=0, int b=0, int l=0, int r=0) diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx index 5b62695446fc..d751899dee8e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx @@ -47,6 +47,7 @@ #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/table/ShadowFormat.hpp> #include <com/sun/star/view/XFormLayerAccess.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> #include <com/sun/star/table/BorderLine2.hpp> #include <com/sun/star/table/TableBorder2.hpp> #include <com/sun/star/text/SizeType.hpp> @@ -2096,6 +2097,81 @@ DECLARE_OOXMLEXPORT_TEST(testTdf99140, "tdf99140.docx") CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::LEFT_AND_WIDTH, getProperty<sal_Int16>(xTableProperties, "HoriOrient")); } +DECLARE_OOXMLEXPORT_TEST( testTableCellMargin, "table-cell-margin.docx" ) +{ + sal_Int32 cellLeftMarginFromOffice[] = { 250, 100, 0, 0 }; + + uno::Reference< text::XTextTablesSupplier > xTablesSupplier( mxComponent, uno::UNO_QUERY ); + uno::Reference< frame::XModel > xModel( mxComponent, uno::UNO_QUERY ); + uno::Reference< container::XIndexAccess > xTables( xTablesSupplier->getTextTables(), uno::UNO_QUERY ); + + for ( int i = 0; i < 4; i++ ) + { + uno::Reference< text::XTextTable > xTable1( xTables->getByIndex( i ), uno::UNO_QUERY ); + + // Verify left margin of 1st cell : + // * Office left margins are measured relative to the right of the border + // * LO left spacing is measured from the center of the border + uno::Reference< table::XCell > xCell = xTable1->getCellByName( "A1" ); + uno::Reference< beans::XPropertySet > xPropSet( xCell, uno::UNO_QUERY_THROW ); + sal_Int32 aLeftMargin = -1; + xPropSet->getPropertyValue( "LeftBorderDistance" ) >>= aLeftMargin; + uno::Any aLeftBorder = xPropSet->getPropertyValue( "LeftBorder" ); + table::BorderLine2 aLeftBorderLine; + aLeftBorder >>= aLeftBorderLine; + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Incorrect left spacing computed from docx cell margin", + cellLeftMarginFromOffice[i], aLeftMargin - 0.5 * aLeftBorderLine.LineWidth, 1 ); + } +} + +// tdf#106742 for DOCX with compatibility level <= 14 (MS Word up to and incl. ver.2010), we should use cell margins when calculating table left border position +DECLARE_OOXMLEXPORT_TEST( testTablePosition14, "table-position-14.docx" ) +{ + sal_Int32 aXCoordsFromOffice[] = { 2500, -1000, 0, 0 }; + + uno::Reference< text::XTextTablesSupplier > xTablesSupplier( mxComponent, uno::UNO_QUERY ); + uno::Reference< frame::XModel > xModel( mxComponent, uno::UNO_QUERY ); + uno::Reference< container::XIndexAccess > xTables( xTablesSupplier->getTextTables(), uno::UNO_QUERY ); + + for ( int i = 0; i < 4; i++ ) + { + uno::Reference< text::XTextTable > xTable1( xTables->getByIndex( i ), uno::UNO_QUERY ); + + // Verify X coord + uno::Reference< view::XSelectionSupplier > xCtrl( xModel->getCurrentController(), uno::UNO_QUERY ); + xCtrl->select( uno::makeAny( xTable1 ) ); + uno::Reference< text::XTextViewCursorSupplier > xTextViewCursorSupplier( xCtrl, uno::UNO_QUERY ); + uno::Reference< text::XTextViewCursor > xCursor( xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY ); + awt::Point pos = xCursor->getPosition(); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Incorrect X coord computed from docx", + aXCoordsFromOffice[i], pos.X, 1 ); + } +} + +// tdf#106742 for DOCX with compatibility level > 14 (MS Word since ver.2013), we should NOT use cell margins when calculating table left border position +DECLARE_OOXMLEXPORT_TEST( testTablePosition15, "table-position-15.docx" ) +{ + sal_Int32 aXCoordsFromOffice[] = { 2751, -899, 1, 106 }; + + uno::Reference< text::XTextTablesSupplier > xTablesSupplier( mxComponent, uno::UNO_QUERY ); + uno::Reference< frame::XModel > xModel( mxComponent, uno::UNO_QUERY ); + uno::Reference< container::XIndexAccess > xTables( xTablesSupplier->getTextTables(), uno::UNO_QUERY ); + + for ( int i = 0; i < 4; i++ ) + { + uno::Reference< text::XTextTable > xTable1( xTables->getByIndex( i ), uno::UNO_QUERY ); + + // Verify X coord + uno::Reference< view::XSelectionSupplier > xCtrl( xModel->getCurrentController(), uno::UNO_QUERY ); + xCtrl->select( uno::makeAny( xTable1 ) ); + uno::Reference< text::XTextViewCursorSupplier > xTextViewCursorSupplier( xCtrl, uno::UNO_QUERY ); + uno::Reference< text::XTextViewCursor > xCursor( xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY ); + awt::Point pos = xCursor->getPosition(); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Incorrect X coord computed from docx", + aXCoordsFromOffice[i], pos.X, 1 ); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index fe8ec152a934..a1be3420d4fe 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -3206,6 +3206,51 @@ OString lcl_padStartToLength(OString const & aString, sal_Int32 nLen, sal_Char c return aString; } +sal_Int32 lcl_getWordCompatibilityMode( const SwDoc& rDoc ) +{ + uno::Reference< beans::XPropertySet > xPropSet( rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + if ( xPropSetInfo->hasPropertyByName( UNO_NAME_MISC_OBJ_INTEROPGRABBAG ) ) + { + uno::Sequence< beans::PropertyValue > propList; + xPropSet->getPropertyValue( UNO_NAME_MISC_OBJ_INTEROPGRABBAG ) >>= propList; + + for ( sal_Int32 i = 0; i < propList.getLength(); ++i ) + { + if ( propList[i].Name == "CompatSettings" ) + { + css::uno::Sequence< css::beans::PropertyValue > aCurrentCompatSettings; + propList[i].Value >>= aCurrentCompatSettings; + + for ( sal_Int32 j = 0; j < aCurrentCompatSettings.getLength(); ++j ) + { + uno::Sequence< beans::PropertyValue > aCompatSetting; + aCurrentCompatSettings[j].Value >>= aCompatSetting; + + OUString sName; + OUString sUri; + OUString sVal; + + for ( sal_Int32 k = 0; k < aCompatSetting.getLength(); ++k ) + { + if ( aCompatSetting[k].Name == "name" ) aCompatSetting[k].Value >>= sName; + if ( aCompatSetting[k].Name == "uri" ) aCompatSetting[k].Value >>= sUri; + if ( aCompatSetting[k].Name == "val" ) aCompatSetting[k].Value >>= sVal; + } + + if ( sName == "compatibilityMode" && sUri == "http://schemas.microsoft.com/office/word" ) + { + return sVal.toInt32(); + } + } + } + } + } + + return -1; // Word compatibility mode not found +} + } void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) @@ -3428,17 +3473,24 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pJcVal = "left"; else pJcVal = "start"; - nIndent = sal_Int32( pTableFormat->GetLRSpace( ).GetLeft( ) ); + nIndent = sal_Int32( pTableFormat->GetLRSpace().GetLeft() ); + // Table indentation has different meaning in Word, depending if the table is nested or not. // If nested, tblInd is added to parent table's left spacing and defines left edge position // If not nested, text position of left-most cell must be at absolute X = tblInd // so, table_spacing + table_spacing_to_content = tblInd - if (m_tableReference->m_nTableDepth == 0) + + // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables; + // this is also the default behavior in LO when DOCX doesn't define "compatibilityMode" option + sal_Int32 nMode = lcl_getWordCompatibilityMode( *m_rExport.m_pDoc ); + + if ( nMode > 0 && nMode <= 14 && m_tableReference->m_nTableDepth == 0 ) { - const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); - const SwFrameFormat * pFrameFormat = pTabBox->GetFrameFormat(); - nIndent += sal_Int32( pFrameFormat->GetBox( ).GetDistance( SvxBoxItemLine::LEFT ) ); + const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwFrameFormat* pFrameFormat = pTabBox->GetFrameFormat(); + nIndent += sal_Int32( pFrameFormat->GetBox().GetDistance( SvxBoxItemLine::LEFT ) ); } + break; } } diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx index c4d26e514429..8fa604a3710c 100644 --- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -313,6 +313,34 @@ void lcl_DecrementHoriOrientPosition(std::vector<beans::PropertyValue>& rFramePr } } +sal_Int32 lcl_getWordCompatibilityMode( const css::uno::Sequence< css::beans::PropertyValue >& rCompatSettings ) +{ + for ( int i = 0; i < rCompatSettings.getLength(); ++i ) + { + const css::beans::PropertyValue& rProp = rCompatSettings[i]; + if ( rProp.Name == "compatSetting" ) + { + css::uno::Sequence< css::beans::PropertyValue > aCurrentCompatSettings; + rProp.Value >>= aCurrentCompatSettings; + + OUString sName; + OUString sUri; + OUString sVal; + + aCurrentCompatSettings[0].Value >>= sName; + aCurrentCompatSettings[1].Value >>= sUri; + aCurrentCompatSettings[2].Value >>= sVal; + + if ( sName == "compatibilityMode" && sUri == "http://schemas.microsoft.com/office/word" ) + { + return sVal.toInt32(); + } + } + } + + return -1; // Word compatibility mode not found +} + TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo, std::vector<beans::PropertyValue>& rFrameProperties) { // will receive the table style if any @@ -546,13 +574,18 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo // - top level tables: the goal is to have in-cell text starting at table indent pos (tblInd), // so table's position depends on table's cells margin // - nested tables: the goal is to have left-most border starting at table_indent pos - if (rInfo.nNestLevel > 1) + + // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables; + // this is also the default behavior in LO when DOCX doesn't define "compatibilityMode" option + sal_Int32 nMode = lcl_getWordCompatibilityMode( m_rDMapper_Impl.GetSettingsTable()->GetCompatSettings() ); + + if ( nMode > 0 && nMode <= 14 && rInfo.nNestLevel == 1 ) { - m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf )); + m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf - rInfo.nLeftBorderDistance ) ); } else { - m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf - rInfo.nLeftBorderDistance )); + m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf ) ); } m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth ); |