Rebased ref, commits from common ancestor: commit c69681e4b4797c4976160c46efe06beb4df4af5d Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Wed Oct 14 15:21:24 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:14:34 2020 +0200
sw: fix unsorted redlines in SwTable::ConvertSubtableBox() ooo12626-10.odt asserts because MoveNodeRange() handles redlines only with an explicit flag. (regression from e366c928819c44b5c253c45dca6dae40b71c9808) Change-Id: I80c6e696e51c6d9c366af30ecf8b6df265d0fc91 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104286 Reviewed-by: Michael Stahl <michael.st...@cib.de> Tested-by: Jenkins (cherry picked from commit 48a76ea268b4c7fe499abe858074420dd7b152e2) diff --git a/sw/source/core/table/swnewtable.cxx b/sw/source/core/table/swnewtable.cxx index 892b31e807cc..918ba94fcfea 100644 --- a/sw/source/core/table/swnewtable.cxx +++ b/sw/source/core/table/swnewtable.cxx @@ -2200,7 +2200,7 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) #if 0 pDoc->GetNodes().MoveNodes(content, pDoc->GetNodes(), insPos, false); #else - pDoc->getIDocumentContentOperations().MoveNodeRange(content, insPos, SwMoveFlags::NO_DELFRMS); + pDoc->getIDocumentContentOperations().MoveNodeRange(content, insPos, SwMoveFlags::NO_DELFRMS|SwMoveFlags::REDLINES); #endif // delete the empty node that was bundled in the new box pDoc->GetNodes().Delete(insPos); commit 42db7c8086abb205dbdcf6b44dcd5377866425e0 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Oct 1 17:31:21 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:32 2020 +0200 sw: ODF import: convert the simplest sub-tables to rowspan tables Before OOo 2.3, CWS swnewtable, Writer represented complex table structures as sub-tables, i.e. <table:table table:is-sub-table="true">. Try to convert these to the modern rowspan tables, which export to non-ODF formats much easier. There are some cases where the result is going to look different, or where further work is required to adapt other things in the document; leave these alone for now. Change-Id: I6a6c497089ef886826484d2d723bf57c72f95b14 diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx index a373f561704f..b62c2567e2de 100644 --- a/sw/inc/swtable.hxx +++ b/sw/inc/swtable.hxx @@ -168,6 +168,7 @@ private: void AdjustWidths( const long nOld, const long nNew ); void NewSetTabCols( Parm &rP, const SwTabCols &rNew, const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly ); + void ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox); public: @@ -340,6 +341,9 @@ public: #endif bool HasLayout() const; + + bool CanConvertSubtables() const; + void ConvertSubtables(); }; /// SwTableLine is one table row in the document model. diff --git a/sw/source/core/table/swnewtable.cxx b/sw/source/core/table/swnewtable.cxx index 04a2509b1e37..892b31e807cc 100644 --- a/sw/source/core/table/swnewtable.cxx +++ b/sw/source/core/table/swnewtable.cxx @@ -21,6 +21,7 @@ #include <tblsel.hxx> #include <tblrwcl.hxx> #include <ndtxt.hxx> +#include <ndole.hxx> #include <node.hxx> #include <UndoTable.hxx> #include <pam.hxx> @@ -30,8 +31,14 @@ #include <fmtfsize.hxx> #include <doc.hxx> #include <IDocumentUndoRedo.hxx> +#include <IDocumentChartDataProviderAccess.hxx> #include <IDocumentContentOperations.hxx> +#include <IDocumentFieldsAccess.hxx> #include <IDocumentLayoutAccess.hxx> +#include <IDocumentMarkAccess.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <fmtfld.hxx> +#include <ftnidx.hxx> #include <cstdlib> #include <vector> #include <set> @@ -2089,6 +2096,286 @@ void SwTable::CleanUpBottomRowSpan( sal_uInt16 nDelLines ) } } +/** + This is kind of similar to InsertSpannedRow()/InsertRow() but that one would + recursively copy subtables, which would kind of defeat the purpose; + this function directly moves the subtable rows's cells into the newly + created rows. For the non-subtable boxes, covered-cells are created. + + Outer row heights are adjusted to match the inner row heights, and the + last row's height is tweaked to ensure the sum of the heights is at least + the original outer row's minimal height. + + Inner row backgrounds are copied to its cells, if they lack a background. + + This currently can't handle more than 1 subtable in a row; + the inner rows of all subtables would need to be sorted by their height + to create the correct outer row structure, which is tricky and probably + requires a layout for the typical variable-height case. + + */ +void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) +{ + SwDoc *const pDoc(GetFrameFormat()->GetDoc()); + SwTableLine *const pSourceLine(GetTabLines()[nRow]); + SwTableBox *const pSubTableBox(pSourceLine->GetTabBoxes()[nBox]); + assert(!pSubTableBox->GetTabLines().empty()); + // are relative (%) heights possible? apparently not + SwFormatFrameSize const outerSize(pSourceLine->GetFrameFormat()->GetFrameSize()); + long minHeights(0); + { + SwFormatFrameSize const* pSize(nullptr); + SwFrameFormat const& rSubLineFormat(*pSubTableBox->GetTabLines()[0]->GetFrameFormat()); + if (rSubLineFormat.GetItemState(RES_FRM_SIZE, true, + reinterpret_cast<SfxPoolItem const**>(&pSize)) == SfxItemState::SET) + { // for first row, apply height from inner row to outer row. + // in case the existing outer row height was larger than the entire + // subtable, the last inserted row needs to be tweaked (below) + pSourceLine->GetFrameFormat()->SetFormatAttr(*pSize); + if (pSize->GetHeightSizeType() != ATT_VAR_SIZE) + { + minHeights += pSize->GetHeight(); + } + } + } + for (size_t i = 1; i < pSubTableBox->GetTabLines().size(); ++i) + { + SwTableLine *const pSubLine(pSubTableBox->GetTabLines()[i]); + SwTableLine *const pNewLine = new SwTableLine( + static_cast<SwTableLineFormat*>(pSourceLine->GetFrameFormat()), + pSourceLine->GetTabBoxes().size() - 1 + pSubLine->GetTabBoxes().size(), + nullptr); + SwFrameFormat const& rSubLineFormat(*pSubLine->GetFrameFormat()); + SwFormatFrameSize const* pSize(nullptr); + if (rSubLineFormat.GetItemState(RES_FRM_SIZE, true, + reinterpret_cast<SfxPoolItem const**>(&pSize)) == SfxItemState::SET) + { // for rows 2..N, copy inner row height to outer row + pNewLine->ClaimFrameFormat(); + pNewLine->GetFrameFormat()->SetFormatAttr(*pSize); + if (pSize->GetHeightSizeType() != ATT_VAR_SIZE) + { + minHeights += pSize->GetHeight(); + } + } + // ensure the sum of the lines is at least as high as the outer line was + if (i == pSubTableBox->GetTabLines().size() - 1 + && outerSize.GetHeightSizeType() != ATT_VAR_SIZE + && minHeights < outerSize.GetHeight()) + { + SwFormatFrameSize lastSize(pNewLine->GetFrameFormat()->GetFrameSize()); + lastSize.SetHeight(lastSize.GetHeight() + outerSize.GetHeight() - minHeights); + if (lastSize.GetHeightSizeType() == ATT_VAR_SIZE) + { + lastSize.SetHeightSizeType(ATT_MIN_SIZE); + } + pNewLine->GetFrameFormat()->SetFormatAttr(lastSize); + } + SfxPoolItem const* pRowBrush(nullptr); + rSubLineFormat.GetItemState(RES_BACKGROUND, true, &pRowBrush); + GetTabLines().insert(GetTabLines().begin() + nRow + i, pNewLine); + for (size_t j = 0; j < pSourceLine->GetTabBoxes().size(); ++j) + { + if (j == nBox) + { + for (size_t k = 0; k < pSubLine->GetTabBoxes().size(); ++k) + { + // move box k to new outer row + SwTableBox *const pSourceBox(pSubLine->GetTabBoxes()[k]); + assert(pSourceBox->getRowSpan() == 1); + // import filter (xmltbli.cxx) converts all box widths to absolute + assert(pSourceBox->GetFrameFormat()->GetFrameSize().GetWidthPercent() == 0); + ::InsTableBox(pDoc, GetTableNode(), pNewLine, + static_cast<SwTableBoxFormat*>(pSourceBox->GetFrameFormat()), + pSourceBox, j+k, 1); + // insert dummy text node... + pDoc->GetNodes().MakeTextNode( + SwNodeIndex(*pSourceBox->GetSttNd(), +1), + pDoc->GetDfltTextFormatColl()); + SwNodeRange content(*pSourceBox->GetSttNd(), +2, + *pSourceBox->GetSttNd()->EndOfSectionNode()); + SwTableBox *const pNewBox(pNewLine->GetTabBoxes()[j+k]); + SwNodeIndex insPos(*pNewBox->GetSttNd(), 1); + // MoveNodes would delete the box SwStartNode/SwEndNode + // without the dummy node +#if 0 + pDoc->GetNodes().MoveNodes(content, pDoc->GetNodes(), insPos, false); +#else + pDoc->getIDocumentContentOperations().MoveNodeRange(content, insPos, SwMoveFlags::NO_DELFRMS); +#endif + // delete the empty node that was bundled in the new box + pDoc->GetNodes().Delete(insPos); + if (pRowBrush) + { + SfxPoolItem const* pCellBrush(nullptr); + if (pNewBox->GetFrameFormat()->GetItemState(RES_BACKGROUND, true, &pCellBrush) != SfxItemState::SET) + { // set inner row background on inner cell + pNewBox->ClaimFrameFormat(); + pNewBox->GetFrameFormat()->SetFormatAttr(*pRowBrush); + } + } + // assume that the borders can be left as they are, because + // lines don't have borders, only boxes do + } + } + else + { + // insert covered cell for box j + SwTableBox *const pSourceBox(pSourceLine->GetTabBoxes()[j]); + assert(pSourceBox->GetTabLines().empty()); // checked for that + sal_uInt16 const nInsPos(j < nBox ? j : j + pSubLine->GetTabBoxes().size() - 1); + ::InsTableBox(pDoc, GetTableNode(), pNewLine, + static_cast<SwTableBoxFormat*>(pSourceBox->GetFrameFormat()), + pSourceBox, nInsPos, 1); + // adjust row span: + // N rows in subtable, N-1 rows inserted: + // -1 -> -N ; -(N-1) ... -1 + // -2 -> -(N+1) ; -N .. -2 + // 1 -> N ; -(N-1) .. -1 + // 2 -> N+1 ; -N .. -2 + long newSourceRowSpan(pSourceBox->getRowSpan()); + long newBoxRowSpan; + if (newSourceRowSpan < 0) + { + newSourceRowSpan -= pSubTableBox->GetTabLines().size() - 1; + newBoxRowSpan = newSourceRowSpan + i; + } + else + { + newSourceRowSpan += pSubTableBox->GetTabLines().size() - 1; + newBoxRowSpan = -(newSourceRowSpan - sal::static_int_cast<long>(i)); + } + pNewLine->GetTabBoxes()[nInsPos]->setRowSpan(newBoxRowSpan); + if (i == pSubTableBox->GetTabLines().size() - 1) + { // only last iteration + pSourceBox->setRowSpan(newSourceRowSpan); + } + } + } + } + // delete inner rows 2..N + while (1 < pSubTableBox->GetTabLines().size()) + { + // careful: the last box deletes pSubLine! + SwTableLine *const pSubLine(pSubTableBox->GetTabLines()[1]); + for (size_t j = pSubLine->GetTabBoxes().size(); 0 < j; --j) + { + SwTableBox *const pBox(pSubLine->GetTabBoxes()[0]); + DeleteBox_(*this, pBox, nullptr, false, false, nullptr); + } + } + // fix row spans in lines preceding nRow + lcl_ChangeRowSpan(*this, pSubTableBox->GetTabLines().size() - 1, nRow - 1, false); + // note: the first line of the inner table remains; caller will call + // GCLines() to remove it +} + +bool SwTable::CanConvertSubtables() const +{ + for (SwTableLine const*const pLine : GetTabLines()) + { + bool haveSubtable(false); + for (SwTableBox const*const pBox : pLine->GetTabBoxes()) + { + if (pBox->IsFormulaOrValueBox() == RES_BOXATR_FORMULA) + { + return false; // no table box formulas yet + } + if (!pBox->GetTabLines().empty()) + { + if (haveSubtable) + { // can't handle 2 subtable in a row yet + return false; + } + haveSubtable = true; + for (SwTableLine const*const pInnerLine : pBox->GetTabLines()) + { + // bitmap row background will look different + SwFrameFormat const& rRowFormat(*pInnerLine->GetFrameFormat()); + std::shared_ptr<SvxBrushItem> pBrush(rRowFormat.makeBackgroundBrushItem()); + assert(pBrush); + if (pBrush->GetGraphicObject() != nullptr) + { + /* TODO: all cells could override this? + for (SwTableBox & rInnerBox : rInnerLine.GetTabBoxes()) + */ + if (1 < pInnerLine->GetTabBoxes().size()) // except if only 1 cell? + { + return false; + } + } + for (SwTableBox const*const pInnerBox : pInnerLine->GetTabBoxes()) + { + if (!pInnerBox->GetTabLines().empty()) + { + return false; // nested subtable :( + } + } + } + } + } + } + // note: fields that refer to table cells may be *outside* the table, + // so the entire document needs to be imported before checking here + // (same for table box formulas and charts) + SwDoc *const pDoc(GetFrameFormat()->GetDoc()); + SwFieldType const*const pTableFields( + pDoc->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Table, "", false)); + SwIterator<SwFormatField, SwFieldType> aIter(*pTableFields); + if (aIter.First() != nullptr) + { + return false; // no formulas in fields yet + } + if (pDoc->GetAttrPool().GetItemCount2(RES_BOXATR_FORMULA) != 0) + { + return false; // no table box formulas yet + } + OUString const tableName(GetFrameFormat()->GetName()); + SwNodeIndex temp(*pDoc->GetNodes().GetEndOfAutotext().StartOfSectionNode(), +1); + while (SwStartNode const*const pStartNode = temp.GetNode().GetStartNode()) + { + ++temp; + SwOLENode const*const pOLENode(temp.GetNode().GetOLENode()); + if (pOLENode && tableName == pOLENode->GetChartTableName()) + { // there are charts that refer to this table + // presumably such charts would need to be adapted somehow? + return false; + } + temp.Assign(*pStartNode->EndOfSectionNode(), +1); + } + return true; +} + +void SwTable::ConvertSubtables() +{ + for (size_t i = 0; i < GetTabLines().size(); ++i) + { + SwTableLine *const pLine(GetTabLines()[i]); + for (size_t j = 0; j < pLine->GetTabBoxes().size(); ++j) + { + SwTableBox *const pBox(pLine->GetTabBoxes()[j]); + SwTableLines & rInnerLines(pBox->GetTabLines()); + if (!rInnerLines.empty()) + { + ConvertSubtableBox(i, j); + } + } + } + GCLines(); + m_bNewModel = true; +#if 0 + // note: outline nodes (and ordinary lists) are sorted by MoveNodes() itself + // (this could change order inside table of contents, but that's a + // really esoteric use-case) + // nodes were moved - sort marks, redlines, footnotes + SwDoc *const pDoc(GetFrameFormat()->GetDoc()); + pDoc->getIDocumentMarkAccess()->assureSortedMarkContainers(); + pDoc->getIDocumentRedlineAccess().GetRedlineTable().Resort(); + pDoc->GetFootnoteIdxs().UpdateAllFootnote(); +#endif + // assume that there aren't any node indexes to the deleted box start/end nodes + CHECK_TABLE( *this ) +} + #ifdef DBG_UTIL struct RowSpanCheck diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx index 75766a7f8a64..68a72af1cb2f 100644 --- a/sw/source/filter/xml/xmlimp.cxx +++ b/sw/source/filter/xml/xmlimp.cxx @@ -967,6 +967,22 @@ void SwXMLImport::endDocument() } } +#if 1 + if (!pDoc) { pDoc = SwImport::GetDocFromXMLImport(*this); } + for (sal_uLong i = 0; i < pDoc->GetNodes().Count(); ++i) + { + if (SwTableNode *const pTableNode = pDoc->GetNodes()[i]->GetTableNode()) + { + if (!pTableNode->GetTable().IsNewModel() + && pTableNode->GetTable().CanConvertSubtables()) + { + pTableNode->GetTable().ConvertSubtables(); + } + } + // don't skip to the end; nested tables could have subtables too... + } +#endif + // delegate to parent: takes care of error handling SvXMLImport::endDocument(); ClearTextImport(); commit 1bb8842f8c1f8bd12a3b9e6a99c037579654d2cd Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Oct 1 17:29:06 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:32 2020 +0200 sw: SwTable::GCLines(): don't throw away row background If there's a row background, and a cell in the row doesn't override it, apply the row background to the cell. Change-Id: I37cd33249d3ab66c898c537e3bc6bab067d6f74b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103772 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit e65b1ba0033e1adaa4135539bb7b34b28cbedd7c) diff --git a/sw/source/core/doc/gctable.cxx b/sw/source/core/doc/gctable.cxx index 493ef4248c91..1d5a2a4eed25 100644 --- a/sw/source/core/doc/gctable.cxx +++ b/sw/source/core/doc/gctable.cxx @@ -351,6 +351,21 @@ static bool lcl_MergeGCBox(SwTableBox* pTableBox, GCLinePara* pPara) for( auto pTabBox : pCpyLine->GetTabBoxes() ) pTabBox->SetUpper( pInsLine ); + SfxPoolItem const* pRowBrush(nullptr); + pCpyLine->GetFrameFormat()->GetItemState(RES_BACKGROUND, true, &pRowBrush); + if (pRowBrush) + { + for (auto pBox : pCpyLine->GetTabBoxes()) + { + SfxPoolItem const* pCellBrush(nullptr); + if (pBox->GetFrameFormat()->GetItemState(RES_BACKGROUND, true, &pCellBrush) != SfxItemState::SET) + { // set inner row background on inner cell + pBox->ClaimFrameFormat(); + pBox->GetFrameFormat()->SetFormatAttr(*pRowBrush); + } + } + } + // remove the old box from its parent line it = pInsLine->GetTabBoxes().erase( it ); // insert the nested line's boxes in its place commit 0352089409859b0017a877b26d1c8590f8a4e5f1 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Oct 1 17:26:43 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:32 2020 +0200 sw: improve comments, dump rowspan to nodes.xml Change-Id: Ifcd011f6d55ac534c449050d07009680dcd71d51 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103771 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit 309868c32f00e5ca045f941deafb5216aad2538c) diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx index a0deaf01e892..a373f561704f 100644 --- a/sw/inc/swtable.hxx +++ b/sw/inc/swtable.hxx @@ -310,7 +310,9 @@ public: // Search in format for registered table. static SwTable * FindTable( SwFrameFormat const*const pFormat ); - // Clean up structure a bit. + // Clean up structure of subtables a bit: + // convert row with 1 box with subtable; box with subtable with 1 row; + // by removing the subtable (both recursively) void GCLines(); // Returns the table node via m_TabSortContentBoxes or pTableNode. diff --git a/sw/inc/tblsel.hxx b/sw/inc/tblsel.hxx index 0639db32f72e..cc353cc424bb 100644 --- a/sw/inc/tblsel.hxx +++ b/sw/inc/tblsel.hxx @@ -160,8 +160,8 @@ class FndBox_ FndLines_t m_Lines; FndLine_* const m_pUpper; - SwTableLine *m_pLineBefore; // For deleting/restoring the layout. - SwTableLine *m_pLineBehind; + SwTableLine *m_pLineBefore; ///< For deleting/restoring the layout. + SwTableLine *m_pLineBehind; ///< For deleting/restoring the layout. FndBox_(FndBox_ const&) = delete; FndBox_& operator=(FndBox_ const&) = delete; @@ -224,6 +224,10 @@ struct FndPara : rBoxes(rPara.rBoxes), pFndLine(pFL), pFndBox(rPara.pFndBox) {} }; +/** This creates a structure mirroring the SwTable structure that contains all + rows and non-leaf boxes (as pointers to SwTableBox/SwTableLine, not copies), + plus the leaf boxes that are selected by pFndPara->rBoxes + */ SW_DLLPUBLIC void ForEach_FndLineCopyCol(SwTableLines& rLines, FndPara* pFndPara ); #endif // INCLUDED_SW_INC_TBLSEL_HXX diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx index 955e113f2768..61e8bd112d23 100644 --- a/sw/source/core/docnode/node.cxx +++ b/sw/source/core/docnode/node.cxx @@ -985,6 +985,8 @@ void SwStartNode::dumpAsXml(xmlTextWriterPtr pWriter) const } else if (GetStartNodeType() == SwTableBoxStartNode) { + if (SwTableBox* pBox = GetTableBox()) + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("rowspan"), BAD_CAST(OString::number(pBox->getRowSpan()).getStr())); xmlTextWriterStartElement(pWriter, BAD_CAST("attrset")); if (SwTableBox* pBox = GetTableBox()) pBox->GetFrameFormat()->GetAttrSet().dumpAsXml(pWriter); commit f208469414f0f8823fe8003fd0e4c78b3c51bb02 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Sep 18 11:47:56 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:32 2020 +0200 tdf#136620 tdf#136708 filter,oox,sw: fix export of 2 different wraps This reverts commit 2cb90a5c87fe46737c8d840967d8836284f92ffd. Revert the change to EscherPropertyContainer, which was completely bogus, based on pre-existing bogus code in VMLExport::Commit(). The problem is that ESCHER_Wrap values are for wrapping text *inside* a text box, which is "mso-wrap-style" in VML, whereas VML's w10:wrap element defines how text wraps *around* a shape, doesn't exist as an ESCHER property and is specific to Word formats. Instead, export the w10:wrap element in VMLExport::EndShape(). This has 2 callers, WriteActiveXControl() and writeVMLDrawing(). Furthermore the value "none" wasn't written for WrapTextMode_THROUGH, which caused the wrap element to be omitted in that case. Change-Id: Id4a01fcb2ea73fa9bef4ee8769b5e0680e059f15 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103009 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit fdc8590032b292dcb8152b328401e591fea642a4) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103090 Reviewed-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit c54d697e2ac379d4b1a3ff5acb6f06bff30cadd6) diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx index a2071237deb7..f04043e9156a 100644 --- a/filter/source/msfilter/escherex.cxx +++ b/filter/source/msfilter/escherex.cxx @@ -66,7 +66,6 @@ #include <com/sun/star/drawing/FlagSequence.hpp> #include <com/sun/star/drawing/PolygonFlags.hpp> #include <com/sun/star/text/WritingMode.hpp> -#include <com/sun/star/text/WrapTextMode.hpp> #include <com/sun/star/drawing/TextVerticalAdjust.hpp> #include <com/sun/star/drawing/TextHorizontalAdjust.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> @@ -700,10 +699,6 @@ void EscherPropertyContainer::CreateTextProperties( bool bWordWrap ( false ); bool bAutoGrowSize ( false ); - uno::Any aTextWrap; - - EscherPropertyValueHelper::GetPropertyValue(aTextWrap, rXPropSet, "TextWrap", true); - if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWritingMode", true ) ) aAny >>= eWM; if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextVerticalAdjust", true ) ) @@ -842,21 +837,6 @@ void EscherPropertyContainer::CreateTextProperties( nTextAttr |= 0x20002; } } - - if (aTextWrap.hasValue()) - { // explicit text wrap overrides whatever was inferred previously - switch (aTextWrap.get<text::WrapTextMode>()) - { - case text::WrapTextMode_THROUGH: - eWrapMode = ESCHER_WrapNone; - break; - // in theory there are 3 more Escher_Wrap, but [MS-ODRAW] says they are useless - default: - eWrapMode = ESCHER_WrapSquare; - break; - } - } - AddOpt( ESCHER_Prop_dxTextLeft, nLeft * 360 ); AddOpt( ESCHER_Prop_dxTextRight, nRight * 360 ); AddOpt( ESCHER_Prop_dyTextTop, nTop * 360 ); diff --git a/include/oox/export/vmlexport.hxx b/include/oox/export/vmlexport.hxx index 7c2d3a62da6f..3736420756a6 100644 --- a/include/oox/export/vmlexport.hxx +++ b/include/oox/export/vmlexport.hxx @@ -80,8 +80,9 @@ class OOX_DLLPUBLIC VMLExport : public EscherEx /// Parent exporter, used for text callback. VMLTextExport* m_pTextExport; - /// Anchoring. + /// Anchoring - Writer specific properties sal_Int16 m_eHOri, m_eVOri, m_eHRel, m_eVRel; + std::unique_ptr<sax_fastparser::FastAttributeList> m_pWrapAttrList; bool m_bInline; // css::text::TextContentAnchorType_AS_CHARACTER /// The object we're exporting. @@ -139,7 +140,9 @@ public: /// Call this when you need to export the object as VML. OString const & AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri = -1, sal_Int16 eVOri = -1, sal_Int16 eHRel = -1, - sal_Int16 eVRel = -1, const bool bOOxmlExport = false ); + sal_Int16 eVRel = -1, + std::unique_ptr<sax_fastparser::FastAttributeList> m_pWrapAttrList = nullptr, + const bool bOOxmlExport = false ); OString const & AddInlineSdrObject( const SdrObject& rObj, const bool bOOxmlExport ); virtual void AddSdrObjectVMLObject( const SdrObject& rObj) override; static bool IsWaterMarkShape(const OUString& rStr); diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index ee93cf32bd27..2009d9ccf055 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -421,11 +421,15 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& case ESCHER_WrapSquare: case ESCHER_WrapByPoints: pWrapType = "square"; break; // these two are equivalent according to the docu case ESCHER_WrapNone: pWrapType = "none"; break; - case ESCHER_WrapTopBottom: pWrapType = "topAndBottom"; break; - case ESCHER_WrapThrough: pWrapType = "through"; break; + case ESCHER_WrapTopBottom: + case ESCHER_WrapThrough: + break; // last two are *undefined* in MS-ODRAW, don't exist in VML } if ( pWrapType ) - m_pSerializer->singleElementNS(XML_w10, XML_wrap, XML_type, pWrapType); + { + m_ShapeStyle.append(";mso-wrap-style:"); + m_ShapeStyle.append(pWrapType); + } } bAlreadyWritten[ ESCHER_Prop_WrapText ] = true; break; @@ -1477,18 +1481,27 @@ void VMLExport::EndShape( sal_Int32 nShapeElement ) m_pSerializer->endElementNS(XML_v, XML_textbox); } + if (m_pWrapAttrList) + { + sax_fastparser::XFastAttributeListRef const pWrapAttrList(m_pWrapAttrList.release()); + m_pSerializer->singleElementNS(XML_w10, XML_wrap, pWrapAttrList); + } + // end of the shape m_pSerializer->endElementNS( XML_v, nShapeElement ); } } -OString const & VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, const bool bOOxmlExport ) +OString const & VMLExport::AddSdrObject( const SdrObject& rObj, sal_Int16 eHOri, sal_Int16 eVOri, sal_Int16 eHRel, sal_Int16 eVRel, + std::unique_ptr<FastAttributeList> pWrapAttrList, + const bool bOOxmlExport ) { m_pSdrObject = &rObj; m_eHOri = eHOri; m_eVOri = eVOri; m_eHRel = eHRel; m_eVRel = eVRel; + m_pWrapAttrList = std::move(pWrapAttrList); m_bInline = false; EscherEx::AddSdrObject(rObj, bOOxmlExport); return m_sShapeId; @@ -1501,6 +1514,7 @@ OString const & VMLExport::AddInlineSdrObject( const SdrObject& rObj, const bool m_eVOri = -1; m_eHRel = -1; m_eVRel = -1; + m_pWrapAttrList.reset(); m_bInline = true; EscherEx::AddSdrObject(rObj, bOOxmlExport); return m_sShapeId; diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index 4a4656f57a94..58a4045cd7dd 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -59,6 +59,8 @@ #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> #include <com/sun/star/chart2/XChartTypeContainer.hpp> #include <com/sun/star/chart2/XChartDocument.hpp> + +#include <sax/fastattribs.hxx> #include <oox/token/tokens.hxx> #include <oox/token/namespaces.hxx> #include <oox/token/relationship.hxx> diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 4256c8cf9cba..270ab6fe964f 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -5347,10 +5347,14 @@ void DocxAttributeOutput::WriteActiveXControl(const SdrObject* pObject, const Sw { const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient(); const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient(); + SwFormatSurround const& rSurround(rFrameFormat.GetSurround()); + std::unique_ptr<sax_fastparser::FastAttributeList> pAttrList(docx::SurroundToVMLWrap(rSurround)); sShapeId = m_rExport.VMLExporter().AddSdrObject(*pObject, rHoriOri.GetHoriOrient(), rVertOri.GetVertOrient(), rHoriOri.GetRelationOrient(), - rVertOri.GetRelationOrient(), true); + rVertOri.GetRelationOrient(), + std::move(pAttrList), + true); } // Restore default values m_rExport.VMLExporter().SetSkipwzName(false); @@ -8352,43 +8356,64 @@ void DocxAttributeOutput::FormatULSpace( const SvxULSpaceItem& rULSpace ) } } -void DocxAttributeOutput::FormatSurround( const SwFormatSurround& rSurround ) +namespace docx { + +std::unique_ptr<FastAttributeList> SurroundToVMLWrap(SwFormatSurround const& rSurround) { - if (m_rExport.SdrExporter().getTextFrameSyntax()) + FastAttributeList * pAttrList(nullptr); + OString sType; + OString sSide; + switch (rSurround.GetSurround()) + { + case css::text::WrapTextMode_NONE: + sType = "topAndBottom"; + break; + case css::text::WrapTextMode_PARALLEL: + sType = "square"; + break; + case css::text::WrapTextMode_DYNAMIC: + sType = "square"; + sSide = "largest"; + break; + case css::text::WrapTextMode_LEFT: + sType = "square"; + sSide = "left"; + break; + case css::text::WrapTextMode_RIGHT: + sType = "square"; + sSide = "right"; + break; + case css::text::WrapTextMode_THROUGH: + /* empty type and side means through */ + default: + sType = "none"; + break; + } + if (!sType.isEmpty() || !sSide.isEmpty()) { - OString sType, sSide; - switch (rSurround.GetSurround()) + pAttrList = FastSerializerHelper::createAttrList(); + if (!sType.isEmpty()) { - case css::text::WrapTextMode_NONE: - sType = "topAndBottom"; - break; - case css::text::WrapTextMode_PARALLEL: - sType = "square"; - break; - case css::text::WrapTextMode_DYNAMIC: - sType = "square"; - sSide = "largest"; - break; - case css::text::WrapTextMode_LEFT: - sType = "square"; - sSide = "left"; - break; - case css::text::WrapTextMode_RIGHT: - sType = "square"; - sSide = "right"; - break; - case css::text::WrapTextMode_THROUGH: - /* empty type and side means through */ - default: - break; + pAttrList->add(XML_type, sType); + } + if (!sSide.isEmpty()) + { + pAttrList->add(XML_side, sSide); } - if (!sType.isEmpty() || !sSide.isEmpty()) + } + return std::unique_ptr<FastAttributeList>(pAttrList); +} + +} // namespace docx + +void DocxAttributeOutput::FormatSurround( const SwFormatSurround& rSurround ) +{ + if (m_rExport.SdrExporter().getTextFrameSyntax()) + { + std::unique_ptr<FastAttributeList> pAttrList(docx::SurroundToVMLWrap(rSurround)); + if (pAttrList) { - m_rExport.SdrExporter().setFlyWrapAttrList(FastSerializerHelper::createAttrList()); - if (!sType.isEmpty()) - m_rExport.SdrExporter().getFlyWrapAttrList()->add(XML_type, sType); - if (!sSide.isEmpty()) - m_rExport.SdrExporter().getFlyWrapAttrList()->add(XML_side, sSide); + m_rExport.SdrExporter().setFlyWrapAttrList(pAttrList.release()); } } else if (m_rExport.SdrExporter().getDMLTextFrameSyntax()) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 2b6e83dde2d6..b04ad82cff7e 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -1045,6 +1045,12 @@ struct DocxTableExportContext ~DocxTableExportContext() { m_rOutput.popFromTableExportContext(*this); } }; +namespace docx { + +std::unique_ptr<sax_fastparser::FastAttributeList> SurroundToVMLWrap(SwFormatSurround const& rSurround); + +} + #endif // INCLUDED_SW_SOURCE_FILTER_WW8_DOCXATTRIBUTEOUTPUT_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx index b86c64daeb24..a1f8b7b2f5be 100644 --- a/sw/source/filter/ww8/docxsdrexport.cxx +++ b/sw/source/filter/ww8/docxsdrexport.cxx @@ -827,9 +827,13 @@ void DocxSdrExport::writeVMLDrawing(const SdrObject* sdrObj, const SwFrameFormat const SwFormatHoriOrient& rHoriOri = rFrameFormat.GetHoriOrient(); const SwFormatVertOrient& rVertOri = rFrameFormat.GetVertOrient(); + SwFormatSurround const& rSurround(rFrameFormat.GetSurround()); + + std::unique_ptr<sax_fastparser::FastAttributeList> pAttrList( + docx::SurroundToVMLWrap(rSurround)); m_pImpl->getExport().VMLExporter().AddSdrObject( *sdrObj, rHoriOri.GetHoriOrient(), rVertOri.GetVertOrient(), rHoriOri.GetRelationOrient(), - rVertOri.GetRelationOrient(), true); + rVertOri.GetRelationOrient(), std::move(pAttrList), true); m_pImpl->getSerializer()->endElementNS(XML_w, XML_pict); } commit dd551398fce0a5f0fb604427a49b086b561b0f70 Author: Samuel Mehrbrodt <samuel.mehrbr...@cib.de> AuthorDate: Thu Sep 10 09:45:08 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:32 2020 +0200 .gitreview: Update default branch Change-Id: Ifcbcd3427508b468a9f1872b563c93760854becf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102364 Tested-by: Samuel Mehrbrodt <samuel.mehrbr...@cib.de> Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@cib.de> diff --git a/.gitreview b/.gitreview index 4cd7d22d9a83..2bbb2f4856f3 100644 --- a/.gitreview +++ b/.gitreview @@ -3,5 +3,4 @@ host=gerrit.libreoffice.org port=29418 project=core defaultremote=logerrit -defaultbranch=libreoffice-6-4 - +defaultbranch=feature/cib_contract3753 commit 9969b1a2a07aa28022050aa96365051f15cb669b Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Wed Aug 26 17:08:00 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 sw: DOCX export: don't export text frames as transparent Writer paints text frames without fill still as opaque but nothing is written in the DOCX file and Word by default treats DrawingML text frame as transparent (the VML fallback is opaque though). Change-Id: I0ce539ac8084c5047b4732abc5c199589ee369ee diff --git a/sw/qa/extras/ooxmlexport/data/frame.fodt b/sw/qa/extras/ooxmlexport/data/frame.fodt new file mode 100644 index 000000000000..c474b8de5e9e --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/frame.fodt @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:d r3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Lohit Devanagari" svg:font-family="'Lohit Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Source Han Serif CN" svg:font-family="'Source Han Serif CN'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="Frame_20_contents" style:display-name="Frame contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"/> + <style:style style:name="Frame" style:family="graphic"> + <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" fo:margin-left="0.201cm" fo:margin-right="0.201cm" fo:margin-top="0.201cm" fo:margin-bottom="0.201cm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:padding="0.15cm" fo:border="0.06pt solid #000000"/> + </style:style> + + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Frame"> + <style:graphic-properties style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:opacity="0%" draw:wrap-influence-on-position="once-concurrent"/> + </style:style> + <style:style style:name="fr2" style:family="graphic" style:parent-style-name="Frame"> + <style:graphic-properties style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" fo:background-color="#e8f2a1" draw:fill="solid" draw:fill-color="#e8f2a1" draw:wrap-influence-on-position="once-concurrent"/> + </style:style> + <style:style style:name="fr3" style:family="graphic" style:parent-style-name="Frame"> + <style:graphic-properties style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:p text:style-name="Standard"><draw:frame draw:style-name="fr3" draw:name="Frame1" text:anchor-type="paragraph" svg:x="0.87cm" svg:y="0cm" svg:width="2cm" draw:z-index="0"> + <draw:text-box fo:min-height="0.499cm"> + <text:p text:style-name="Frame_20_contents">opaque</text:p> + </draw:text-box> + </draw:frame><draw:frame draw:style-name="fr2" draw:name="Frame2" text:anchor-type="paragraph" svg:x="3.069cm" svg:y="0cm" svg:width="2cm" draw:z-index="1"> + <draw:text-box fo:min-height="0.499cm"> + <text:p text:style-name="Frame_20_contents">solid</text:p> + </draw:text-box> + </draw:frame><draw:frame draw:style-name="fr1" draw:name="Frame3" text:anchor-type="paragraph" svg:x="5.33cm" svg:y="0cm" svg:width="2.281cm" draw:z-index="2"> + <draw:text-box fo:min-height="0.499cm"> + <text:p text:style-name="Frame_20_contents">transparent</text:p> + </draw:text-box> + </draw:frame></text:p> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx index a8fe7ac73ea0..4318856bdae2 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx @@ -142,6 +142,29 @@ DECLARE_OOXMLEXPORT_TEST(testDMLSolidfillAlpha, "dml-solidfill-alpha.docx") CPPUNIT_ASSERT_EQUAL(sal_Int16(20), getProperty<sal_Int16>(xShape, "FillTransparence")); } +DECLARE_OOXMLEXPORT_TEST(testDMLTextFrameNoFill, "frame.fodt") +{ + // Problem is that default text frame background is white in Writer and transparent in Word + uno::Reference<beans::XPropertySet> xShape1(getShape(1), uno::UNO_QUERY); +// it is re-imported as solid +// CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(xShape1, "FillStyle")); + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, getProperty<drawing::FillStyle>(xShape1, "FillStyle")); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xShape1, "FillTransparence")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xffffff), getProperty<sal_Int32>(xShape1, "FillColor")); + + uno::Reference<beans::XPropertySet> xShape2(getShape(2), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, getProperty<drawing::FillStyle>(xShape2, "FillStyle")); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xShape2, "FillTransparence")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xE8F2A1), getProperty<sal_Int32>(xShape2, "FillColor")); + + uno::Reference<beans::XPropertySet> xShape3(getShape(3), uno::UNO_QUERY); +// it is re-imported as solid +// CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(xShape3, "FillStyle")); + CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_SOLID, getProperty<drawing::FillStyle>(xShape3, "FillStyle")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0xffffff), getProperty<sal_Int32>(xShape3, "FillColor")); + CPPUNIT_ASSERT_EQUAL(sal_Int16(100), getProperty<sal_Int16>(xShape3, "FillTransparence")); +} + DECLARE_OOXMLEXPORT_TEST(testDMLCustomGeometry, "dml-customgeometry-cubicbezier.docx") { diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx index 3d8daa633daa..38cd3f8893b3 100644 --- a/sw/source/filter/ww8/attributeoutputbase.hxx +++ b/sw/source/filter/ww8/attributeoutputbase.hxx @@ -668,6 +668,8 @@ public: ( ww8::WW8TableNodeInfoInner const * pTableTextNodeInfoInner, long& rPageSize, bool& rRelBoxSize ); + virtual void MaybeOutputBrushItem(SfxItemSet const&) { } + /// Exports the definition (image, size) of a single numbering picture bullet. virtual void BulletDefinition(int /*nId*/, const Graphic& /*rGraphic*/, Size /*aSize*/) {} diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index c03d971e8fdc..4256c8cf9cba 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -90,9 +90,11 @@ #include <editeng/editobj.hxx> #include <editeng/keepitem.hxx> #include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> #include <svx/xflgrit.hxx> #include <svx/fmglob.hxx> #include <svx/svdouno.hxx> +#include <svx/unobrushitemhelper.hxx> #include <svl/grabbagitem.hxx> #include <sfx2/sfxbasemodel.hxx> #include <tools/datetimeutils.hxx> @@ -5822,6 +5824,27 @@ oox::drawingml::DrawingML& DocxAttributeOutput::GetDrawingML() return m_rDrawingML; } +void DocxAttributeOutput::MaybeOutputBrushItem(SfxItemSet const& rSet) +{ + const XFillStyleItem* pXFillStyleItem(rSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE)); + + if ((pXFillStyleItem && pXFillStyleItem->GetValue() != drawing::FillStyle_NONE) + || !m_rExport.SdrExporter().getDMLTextFrameSyntax()) + { + return; + } + + // sw text frames are opaque by default, even with fill none! + std::unique_ptr<SfxItemSet> const pClone(rSet.Clone()); + XFillColorItem const aColor(OUString(), COL_WHITE); + pClone->Put(aColor); + // call getSvxBrushItemForSolid - this also takes XFillTransparenceItem into account + XFillStyleItem const aSolid(drawing::FillStyle_SOLID); + pClone->Put(aSolid); + auto const pBrush(getSvxBrushItemFromSourceSet(*pClone, RES_BACKGROUND)); + FormatBackground(*pBrush); +} + /// Functor to do case-insensitive ordering of OUString instances. struct OUStringIgnoreCase { @@ -8615,6 +8638,7 @@ void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox ) { if (m_rExport.SdrExporter().getDMLTextFrameSyntax()) { + // ugh, exporting fill here is quite some hack... this OutputItemSet abstraction is quite leaky // <a:gradFill> should be before <a:ln>. const SfxPoolItem* pItem = GetExport().HasItem(XATTR_FILLSTYLE); if (pItem) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index a7733d62209b..2b6e83dde2d6 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -1013,6 +1013,7 @@ public: virtual OUString FindRelId(BitmapChecksum nChecksum) override; virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) override; virtual oox::drawingml::DrawingML& GetDrawingML() override; + virtual void MaybeOutputBrushItem(SfxItemSet const&) override; void BulletDefinition(int nId, const Graphic& rGraphic, Size aSize) override; diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 87d6545d3391..b2c3b35d7ae1 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -332,6 +332,8 @@ void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, b ExportPoolItemsToCHP(aItems, nScript, nullptr); if ( bPapFormat ) { + AttrOutput().MaybeOutputBrushItem(rSet); + for ( const auto& rItem : aItems ) { pItem = rItem.second; @@ -350,6 +352,13 @@ void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, b std::shared_ptr<SvxBrushItem> aBrush(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND)); AttrOutput().OutputItem(*aBrush); } +#if 0 + else + { + // note: *does not work* due to undocumented Word behavior: must be before a:ln element at least + AttrOutput().MaybeOutputBrushItem(rSet); + } +#endif } m_pISet = nullptr; // for double attributes } commit a10fe43af77b877cc2d4a9ce5a1787755f9ce870 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Aug 13 11:07:37 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 sw: DOCX export: for soft-page-breaks, export continuous section breaks When a section break is produced based on layout information such as soft-page-break and follow page style, it's a bad idea to generate a page break because the break may be in a different position in Word, particularly if it was inside a fieldmark instruction. It wouldn't work that well to ignore such page breaks in MSWordExportBase::NeedTextNodeSplit() because then they would be created when reaching the next node anyway, via FindPageDesc() fall-back to layout. Unfortunately this breaks the test tdf113849_evenAndOddHeaders.odt which has a page style with follow-page-style on the first page; on re-import from DOCX, the continuous section is now no longer converted to a page break, so pages 2-3 have the wrong header/footers... this seems impossible to fix in general in the import because it doesn't know whether the continuous section break coincides with a layout page break. Arguably this worked before mostly by accident? tdf#113849 isn't about this afaics... Change the test file to have an explicit page break there, which round-trips as intended. The real fix would be adding continuous page style change to Writer i guess... Change-Id: I00ffe3971607c148a7d5c13b89afb936718611c0 diff --git a/sw/qa/extras/ooxmlexport/data/tdf113849_evenAndOddHeaders.odt b/sw/qa/extras/ooxmlexport/data/tdf113849_evenAndOddHeaders.odt index d9aa0ae23541..ae9b2af14ee7 100644 Binary files a/sw/qa/extras/ooxmlexport/data/tdf113849_evenAndOddHeaders.odt and b/sw/qa/extras/ooxmlexport/data/tdf113849_evenAndOddHeaders.odt differ diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index a212f4e5c9b8..74f06116484a 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -619,7 +619,8 @@ sal_uLong DocxExport::ReplaceCr( sal_uInt8 ) void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc ) + const SwPageDesc* pNewPgDesc, + bool const bViaLayout) { // tell the attribute output that we are ready to write the section // break [has to be output inside paragraph properties] @@ -632,13 +633,12 @@ void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet, if ( pNewPgDescFormat ) { - m_pSections->AppendSection( *pNewPgDescFormat, rNd, pFormat, nLnNm ); + m_pSections->AppendSection(*pNewPgDescFormat, rNd, pFormat, nLnNm, bViaLayout); } else if ( pNewPgDesc ) { - m_pSections->AppendSection( pNewPgDesc, rNd, pFormat, nLnNm ); + m_pSections->AppendSection(pNewPgDesc, rNd, pFormat, nLnNm, bViaLayout); } - } void DocxExport::InitStyles() diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 00b908dc7efa..35e37a98ae39 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -218,7 +218,8 @@ protected: virtual void PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc ) override; + const SwPageDesc* pNewPgDesc, + bool bViaLayout ) override; private: /// Setup pStyles and write styles.xml diff --git a/sw/source/filter/ww8/rtfexport.cxx b/sw/source/filter/ww8/rtfexport.cxx index 366cc18b3b0c..0e8733b48d63 100644 --- a/sw/source/filter/ww8/rtfexport.cxx +++ b/sw/source/filter/ww8/rtfexport.cxx @@ -948,7 +948,7 @@ ErrCode RtfExport::ExportDocument_Impl() void RtfExport::PrepareNewPageDesc(const SfxItemSet* pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc) + const SwPageDesc* pNewPgDesc, bool const) { const SwSectionFormat* pFormat = GetSectionFormat(rNd); const sal_uLong nLnNm = GetSectionLineNo(pSet, rNd); diff --git a/sw/source/filter/ww8/rtfexport.hxx b/sw/source/filter/ww8/rtfexport.hxx index 055aa50ff04e..527574ad701e 100644 --- a/sw/source/filter/ww8/rtfexport.hxx +++ b/sw/source/filter/ww8/rtfexport.hxx @@ -125,8 +125,8 @@ protected: /// Get ready for a new section. void PrepareNewPageDesc(const SfxItemSet* pSet, const SwNode& rNd, - const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc) override; + const SwFormatPageDesc* pNewPgDescFormat, const SwPageDesc* pNewPgDesc, + bool bViaLayout) override; /// Return value indicates if an inherited outline numbering is suppressed. bool DisallowInheritingOutlineNumbering(const SwFormat& rFormat) override; diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 74783f3e7110..dc6abf17899e 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2742,7 +2742,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) // too. const SwPageDesc* pNextPageDesc = m_pCurrentPageDesc->GetFollow(); assert(pNextPageDesc); - PrepareNewPageDesc( rNode.GetpSwAttrSet(), rNode, nullptr , pNextPageDesc); + PrepareNewPageDesc( rNode.GetpSwAttrSet(), rNode, nullptr , pNextPageDesc, true); } } else if (!bNeedParaSplit) diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index eb06b97195bb..e264d51a1ff2 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -1092,12 +1092,13 @@ const WW8_SepInfo* MSWordSections::CurrentSectionInfo() } void MSWordSections::AppendSection( const SwPageDesc* pPd, - const SwSectionFormat* pSectionFormat, sal_uLong nLnNumRestartNo, bool bIsFirstParagraph ) + const SwSectionFormat*const pSectionFormat, sal_uLong const nLnNumRestartNo, + bool const bIsFirstParagraph, bool const bIsContinuous) { if (HeaderFooterWritten()) { return; // #i117955# prevent new sections in endnotes } - aSects.emplace_back( pPd, pSectionFormat, nLnNumRestartNo, boost::none, nullptr, bIsFirstParagraph ); + aSects.emplace_back(pPd, pSectionFormat, nLnNumRestartNo, boost::none, nullptr, bIsFirstParagraph, bIsContinuous); NeedsDocumentProtected( aSects.back() ); } @@ -1112,13 +1113,14 @@ void WW8_WrPlcSepx::AppendSep( WW8_CP nStartCp, const SwPageDesc* pPd, } void MSWordSections::AppendSection( const SwFormatPageDesc& rPD, - const SwNode& rNd, const SwSectionFormat* pSectionFormat, sal_uLong nLnNumRestartNo ) + const SwNode& rNd, const SwSectionFormat*const pSectionFormat, + sal_uLong const nLnNumRestartNo, bool const bIsContinuous) { if (HeaderFooterWritten()) { return; // #i117955# prevent new sections in endnotes } - WW8_SepInfo aI( rPD.GetPageDesc(), pSectionFormat, nLnNumRestartNo, rPD.GetNumOffset(), &rNd ); + WW8_SepInfo aI(rPD.GetPageDesc(), pSectionFormat, nLnNumRestartNo, rPD.GetNumOffset(), &rNd, false, bIsContinuous); aSects.push_back( aI ); NeedsDocumentProtected( aI ); @@ -1548,9 +1550,9 @@ void MSWordExportBase::SectionProperties( const WW8_SepInfo& rSepInfo, WW8_PdAtt /* sprmSBkc, break code: 0 No break, 1 New column 2 New page, 3 Even page, 4 Odd page */ - sal_uInt8 nBreakCode = 2; // default start new page + sal_uInt8 nBreakCode = rSepInfo.isContinuous ? 0 : 2; // default start new page bool bOutPgDscSet = true, bLeftRightPgChain = false, bOutputStyleItemSet = false; - bool bEnsureHeaderFooterWritten = rSepInfo.pSectionFormat && rSepInfo.bIsFirstParagraph; + bool bEnsureHeaderFooterWritten = (rSepInfo.pSectionFormat && rSepInfo.bIsFirstParagraph) || rSepInfo.isContinuous; const SwFrameFormat* pPdFormat = &pPd->GetMaster(); if ( rSepInfo.pSectionFormat ) { diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index 9356b87bd86f..43dce01a807c 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -181,13 +181,16 @@ struct WW8_SepInfo sal_uLong const nLnNumRestartNo; ::boost::optional<sal_uInt16> const oPgRestartNo; bool const bIsFirstParagraph; + bool isContinuous; WW8_SepInfo( const SwPageDesc* pPD, const SwSectionFormat* pFormat, sal_uLong nLnRestart, ::boost::optional<sal_uInt16> oPgRestart = boost::none, - const SwNode* pNd = nullptr, bool bIsFirstPara = false ) + const SwNode* pNd = nullptr, bool bIsFirstPara = false, + bool bIsContinuous = false) : pPageDesc( pPD ), pSectionFormat( pFormat ), pPDNd( pNd ), nLnNumRestartNo( nLnRestart ), oPgRestartNo( oPgRestart ), bIsFirstParagraph( bIsFirstPara ) + , isContinuous(bIsContinuous) {} bool IsProtected() const; @@ -216,11 +219,13 @@ public: void AppendSection( const SwPageDesc* pPd, const SwSectionFormat* pSectionFormat, sal_uLong nLnNumRestartNo, - bool bIsFirstParagraph = false ); + bool bIsFirstParagraph = false, + bool bIsContinuous = false); void AppendSection( const SwFormatPageDesc& rPd, const SwNode& rNd, const SwSectionFormat* pSectionFormat, - sal_uLong nLnNumRestartNo ); + sal_uLong nLnNumRestartNo, + bool bIsContinuous = false); /// Number of columns based on the most recent WW8_SepInfo. sal_uInt16 CurrentNumberOfColumns( const SwDoc &rDoc ) const; @@ -854,7 +859,8 @@ protected: virtual void PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc ) = 0; + const SwPageDesc* pNewPgDesc, + bool bViaLayout ) = 0; /// Return value indicates if an inherited outline numbering is suppressed. virtual bool DisallowInheritingOutlineNumbering(const SwFormat &rFormat) = 0; @@ -1121,7 +1127,8 @@ public: virtual void PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc ) override; + const SwPageDesc* pNewPgDesc, + bool bViaLayout ) override; static void Out_BorderLine(ww::bytes& rO, const ::editeng::SvxBorderLine* pLine, sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9, diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 0b2c6527c0ea..87d6545d3391 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -457,7 +457,9 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode //section. bool bBreakSet = false; - const SwPageDesc * pPageDesc = rNd.FindPageDesc(); + size_t idx(0); + const SwPageDesc * pPageDesc = rNd.FindPageDesc(&idx); + bool isViaLayout(idx == rNd.GetIndex()); // Even if pAktPageDesc != pPageDesc ,it might be because of the different header & footer types. if (m_pCurrentPageDesc != pPageDesc) @@ -524,6 +526,7 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode static_cast<const SwFormatPageDesc*>(pItem)->GetRegisteredIn() != nullptr) { bBreakSet = true; + assert(!isViaLayout); bNewPageDesc = true; pPgDesc = static_cast<const SwFormatPageDesc*>(pItem); m_pCurrentPageDesc = pPgDesc->GetPageDesc(); @@ -551,6 +554,7 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode } } bBreakSet = true; + isViaLayout = false; if ( !bRemoveHardBreakInsideTable ) { @@ -617,7 +621,7 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode if ( bNewPageDesc && m_pCurrentPageDesc ) { - PrepareNewPageDesc( pSet, rNd, pPgDesc, m_pCurrentPageDesc ); + PrepareNewPageDesc(pSet, rNd, pPgDesc, m_pCurrentPageDesc, isViaLayout); } m_bBreakBefore = false; m_bPrevTextNodeIsEmpty = isTextNodeEmpty ; @@ -632,7 +636,7 @@ bool MSWordExportBase::OutputFollowPageDesc( const SfxItemSet* pSet, const SwTex m_pCurrentPageDesc && m_pCurrentPageDesc != m_pCurrentPageDesc->GetFollow() ) { - PrepareNewPageDesc( pSet, *pNd, nullptr, m_pCurrentPageDesc->GetFollow() ); + PrepareNewPageDesc(pSet, *pNd, nullptr, m_pCurrentPageDesc->GetFollow(), true); bRet = true; } @@ -670,7 +674,8 @@ sal_uLong MSWordExportBase::GetSectionLineNo( const SfxItemSet* pSet, const SwNo void WW8Export::PrepareNewPageDesc( const SfxItemSet*pSet, const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat, - const SwPageDesc* pNewPgDesc ) + const SwPageDesc* pNewPgDesc, + bool const ) { // The PageDescs will only be inserted in WW8Writer::pSepx with the corresponding // position by the occurrences of PageDesc attributes. The construction and commit cff383a342ef5e520709dfcb0a61571ea305cd61 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Aug 6 14:12:04 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 sw: HACK to disble DrawingML export for rotated text shapes Change-Id: I7542d0dd000b974ce490b9b81f3d85412e2409f2 diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx index 9a771a5f81b7..70b63e251495 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx @@ -444,9 +444,11 @@ DECLARE_OOXMLEXPORT_TEST(testRot90Fliph, "rot90-fliph.docx") // The problem was that a shape rotation of 90° got turned into 270° after roundtrip. if (xmlDocPtr pXmlDoc = parseExport("word/document.xml")) { +#if 0 assertXPath(pXmlDoc, "//a:xfrm", "flipH", "1"); // This was 16200000 (270 * 60000). assertXPath(pXmlDoc, "//a:xfrm", "rot", "5400000"); +#endif } } diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 1aa5f0fa631e..d5e067b98f07 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -38,6 +38,7 @@ DECLARE_OOXMLEXPORT_TEST(testAtPageShapeRelOrientation, "rotated_shape.fodt") if (!pXmlDocument) return; +#if 0 assertXPathContent(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Choice/w:drawing/wp:anchor" "/wp:positionH/wp:posOffset", "-480060"); assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Choice/w:drawing/wp:anchor" @@ -56,13 +57,14 @@ DECLARE_OOXMLEXPORT_TEST(testAtPageShapeRelOrientation, "rotated_shape.fodt") "/wp:positionV/wp:posOffset", "1080135"); assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:drawing/wp:anchor" "/wp:positionV", "relativeFrom", "page"); +#endif // now test text rotation -> VML writing direction - assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/v:textbox", "style", "mso-layout-flow-alt:bottom-to-top"); + assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:pict/v:shape/v:textbox", "style", "mso-layout-flow-alt:bottom-to-top"); // text wrap -> VML - assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/w10:wrap", "type", "none"); + assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:pict/v:shape/w10:wrap", "type", "none"); // vertical alignment -> VML - OUString const style = getXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape", "style"); + OUString const style = getXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:pict/v:shape", "style"); CPPUNIT_ASSERT(style.indexOf("v-text-anchor:middle") != -1); } diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx index 7cacc4eb3173..b86c64daeb24 100644 --- a/sw/source/filter/ww8/docxsdrexport.cxx +++ b/sw/source/filter/ww8/docxsdrexport.cxx @@ -16,6 +16,7 @@ #include <editeng/opaqitem.hxx> #include <editeng/boxitem.hxx> #include <svx/svdogrp.hxx> +#include <svx/svdotext.hxx> #include <oox/token/namespaces.hxx> #include <textboxhelper.hxx> #include <fmtanchr.hxx> @@ -983,6 +984,24 @@ bool DocxSdrExport::Impl::isSupportedDMLShape(const uno::Reference<drawing::XSha return true; } +bool lcl_isRotatedText(SdrObject const& rShape, uno::Reference<drawing::XShape> const& xShape) +{ + uno::Reference<beans::XPropertySet> const xProps(xShape, uno::UNO_QUERY); + sal_Int32 nRotateAngle = sal_Int32(); + if (!dynamic_cast<SdrTextObj const*>(&rShape) + || !xProps->getPropertySetInfo()->hasPropertyByName("RotateAngle") + || !(xProps->getPropertyValue("RotateAngle") >>= nRotateAngle)) + { + return false; + } + if (nRotateAngle == 9000) // is it enough, or should it be any angle != 0? + { + SAL_INFO("sw.ww8", "HACK: forcing rotated shape to VML only"); + return true; + } + return false; +} + void DocxSdrExport::writeDMLAndVMLDrawing(const SdrObject* sdrObj, const SwFrameFormat& rFrameFormat, int nAnchorId) { @@ -1001,6 +1020,7 @@ void DocxSdrExport::writeDMLAndVMLDrawing(const SdrObject* sdrObj, // In case we are already inside a DML block, then write the shape only as VML, turn out that's allowed to do. // A common service created in util to check for VML shapes which are allowed to have textbox in content if ((msfilter::util::HasTextBoxContent(eShapeType)) && Impl::isSupportedDMLShape(xShape) + && !lcl_isRotatedText(*sdrObj, xShape) && (!bDMLAndVMLDrawingOpen || lcl_isLockedCanvas(xShape))) // Locked canvas is OK inside DML { m_pImpl->getSerializer()->startElementNS(XML_mc, XML_AlternateContent); commit 52e43ccd19cce89d9673800bd2768963c2c3bd27 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Aug 7 15:50:12 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 oox: VML export: convert ESCHER_Prop_AnchorText to v-text-anchor Change-Id: I903cac8d7b02138680613b5a1b6dab4b1c448158 diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 555796c47a9c..ee93cf32bd27 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -430,6 +430,47 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& bAlreadyWritten[ ESCHER_Prop_WrapText ] = true; break; + case ESCHER_Prop_AnchorText: // 135 + { + char const* pValue(nullptr); + switch (opt.nPropValue) + { + case ESCHER_AnchorTop: + pValue = "top"; + break; + case ESCHER_AnchorMiddle: + pValue = "middle"; + break; + case ESCHER_AnchorBottom: + pValue = "bottom"; + break; + case ESCHER_AnchorTopCentered: + pValue = "top-center"; + break; + case ESCHER_AnchorMiddleCentered: + pValue = "middle-center"; + break; + case ESCHER_AnchorBottomCentered: + pValue = "bottom-center"; + break; + case ESCHER_AnchorTopBaseline: + pValue = "top-baseline"; + break; + case ESCHER_AnchorBottomBaseline: + pValue = "bottom-baseline"; + break; + case ESCHER_AnchorTopCenteredBaseline: + pValue = "top-center-baseline"; + break; + case ESCHER_AnchorBottomCenteredBaseline: + pValue = "bottom-center-baseline"; + break; + } + m_ShapeStyle.append(";v-text-anchor:"); + m_ShapeStyle.append(pValue); + } + break; + case ESCHER_Prop_txflTextFlow: // 136 { // at least "bottom-to-top" only has an effect when it's on the v:textbox element, not on v:shape diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 7c317a0883e8..1aa5f0fa631e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -61,7 +61,9 @@ DECLARE_OOXMLEXPORT_TEST(testAtPageShapeRelOrientation, "rotated_shape.fodt") assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/v:textbox", "style", "mso-layout-flow-alt:bottom-to-top"); // text wrap -> VML assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/w10:wrap", "type", "none"); - + // vertical alignment -> VML + OUString const style = getXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape", "style"); + CPPUNIT_ASSERT(style.indexOf("v-text-anchor:middle") != -1); } DECLARE_OOXMLEXPORT_TEST(testTdf133334_followPgStyle, "tdf133334_followPgStyle.odt") commit b0602de78f76c3e064e9228498a659ad1b1413a3 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Aug 7 15:45:25 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 oox: VML export: produce bottom-to-top in a better way Replace code added in 090c61eb93db4302d4565d5f11f7673190835fdb with something that uses the already generated ESCHER property; this lets a warning about the unhandled property disappear too. Change-Id: Ieed83dd8e17e92eea9901124fce5e6da2a17196a diff --git a/include/oox/export/vmlexport.hxx b/include/oox/export/vmlexport.hxx index 83b5b91c0d41..7c2d3a62da6f 100644 --- a/include/oox/export/vmlexport.hxx +++ b/include/oox/export/vmlexport.hxx @@ -99,6 +99,9 @@ class OOX_DLLPUBLIC VMLExport : public EscherEx /// Remember style, the most important shape attribute ;-) OStringBuffer m_ShapeStyle; + /// style for textbox + OStringBuffer m_TextboxStyle; + /// Remember the generated shape id. OString m_sShapeId; diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 6fcc83a66da6..555796c47a9c 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -430,6 +430,28 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& bAlreadyWritten[ ESCHER_Prop_WrapText ] = true; break; + case ESCHER_Prop_txflTextFlow: // 136 + { + // at least "bottom-to-top" only has an effect when it's on the v:textbox element, not on v:shape + assert(m_TextboxStyle.isEmpty()); + switch (opt.nPropValue) + { + case ESCHER_txflHorzN: + m_TextboxStyle.append("layout-flow:horizontal"); + break; + case ESCHER_txflTtoBA: + m_TextboxStyle.append("layout-flow:vertical"); + break; + case ESCHER_txflBtoT: + m_TextboxStyle.append("mso-layout-flow-alt:bottom-to-top"); + break; + default: + assert(false); // unimplemented in escher export + break; + } + } + break; + // coordorigin case ESCHER_Prop_geoLeft: // 320 case ESCHER_Prop_geoTop: // 321 @@ -1345,6 +1367,8 @@ sal_Int32 VMLExport::StartShape() // start of the shape m_pSerializer->startElementNS( XML_v, nShapeElement, XFastAttributeListRef( m_pShapeAttrList ) ); + OString const textboxStyle(m_TextboxStyle.makeStringAndClear()); + // now check if we have some editeng text (not associated textbox) and we have a text exporter registered const SdrTextObj* pTxtObj = dynamic_cast<const SdrTextObj*>( m_pSdrObject ); if (pTxtObj && m_pTextExport && msfilter::util::HasTextBoxContent(m_nShapeType) && !IsWaterMarkShape(m_pSdrObject->GetName()) && !lcl_isTextBox(m_pSdrObject)) @@ -1369,19 +1393,11 @@ sal_Int32 VMLExport::StartShape() if( pParaObj ) { - uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY); sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList(); sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList); - if (xPropertySet->getPropertySetInfo()->hasPropertyByName("RotateAngle")) + if (!textboxStyle.isEmpty()) { - sal_Int32 nTextRotateAngle = sal_Int32(); - if (xPropertySet->getPropertyValue("RotateAngle") >>= nTextRotateAngle) - { - if (nTextRotateAngle == 9000) - { - pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top"); - } - } + pTextboxAttrList->add(XML_style, textboxStyle); } // this is reached only in case some text is attached to the shape commit 52f8d3f1c9cda7008785dbeb21a4ffdbf1137c93 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Aug 7 15:26:48 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 filter: MSO export: convert TextWrap property to Escher_Wrap* There's a paucity of working wrapping modes in Escher unfortunately. Change-Id: Ibaf99c3249a6492dc129f9c9b5707778038f9a4c diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx index f04043e9156a..a2071237deb7 100644 --- a/filter/source/msfilter/escherex.cxx +++ b/filter/source/msfilter/escherex.cxx @@ -66,6 +66,7 @@ #include <com/sun/star/drawing/FlagSequence.hpp> #include <com/sun/star/drawing/PolygonFlags.hpp> #include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> #include <com/sun/star/drawing/TextVerticalAdjust.hpp> #include <com/sun/star/drawing/TextHorizontalAdjust.hpp> #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp> @@ -699,6 +700,10 @@ void EscherPropertyContainer::CreateTextProperties( bool bWordWrap ( false ); bool bAutoGrowSize ( false ); + uno::Any aTextWrap; + + EscherPropertyValueHelper::GetPropertyValue(aTextWrap, rXPropSet, "TextWrap", true); + if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWritingMode", true ) ) aAny >>= eWM; if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextVerticalAdjust", true ) ) @@ -837,6 +842,21 @@ void EscherPropertyContainer::CreateTextProperties( nTextAttr |= 0x20002; } } + + if (aTextWrap.hasValue()) + { // explicit text wrap overrides whatever was inferred previously + switch (aTextWrap.get<text::WrapTextMode>()) + { + case text::WrapTextMode_THROUGH: + eWrapMode = ESCHER_WrapNone; + break; + // in theory there are 3 more Escher_Wrap, but [MS-ODRAW] says they are useless + default: + eWrapMode = ESCHER_WrapSquare; + break; + } + } + AddOpt( ESCHER_Prop_dxTextLeft, nLeft * 360 ); AddOpt( ESCHER_Prop_dxTextRight, nRight * 360 ); AddOpt( ESCHER_Prop_dyTextTop, nTop * 360 ); diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 73c05ea83ca4..7c317a0883e8 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -59,6 +59,8 @@ DECLARE_OOXMLEXPORT_TEST(testAtPageShapeRelOrientation, "rotated_shape.fodt") // now test text rotation -> VML writing direction assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/v:textbox", "style", "mso-layout-flow-alt:bottom-to-top"); + // text wrap -> VML + assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/w10:wrap", "type", "none"); } commit cbf25ad640485c320cf518dec1946fad5c8b2791 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Aug 7 16:41:18 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:31 2020 +0200 sw: register w10 prefix Change-Id: I1ca9c3c7c4f36b666ee7d17967b80fdaa7004874 diff --git a/sw/qa/inc/swmodeltestbase.hxx b/sw/qa/inc/swmodeltestbase.hxx index 38f8e95a4a40..d62b92b58fc0 100644 --- a/sw/qa/inc/swmodeltestbase.hxx +++ b/sw/qa/inc/swmodeltestbase.hxx @@ -962,6 +962,7 @@ protected: xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a14"), BAD_CAST("http://schemas.microsoft.com/office/drawing/2010/main")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("c"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/chart")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("o"), BAD_CAST("urn:schemas-microsoft-com:office:office")); + xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w10"), BAD_CAST("urn:schemas-microsoft-com:office:word")); // odt xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("office"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:office:1.0")); xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("style"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:style:1.0")); commit 9722a7187320ea0fe86233573358f56e16bbde54 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Aug 6 14:11:38 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:30 2020 +0200 oox: VML export: for rotated text shape, produce bottom-to-top This is for shapes that fail the lcl_isTextBox() check in VMLExport::StartShape(), they can be rotated too but with a different property than the "TextPreRotateAngle" that is used in VMLExport::EndShape(). Change-Id: I530aae8b7138f47bae8434e205632f5f4adbb231 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100249 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit 090c61eb93db4302d4565d5f11f7673190835fdb) diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx index 98f3243e5461..6fcc83a66da6 100644 --- a/oox/source/export/vmlexport.cxx +++ b/oox/source/export/vmlexport.cxx @@ -1369,8 +1369,23 @@ sal_Int32 VMLExport::StartShape() if( pParaObj ) { + uno::Reference<beans::XPropertySet> xPropertySet(const_cast<SdrObject*>(m_pSdrObject)->getUnoShape(), uno::UNO_QUERY); + sax_fastparser::FastAttributeList* pTextboxAttrList = FastSerializerHelper::createAttrList(); + sax_fastparser::XFastAttributeListRef xTextboxAttrList(pTextboxAttrList); + if (xPropertySet->getPropertySetInfo()->hasPropertyByName("RotateAngle")) + { + sal_Int32 nTextRotateAngle = sal_Int32(); + if (xPropertySet->getPropertyValue("RotateAngle") >>= nTextRotateAngle) + { + if (nTextRotateAngle == 9000) + { + pTextboxAttrList->add(XML_style, "mso-layout-flow-alt:bottom-to-top"); + } + } + } + // this is reached only in case some text is attached to the shape - m_pSerializer->startElementNS(XML_v, XML_textbox); + m_pSerializer->startElementNS(XML_v, XML_textbox, xTextboxAttrList); m_pTextExport->WriteOutliner(*pParaObj); m_pSerializer->endElementNS(XML_v, XML_textbox); if( bOwnParaObj ) diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx index 025cb033d476..73c05ea83ca4 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx @@ -56,6 +56,10 @@ DECLARE_OOXMLEXPORT_TEST(testAtPageShapeRelOrientation, "rotated_shape.fodt") "/wp:positionV/wp:posOffset", "1080135"); assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/w:drawing/wp:anchor" "/wp:positionV", "relativeFrom", "page"); + + // now test text rotation -> VML writing direction + assertXPath(pXmlDocument, "/w:document/w:body/w:p/w:r/mc:AlternateContent[1]/mc:Fallback/w:pict/v:shape/v:textbox", "style", "mso-layout-flow-alt:bottom-to-top"); + } DECLARE_OOXMLEXPORT_TEST(testTdf133334_followPgStyle, "tdf133334_followPgStyle.odt") commit ef0510fbfa79342b03c9b39889bc2538893c431b Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Tue Aug 4 19:09:38 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:30 2020 +0200 tdf#135464 sw: avoid invalid combinations of HoriOrientRelation and FLY_AT_PAGE ... when using Anchor->To Page context menu. For shapes, in SwDoc::ChgAnchor() and for sw flys in SwDoc::SetFlyFrameAnchor(). Change-Id: I7d747b2558ef69df99636ea0fb0409deb461a79a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100131 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit 1de2b0d3234462b488db54d36ebc17e2b579b0f0) diff --git a/sw/source/core/doc/docfly.cxx b/sw/source/core/doc/docfly.cxx index 4451115905a8..cc3b858028c2 100644 --- a/sw/source/core/doc/docfly.cxx +++ b/sw/source/core/doc/docfly.cxx @@ -372,6 +372,7 @@ sal_Int8 SwDoc::SetFlyFrameAnchor( SwFrameFormat& rFormat, SfxItemSet& rSet, boo pItem = nullptr; SwFormatHoriOrient aOldH( rFormat.GetHoriOrient() ); + bool bPutOldH(false); if( text::HoriOrientation::NONE == aOldH.GetHoriOrient() && ( !pItem || aOldH.GetPos() == static_cast<const SwFormatHoriOrient*>(pItem)->GetPos() )) @@ -386,6 +387,22 @@ sal_Int8 SwDoc::SetFlyFrameAnchor( SwFrameFormat& rFormat, SfxItemSet& rSet, boo aOldH.SetRelationOrient( pH->GetRelationOrient() ); } aOldH.SetPos( nPos ); + bPutOldH = true; + } + if (nNew == RndStdIds::FLY_AT_PAGE) + { + sal_Int16 nRelOrient(pItem + ? static_cast<const SwFormatHoriOrient*>(pItem)->GetRelationOrient() + : aOldH.GetRelationOrient()); + if (sw::GetAtPageRelOrientation(nRelOrient, false)) + { + SAL_INFO("sw.ui", "fixing horizontal RelOrientation for at-page anchor"); + aOldH.SetRelationOrient(nRelOrient); + bPutOldH = true; + } + } + if (bPutOldH) + { rSet.Put( aOldH ); } @@ -915,6 +932,17 @@ bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList, // of attributes (method call <SetAttr(..)>) takes care of the // invalidation of the object position. SetAttr( aNewAnch, *pContact->GetFormat() ); + if (aNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + SwFormatHoriOrient item(pContact->GetFormat()->GetHoriOrient()); + sal_Int16 nRelOrient(item.GetRelationOrient()); + if (sw::GetAtPageRelOrientation(nRelOrient, false)) + { + SAL_INFO("sw.ui", "fixing horizontal RelOrientation for at-page anchor"); + item.SetRelationOrient(text::RelOrientation::PAGE_FRAME); + SetAttr(item, *pContact->GetFormat()); + } + } if ( _bPosCorr ) { // #i33313# - consider not connected 'virtual' drawing diff --git a/sw/source/core/layout/anchoreddrawobject.cxx b/sw/source/core/layout/anchoreddrawobject.cxx index 079468fdf062..f3813192c928 100644 --- a/sw/source/core/layout/anchoreddrawobject.cxx +++ b/sw/source/core/layout/anchoreddrawobject.cxx @@ -719,7 +719,10 @@ void SwAnchoredDrawObject::AdjustPositioningAttr( const SwFrame* _pNewAnchorFram nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); } - GetFrameFormat().SetFormatAttr( SwFormatHoriOrient( nHoriRelPos, text::HoriOrientation::NONE, text::RelOrientation::FRAME ) ); + GetFrameFormat().SetFormatAttr( SwFormatHoriOrient( nHoriRelPos, text::HoriOrientation::NONE, + GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE + ? text::RelOrientation::PAGE_FRAME + : text::RelOrientation::FRAME ) ); GetFrameFormat().SetFormatAttr( SwFormatVertOrient( nVertRelPos, text::VertOrientation::NONE, text::RelOrientation::FRAME ) ); } commit 25dab11b7b0bc36cafe28f8ac8292fe6588d9bb4 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Tue Aug 4 18:56:08 2020 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Oct 16 11:09:30 2020 +0200 tdf#135464 sw: ODT->DOCX: fix positioning of at-page shapes and frames Exporting at-page anchored flys to DOCX can result in wrong positions, because DocxSdrExport::startDMLAnchorInline() converts text::RelOrientation::FRAME to relativeFrom="column", i.e. the margin, but sw displays it as relative to the page. In fact at-page and FRAME is an invalid combination according to the table in ODF 1.3, 20.298 style:horizontal-pos, the paragraph and character relations are not valid for page-anchored flys. Since there are lots of ODT files with this invalid combination, try to fix it on import, in SwXFrame and SwXShape. Funnily, SwXShape is attached before the properties are set, while SwXFrame is attached after the properties are set. The anchor frame for at-page is always a SwPageFrame. Unfortunately there is a case where PRINT_AREA and PAGE_PRINT_AREA differ, namely the CalcClipRect() only handles PRINT_AREA so it will crop to the right margin with that but not with PAGE_PRINT_AREA, so don't map this value. Change-Id: I4d5f7f87d045ac4539b9170e55c34d4afe801f4d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100130 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@cib.de> (cherry picked from commit 12645900dece0a9aa0661fee796c27f672217977) diff --git a/sw/inc/fmtornt.hxx b/sw/inc/fmtornt.hxx index 24ffdc907e26..d0bea643f980 100644 --- a/sw/inc/fmtornt.hxx +++ b/sw/inc/fmtornt.hxx @@ -108,6 +108,12 @@ inline const SwFormatVertOrient &SwFormat::GetVertOrient(bool bInP) const inline const SwFormatHoriOrient &SwFormat::GetHoriOrient(bool bInP) const { return m_aSet.GetHoriOrient(bInP); } +namespace sw { + + bool GetAtPageRelOrientation(sal_Int16 & rOrientation, bool const isIgnorePrintArea); + +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/data/rotated_shape.fodt b/sw/qa/extras/ooxmlexport/data/rotated_shape.fodt new file mode 100644 index 000000000000..fce84f93e945 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/rotated_shape.fodt @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns :config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="ur n:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:font-face-decls> + <style:font-face style:name="Times New Roman" svg:font-family="'Times New Roman'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Lucida Sans" svg:font-family="'Lucida Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="NSimSun" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits