Rebased ref, commits from common ancestor: commit 3789ce8e92f99ab438844ec31a7854d9489a88e0 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Tue Jan 23 10:29:44 2018 +0100
BorderlineFix: Corrected handling for 'rotated' CellBorders CellBorders can be rotated (including their Text) and need special visualization that is based on an own sheared/rotated coordinate system. Currently only possible for single cells (not merged ones) and needs to handle all borders (also bottom-right directly in the rotated cell, not in the neighboured ones to have the geometry, plus avoiding these in the non-rotated neighbour cells. Also corrected adding CellRotation data to svx::frame::Array in calc using SetCellRotations() which now gets called in the ScOutputData constructor to ensure it gets called in all places where it is used. Change-Id: I47bdfc29ba5ca76bbc07d98cb64733f867b1ee20 diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx index f23dabae3de0..c41433609b9e 100644 --- a/sc/source/ui/inc/output.hxx +++ b/sc/source/ui/inc/output.hxx @@ -255,6 +255,11 @@ private: long SetEngineTextAndGetWidth( DrawEditParam& rParam, const OUString& rSetString, long& rNeededPixel, long nAddWidthPixels ); + // Check for and set cell rotations at OutputData to have it available + // in the svx tooling to render the borders. Moved to private section + // and the single call to end of constructor to be sure this always happens + void SetCellRotations(); + public: /** * @param nNewScrX: X-Offset in the output device for the table @@ -311,8 +316,6 @@ public: // with logic MapMode set! void DrawEdit(bool bPixelToLogic); - - void SetCellRotations(); void DrawRotated(bool bPixelToLogic); // logical void DrawClear(); diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx index 22e07763decb..64cd440e9902 100644 --- a/sc/source/ui/view/gridwin4.cxx +++ b/sc/source/ui/view/gridwin4.cxx @@ -696,10 +696,6 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI pContentDev->SetMapMode(aCurrentMapMode); } - // check for and set cell rotations at OutputData to have it available - // in the svx tooling to render the borders - aOutputData.SetCellRotations(); - if ( rDoc.HasBackgroundDraw( nTab, aDrawingRectLogic ) ) { pContentDev->SetMapMode(MapMode(MapUnit::MapPixel)); diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index bd3687cd1cd3..064bb14ce1a1 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -214,6 +214,9 @@ ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType, bTabProtected = mpDoc->IsTabProtected( nTab ); bLayoutRTL = mpDoc->IsLayoutRTL( nTab ); + + // always needed, so call at the end of the constructor + SetCellRotations(); } ScOutputData::~ScOutputData() diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index 096216210585..ab6db75799e3 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -1092,9 +1092,21 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( const bool bFirstRow(nRow == nFirstRow); const bool bLastRow(nRow == nLastRow); + // handle rotation: If cell is rotated, handle lower/right edge inside + // this local geometry due to the created CoordinateSystem already representing + // the needed transformations. + const bool bRotated(rCell.IsRotated()); + + // Additionally avoid double-handling by supressing handling when self not roated, + // but above/left is rotated and thus already handled. Two directly connected + // rotated will paint/create both edges, they might be rotated differently. + const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated()); + const bool bSupressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated()); + // create upper line for this Cell - if (!bOverlapY // true for first line in merged cells or cells - || bFirstRow) // true for non_Calc usages of this tooling + if ((!bOverlapY // true for first line in merged cells or cells + || bFirstRow) // true for non_Calc usages of this tooling + && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated) { // get CellStyle - method will take care to get the correct one, e.g. // for merged cells (it uses ORIGCELL that works with topLeft's of these) @@ -1107,7 +1119,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( } // create lower line for this Cell - if (bLastRow) // true for non_Calc usages of this tooling + if (bLastRow // true for non_Calc usages of this tooling + || bRotated) // true if cell is rotated, handle lower edge in local geometry { const Style& rBottom(GetCellStyleBottom(nCol, nRow)); @@ -1118,8 +1131,9 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( } // create left line for this Cell - if (!bOverlapX // true for first column in merged cells or cells - || bFirstCol) // true for non_Calc usages of this tooling + if ((!bOverlapX // true for first column in merged cells or cells + || bFirstCol) // true for non_Calc usages of this tooling + && !bSupressLeft) // true when left is not rotated, so edge is already handled (see bRotated) { const Style& rLeft(GetCellStyleLeft(nCol, nRow)); @@ -1130,7 +1144,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( } // create right line for this Cell - if (bLastCol) // true for non_Calc usages of this tooling + if (bLastCol // true for non_Calc usages of this tooling + || bRotated) // true if cell is rotated, handle right edge in local geometry { const Style& rRight(GetCellStyleRight(nCol, nRow)); commit 492b1ad690a3c3de6903f667e0e6793f81345221 Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Mon Jan 22 14:33:20 2018 +0100 BorderlineFix: Avoid BorderLines to be too prolonged For MergedCells there was an effect that the BorderLines were painted too far in PrintPreview/Print/PDF visualization, found reason and changed. Checked (hopefully) all usages, looks good. Change-Id: I0acf8dcb20548a98533f3ab317ac72c0d0f0a947 diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx index e135e371319c..b73531b06e47 100644 --- a/include/svx/framelinkarray.hxx +++ b/include/svx/framelinkarray.hxx @@ -290,7 +290,7 @@ public: long GetHeight() const; /** Returns the output range of the cell (nCol,nRow). - Returns total output range of merged ranges. */ + Returns total output range of merged ranges, if bExpandMerged is true. */ basegfx::B2DRange GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const; // mirroring -------------------------------------------------------------- diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index ac47053155ec..096216210585 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -840,24 +840,44 @@ long Array::GetHeight() const basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const { - size_t nFirstCol = bExpandMerged ? mxImpl->GetMergedFirstCol( nCol, nRow ) : nCol; - size_t nFirstRow = bExpandMerged ? mxImpl->GetMergedFirstRow( nCol, nRow ) : nRow; - size_t nLastCol = bExpandMerged ? mxImpl->GetMergedLastCol( nCol, nRow ) : nCol; - size_t nLastRow = bExpandMerged ? mxImpl->GetMergedLastRow( nCol, nRow ) : nRow; - const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); - const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); - tools::Rectangle aRect(aPoint, aSize); - - // adjust rectangle for partly visible merged cells - const Cell& rCell = CELL( nCol, nRow ); - if( rCell.IsMerged() ) + if(bExpandMerged) { - aRect.Left() -= rCell.mnAddLeft; - aRect.Right() += rCell.mnAddRight; - aRect.Top() -= rCell.mnAddTop; - aRect.Bottom() += rCell.mnAddBottom; + // get the Range of the fully expanded cell (if merged) + const size_t nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow )); + const size_t nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow )); + const size_t nLastCol(mxImpl->GetMergedLastCol( nCol, nRow )); + const size_t nLastRow(mxImpl->GetMergedLastRow( nCol, nRow )); + const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); + const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); + tools::Rectangle aRect(aPoint, aSize); + + // adjust rectangle for partly visible merged cells + const Cell& rCell = CELL( nCol, nRow ); + + if( rCell.IsMerged() ) + { + // not *sure* what exactly this is good for, + // it is just a hard set extension at merged cells, + // probably *should* be included in the above extended + // GetColPosition/GetColWidth already. This might be + // added due to GetColPosition/GetColWidth not working + // correcly over PageChanges (if used), but not sure. + aRect.Left() -= rCell.mnAddLeft; + aRect.Right() += rCell.mnAddRight; + aRect.Top() -= rCell.mnAddTop; + aRect.Bottom() += rCell.mnAddBottom; + } + + return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); + } + else + { + const Point aPoint( GetColPosition( nCol ), GetRowPosition( nRow ) ); + const Size aSize( GetColWidth( nCol, nCol ) + 1, GetRowHeight( nRow, nRow ) + 1 ); + const tools::Rectangle aRect(aPoint, aSize); + + return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); } - return basegfx::B2DRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom()); } // mirroring @@ -1054,7 +1074,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( { for (size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol) { - // get Cell and CoordinateSystem (*only* for this Cell), check if used (not empty) + // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for + // merged cells (!)), check if used (non-empty vectors) const Cell& rCell(CELL(nCol, nRow)); basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this, nCol, nRow, false)); basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); @@ -1153,9 +1174,6 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(bContinue) { - const size_t _nLastCol(mxImpl->GetMergedLastCol(nCol, nRow)); - const size_t _nLastRow(mxImpl->GetMergedLastRow(nCol, nRow)); - if(rTLBR.IsUsed()) { /// top-left and bottom-right Style Tables commit 2070b2185e8fef5222654fdf84d7654d32d8aaab Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Fri Jan 19 14:43:24 2018 +0100 BorderlineFix: Corrected missing borders in print In Print/PDF/PrintPreview border lines were missing, this happened for merged cells. It has to do with access to the involved Styles and/or 'Clip' set (to avoid creating everything). Thus a 'mixed' usage of cell and merged-cell stuff was needed. As it turns out support for this is already there, need to use it. Change-Id: Ic16085b97eef5c79a4501279432f43491bca350e diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 2feaab5af8bf..9b532a2d0d29 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -143,10 +143,6 @@ private: /// the impl class holding the data std::shared_ptr< implStyle > maImplStyle; - /// pointer to Cell using this style. Not member of the - /// impl class since multiple Cells may use the same style - const Cell* mpUsingCell; - /// call to set maImplStyle on demand void implEnsureImplStyle(); diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index ecb3eaace1c6..ac47053155ec 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -1055,17 +1055,14 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( for (size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol) { // get Cell and CoordinateSystem (*only* for this Cell), check if used (not empty) - const Cell& rCell = CELL(nCol, nRow); + const Cell& rCell(CELL(nCol, nRow)); basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this, nCol, nRow, false)); basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); if(!aX.equalZero() && !aY.equalZero()) { - // for getting correct Style(s) for merged Cells, we need the First(Col/Row) - // for access (see accessing Styles below) - const size_t _nFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow)); - const size_t _nFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow)); + // get needed local values basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); const bool bOverlapX(rCell.mbOverlapX); const bool bOverlapY(rCell.mbOverlapY); @@ -1078,7 +1075,9 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if (!bOverlapY // true for first line in merged cells or cells || bFirstRow) // true for non_Calc usages of this tooling { - const Style& rTop = GetCellStyleTop(_nFirstCol, _nFirstRow); + // get CellStyle - method will take care to get the correct one, e.g. + // for merged cells (it uses ORIGCELL that works with topLeft's of these) + const Style& rTop(GetCellStyleTop(nCol, nRow)); if(rTop.IsUsed()) { @@ -1089,7 +1088,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // create lower line for this Cell if (bLastRow) // true for non_Calc usages of this tooling { - const Style& rBottom = GetCellStyleBottom(_nFirstCol, _nFirstRow); + const Style& rBottom(GetCellStyleBottom(nCol, nRow)); if(rBottom.IsUsed()) { @@ -1101,7 +1100,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if (!bOverlapX // true for first column in merged cells or cells || bFirstCol) // true for non_Calc usages of this tooling { - const Style& rLeft(GetCellStyleLeft(_nFirstCol, _nFirstRow)); + const Style& rLeft(GetCellStyleLeft(nCol, nRow)); if(rLeft.IsUsed()) { @@ -1112,7 +1111,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // create right line for this Cell if (bLastCol) // true for non_Calc usages of this tooling { - const Style& rRight(GetCellStyleRight(_nFirstCol, _nFirstRow)); + const Style& rRight(GetCellStyleRight(nCol, nRow)); if(rRight.IsUsed()) { @@ -1122,8 +1121,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // check for crossed lines, these need special treatment, especially // for merged cells, see below - const Style& rTLBR = GetCellStyleTLBR(_nFirstCol, _nFirstRow); - const Style& rBLTR = GetCellStyleBLTR(_nFirstCol, _nFirstRow); + const Style& rTLBR(GetCellStyleTLBR(nCol, nRow)); + const Style& rBLTR(GetCellStyleBLTR(nCol, nRow)); if(rTLBR.IsUsed() || rBLTR.IsUsed()) { @@ -1131,8 +1130,11 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( if(rCell.IsMerged()) { - // first check if this merged cell was already handled - const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nFirstCol, _nFirstRow)); + // first check if this merged cell was already handled. To do so, + // calculate and use the index of the TopLeft cell + const size_t _nMergedFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow)); + const size_t _nMergedFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow)); + const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nMergedFirstCol, _nMergedFirstRow)); bContinue = (aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell)); if(bContinue) @@ -1140,7 +1142,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // not found, add now to mark as handled aMergedCells.insert(nIndexOfMergedCell); - // when merged, get extended coordinate system and dependent values + // when merged, get extended coordinate system and derived values + // for the full range of this merged cell aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true); aX = basegfx::utils::getColumn(aCoordinateSystem, 0); aY = basegfx::utils::getColumn(aCoordinateSystem, 1); @@ -1157,8 +1160,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( { /// top-left and bottom-right Style Tables /// Fill top-left Style Table - const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow)); - const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow)); + const Style& rTLFromRight(GetCellStyleTop(nCol, nRow)); + const Style& rTLFromBottom(GetCellStyleLeft(nCol, nRow)); StyleVectorTable aStart; const basegfx::B2DVector aAxisA(aX + aY); @@ -1167,8 +1170,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( aStart.sort(); /// Fill bottom-right Style Table - const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow)); - const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow)); + const Style& rBRFromBottom(GetCellStyleRight(nCol, nRow)); + const Style& rBRFromLeft(GetCellStyleBottom(nCol, nRow)); StyleVectorTable aEnd; const basegfx::B2DVector aAxisB(-aX -aY); @@ -1191,8 +1194,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( { /// bottom-left and top-right Style Tables /// Fill bottom-left Style Table - const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow)); - const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow)); + const Style& rBLFromTop(GetCellStyleLeft(nCol, nRow)); + const Style& rBLFromBottom(GetCellStyleBottom(nCol, nRow)); StyleVectorTable aStart; const basegfx::B2DVector aAxisA(aX - aY); @@ -1201,8 +1204,8 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( aStart.sort(); /// Fill top-right Style Table - const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow)); - const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow)); + const Style& rTRFromLeft(GetCellStyleTop(nCol, nRow)); + const Style& rTRFromBottom(GetCellStyleRight(nCol, nRow)); StyleVectorTable aEnd; const basegfx::B2DVector aAxisB(aY - aX); commit b386311104c52e61b86be48e9ffe8417e9ff1fec Author: Armin Le Grand <armin.le.gr...@cib.de> Date: Thu Jan 18 17:07:43 2018 +0100 BorderlineFix: Need to redesign Borderline paint for Calc To fix some errors, need to change svx::frame::Array conversion to Primitives, especially regarding handling of merged cells. These make problems in the currtent form where the full extended merged cell tries to be converted. This is bad for cropped stuff and also wrong for double-line stuff attaching to a merged cell. The solution is to handle cells single and merge created primitives which is more expensive but will work. This will involve special handling for X-Ed (crossed) and 'roated' Cells. Also need to be very careful since all this is used in the meantime for all visualizations of Tables in multiple apps/situations. Change-Id: If0652a3ba97a6f27dd5d782ea22b1514303f3710 diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index ce7f09345a80..2feaab5af8bf 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -150,11 +150,6 @@ private: /// call to set maImplStyle on demand void implEnsureImplStyle(); - /// need information which cell this style info comes from due to needed - /// rotation info (which is in the cell). Rotation depends on the cell. - friend class Cell; - void SetUsingCell(const Cell* pCell) { mpUsingCell = pCell; } - public: /** Constructs an invisible frame style. */ explicit Style(); @@ -203,9 +198,6 @@ public: /** Mirrors this style (exchanges primary and secondary), if it is a double frame style. */ Style& MirrorSelf(); - /** return the Cell using this style (if set) */ - const Cell* GetUsingCell() const { return mpUsingCell; } - bool operator==( const Style& rOther) const; bool operator<( const Style& rOther) const; }; diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx index 2b06d29a41b2..e135e371319c 100644 --- a/include/svx/framelinkarray.hxx +++ b/include/svx/framelinkarray.hxx @@ -291,8 +291,7 @@ public: /** Returns the output range of the cell (nCol,nRow). Returns total output range of merged ranges. */ - basegfx::B2DRange GetCellRange( size_t nCol, size_t nRow ) const; - basegfx::B2DRange GetCellRange( size_t nCellIndex ) const; + basegfx::B2DRange GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const; // mirroring -------------------------------------------------------------- @@ -312,9 +311,6 @@ public: /** Draws the part of the array, that is inside the clipping range. */ drawinglayer::primitive2d::Primitive2DContainer CreateB2DPrimitiveArray() const; - // fill the Cell::maCellIndex entries to allow referencing back from Cell to Array Col/Row coordinates - void AddCellIndices() const; - private: std::unique_ptr<ArrayImpl> mxImpl; }; diff --git a/sc/source/ui/miscdlgs/autofmt.cxx b/sc/source/ui/miscdlgs/autofmt.cxx index a6ffdfe75389..f8f2dae645a6 100644 --- a/sc/source/ui/miscdlgs/autofmt.cxx +++ b/sc/source/ui/miscdlgs/autofmt.cxx @@ -250,7 +250,7 @@ void ScAutoFmtPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCo Size aStrSize; sal_uInt16 nFmtIndex = GetFormatIndex( nCol, nRow ); - const basegfx::B2DRange cellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange cellRange(maArray.GetCellRange( nCol, nRow, true )); Point aPos = Point(basegfx::fround(cellRange.getMinX()), basegfx::fround(cellRange.getMinY())); sal_uInt16 nRightX = 0; bool bJustify = pCurData->GetIncludeJustify(); @@ -374,7 +374,7 @@ void ScAutoFmtPreview::DrawBackground(vcl::RenderContext& rRenderContext) rRenderContext.SetLineColor(); rRenderContext.SetFillColor( pItem->GetColor() ); - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); rRenderContext.DrawRect( tools::Rectangle( basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index 827def10ed2f..50ddd110fa04 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -51,14 +51,12 @@ void Style::implEnsureImplStyle() } Style::Style() : - maImplStyle(), - mpUsingCell(nullptr) + maImplStyle() { } Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : - maImplStyle(new implStyle()), - mpUsingCell(nullptr) + maImplStyle(new implStyle()) { maImplStyle->mnType = nType; maImplStyle->mfPatternScale = fScale; @@ -66,8 +64,7 @@ Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double } Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) : - maImplStyle(new implStyle()), - mpUsingCell(nullptr) + maImplStyle(new implStyle()) { maImplStyle->mnType = nType; maImplStyle->mfPatternScale = fScale; @@ -75,8 +72,7 @@ Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rCo } Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) : - maImplStyle(), - mpUsingCell(nullptr) + maImplStyle() { if(nullptr != pBorder) { diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index 560eefd775ce..ecb3eaace1c6 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -45,10 +45,8 @@ public: long mnAddTop; long mnAddBottom; - SvxRotateMode meRotMode; - double mfOrientation; - basegfx::B2DHomMatrix maCoordinateSystem; - size_t maCellIndex; + SvxRotateMode meRotMode; + double mfOrientation; bool mbMergeOrig; bool mbOverlapX; @@ -57,12 +55,12 @@ public: public: explicit Cell(); - void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; maLeft.SetUsingCell(this); } - void SetStyleRight(const Style& rStyle) { maRight = rStyle; maRight.SetUsingCell(this); } - void SetStyleTop(const Style& rStyle) { maTop = rStyle; maTop.SetUsingCell(this); } - void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; maBottom.SetUsingCell(this); } - void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; maTLBR.SetUsingCell(this); } - void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; maBLTR.SetUsingCell(this); } + void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; } + void SetStyleRight(const Style& rStyle) { maRight = rStyle; } + void SetStyleTop(const Style& rStyle) { maTop = rStyle; } + void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; } + void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; } + void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; } const Style& GetStyleLeft() const { return maLeft; } const Style& GetStyleRight() const { return maRight; } @@ -76,74 +74,54 @@ public: void MirrorSelfX(); - basegfx::B2DHomMatrix const & CreateCoordinateSystem(const Array& rArray) const; - size_t GetCellIndex(const Array& rArray) const; + basegfx::B2DHomMatrix CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const; }; typedef std::vector< long > LongVec; typedef std::vector< Cell > CellVec; -size_t Cell::GetCellIndex(const Array& rArray) const +basegfx::B2DHomMatrix Cell::CreateCoordinateSystem(const Array& rArray, size_t nCol, size_t nRow, bool bExpandMerged) const { - if(static_cast<size_t>(-1) == maCellIndex) - { - rArray.AddCellIndices(); - } - - return maCellIndex; -} + basegfx::B2DHomMatrix aRetval; + const basegfx::B2DRange aRange(rArray.GetCellRange(nCol, nRow, bExpandMerged)); -basegfx::B2DHomMatrix const & Cell::CreateCoordinateSystem(const Array& rArray) const -{ - if(!maCoordinateSystem.isIdentity()) + if(!aRange.isEmpty()) { - return maCoordinateSystem; - } - - const size_t nCellIndex(GetCellIndex(rArray)); + basegfx::B2DPoint aOrigin(aRange.getMinimum()); + basegfx::B2DVector aX(aRange.getWidth(), 0.0); + basegfx::B2DVector aY(0.0, aRange.getHeight()); - if(static_cast<size_t>(-1) != nCellIndex) - { - const basegfx::B2DRange aRange(rArray.GetCellRange(nCellIndex)); - - if(!aRange.isEmpty()) + if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode) { - basegfx::B2DPoint aOrigin(aRange.getMinimum()); - basegfx::B2DVector aX(aRange.getWidth(), 0.0); - basegfx::B2DVector aY(0.0, aRange.getHeight()); + // when rotated, adapt values. Get Skew (cos/sin == 1/tan) + const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); - if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode) + switch (meRotMode) { - // when rotated, adapt values. Get Skew (cos/sin == 1/tan) - const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); - - switch (meRotMode) - { - case SvxRotateMode::SVX_ROTATE_MODE_TOP: - // shear Y-Axis - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_CENTER: - // shear origin half, Y full - aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: - // shear origin full, Y full - aOrigin.setX(aOrigin.getX() + fSkew); - aY.setX(-fSkew); - break; - default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above - break; - } + case SvxRotateMode::SVX_ROTATE_MODE_TOP: + // shear Y-Axis + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_CENTER: + // shear origin half, Y full + aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: + // shear origin full, Y full + aOrigin.setX(aOrigin.getX() + fSkew); + aY.setX(-fSkew); + break; + default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above + break; } - - // use column vectors as coordinate axes, homogen column for translation - const_cast<Cell*>(this)->maCoordinateSystem = basegfx::utils::createCoordinateSystemTransform(aOrigin, aX, aY); } + + // use column vectors as coordinate axes, homogen column for translation + aRetval = basegfx::utils::createCoordinateSystemTransform(aOrigin, aX, aY); } - return maCoordinateSystem; + return aRetval; } Cell::Cell() : @@ -153,8 +131,6 @@ Cell::Cell() : mnAddBottom( 0 ), meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ), mfOrientation( 0.0 ), - maCoordinateSystem(), - maCellIndex(static_cast<size_t>(-1)), mbMergeOrig( false ), mbOverlapX( false ), mbOverlapY( false ) @@ -168,8 +144,6 @@ void Cell::MirrorSelfX() maLeft.MirrorSelf(); maRight.MirrorSelf(); mfOrientation = -mfOrientation; - maCoordinateSystem.identity(); - maCellIndex = static_cast<size_t>(-1); } @@ -864,17 +838,12 @@ long Array::GetHeight() const return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 ); } -basegfx::B2DRange Array::GetCellRange( size_t nCellIndex ) const -{ - return GetCellRange(nCellIndex % GetColCount(), nCellIndex / GetColCount()); -} - -basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow ) const +basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow, bool bExpandMerged ) const { - size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); - size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); - size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); - size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); + size_t nFirstCol = bExpandMerged ? mxImpl->GetMergedFirstCol( nCol, nRow ) : nCol; + size_t nFirstRow = bExpandMerged ? mxImpl->GetMergedFirstRow( nCol, nRow ) : nRow; + size_t nLastCol = bExpandMerged ? mxImpl->GetMergedLastCol( nCol, nRow ) : nCol; + size_t nLastRow = bExpandMerged ? mxImpl->GetMergedLastRow( nCol, nRow ) : nRow; const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); tools::Rectangle aRect(aPoint, aSize); @@ -1023,45 +992,6 @@ void HelperCreateVerticalEntry( ); } -void HelperCreateEntry(const Array& rArray, const Style& rStyle, drawinglayer::primitive2d::Primitive2DContainer& rSequence, const Color* pForceColor) -{ - const Cell* pCell = rStyle.GetUsingCell(); - - if(nullptr != pCell) - { - const size_t nCellIndex(pCell->GetCellIndex(rArray)); - - if(static_cast<size_t>(-1) != nCellIndex) - { - size_t col(nCellIndex % rArray.GetColCount()); - size_t row(nCellIndex / rArray.GetColCount()); - const bool bL(&rStyle == &pCell->GetStyleLeft()); - const bool bR(&rStyle == &pCell->GetStyleRight()); - const bool bT(&rStyle == &pCell->GetStyleTop()); - const bool bB(&rStyle == &pCell->GetStyleBottom()); - - if(bL || bR || bT || bB) - { - const basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(rArray)); - const basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); - const basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); - const basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); - - if(bL || bR) - { - // left/right - HelperCreateVerticalEntry(rArray, rStyle, bL ? col : col + 1, row, aOrigin, aX, aY, rSequence, bL, pForceColor); - } - else if(bT || bB) - { - // top/bottom - HelperCreateHorizontalEntry(rArray, rStyle, col, bT ? row : row + 1, aOrigin, aX, aY, rSequence, bT, pForceColor); - } - } - } - } -} - void HelperMergeInB2DPrimitiveArray( const drawinglayer::primitive2d::Primitive2DContainer& rSource, drawinglayer::primitive2d::Primitive2DContainer& rTarget) @@ -1116,23 +1046,27 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nLastCol - nFirstCol + 1); drawinglayer::primitive2d::Primitive2DContainer aCrossSequence; + // remember for which merged cells crossed lines were already created. To + // do so, hold the size_t cell index in a set for fast check + std::set< size_t > aMergedCells; + for (size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow) { for (size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol) { + // get Cell and CoordinateSystem (*only* for this Cell), check if used (not empty) const Cell& rCell = CELL(nCol, nRow); - const basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this)); - const basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); - const basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); + basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this, nCol, nRow, false)); + basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0)); + basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1)); if(!aX.equalZero() && !aY.equalZero()) { - size_t _nFirstCol = mxImpl->GetMergedFirstCol(nCol, nRow); - size_t _nFirstRow = mxImpl->GetMergedFirstRow(nCol, nRow); - size_t _nLastCol = mxImpl->GetMergedLastCol(nCol, nRow); - size_t _nLastRow = mxImpl->GetMergedLastRow(nCol, nRow); - const basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); - + // for getting correct Style(s) for merged Cells, we need the First(Col/Row) + // for access (see accessing Styles below) + const size_t _nFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow)); + const size_t _nFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow)); + basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2)); const bool bOverlapX(rCell.mbOverlapX); const bool bOverlapY(rCell.mbOverlapY); const bool bFirstCol(nCol == nFirstCol); @@ -1140,116 +1074,152 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( const bool bFirstRow(nRow == nFirstRow); const bool bLastRow(nRow == nLastRow); - if (!bOverlapX || bFirstRow) + // create upper line for this Cell + if (!bOverlapY // true for first line in merged cells or cells + || bFirstRow) // true for non_Calc usages of this tooling { const Style& rTop = GetCellStyleTop(_nFirstCol, _nFirstRow); if(rTop.IsUsed()) { - HelperCreateEntry(*this, rTop, aHorizontalSequence, pForceColor); + HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, aHorizontalSequence, true, pForceColor); } } - if (bLastRow) + // create lower line for this Cell + if (bLastRow) // true for non_Calc usages of this tooling { const Style& rBottom = GetCellStyleBottom(_nFirstCol, _nFirstRow); if(rBottom.IsUsed()) { - HelperCreateEntry(*this, rBottom, aHorizontalSequence, pForceColor); + HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, aHorizontalSequence, false, pForceColor); } } - if (!bOverlapY || bFirstCol) + // create left line for this Cell + if (!bOverlapX // true for first column in merged cells or cells + || bFirstCol) // true for non_Calc usages of this tooling { const Style& rLeft(GetCellStyleLeft(_nFirstCol, _nFirstRow)); if(rLeft.IsUsed()) { - HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor); + HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nFirstCol], true, pForceColor); } } - if (bLastCol) + // create right line for this Cell + if (bLastCol) // true for non_Calc usages of this tooling { const Style& rRight(GetCellStyleRight(_nFirstCol, _nFirstRow)); if(rRight.IsUsed()) { - HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor); + HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, aVerticalSequences[nCol - nFirstCol], false, pForceColor); } } - if ((!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) || (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow)) + // check for crossed lines, these need special treatment, especially + // for merged cells, see below + const Style& rTLBR = GetCellStyleTLBR(_nFirstCol, _nFirstRow); + const Style& rBLTR = GetCellStyleBLTR(_nFirstCol, _nFirstRow); + + if(rTLBR.IsUsed() || rBLTR.IsUsed()) { - const Style& rTLBR = GetCellStyleTLBR(_nFirstCol, _nFirstRow); - if(rTLBR.IsUsed()) + bool bContinue(true); + + if(rCell.IsMerged()) { - /// top-left and bottom-right Style Tables - /// Fill top-left Style Table - const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow)); - const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX + aY); - - aStart.add(rTLFromRight, aAxisA, aX, false); - aStart.add(rTLFromBottom, aAxisA, aY, false); - aStart.sort(); - - /// Fill bottom-right Style Table - const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow)); - const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(-aX -aY); - - aEnd.add(rBRFromBottom, aAxisB, -aY, true); - aEnd.add(rBRFromLeft, aAxisB, -aX, true); - aEnd.sort(); - - CreateBorderPrimitives( - aCrossSequence, - aOrigin, - aX + aY, - rTLBR, - aStart, - aEnd, - pForceColor - ); + // first check if this merged cell was already handled + const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nFirstCol, _nFirstRow)); + bContinue = (aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell)); + + if(bContinue) + { + // not found, add now to mark as handled + aMergedCells.insert(nIndexOfMergedCell); + + // when merged, get extended coordinate system and dependent values + aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true); + aX = basegfx::utils::getColumn(aCoordinateSystem, 0); + aY = basegfx::utils::getColumn(aCoordinateSystem, 1); + aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2); + } } - const Style& rBLTR = GetCellStyleBLTR(_nFirstCol, _nFirstRow); - if(rBLTR.IsUsed()) + if(bContinue) { - /// bottom-left and top-right Style Tables - /// Fill bottom-left Style Table - const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow)); - const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow)); - StyleVectorTable aStart; - const basegfx::B2DVector aAxisA(aX - aY); - - aStart.add(rBLFromTop, aAxisA, -aY, true); - aStart.add(rBLFromBottom, aAxisA, aX, false); - aStart.sort(); - - /// Fill top-right Style Table - const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow)); - const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow)); - StyleVectorTable aEnd; - const basegfx::B2DVector aAxisB(aY - aX); - - aEnd.add(rTRFromLeft, aAxisB, -aX, true); - aEnd.add(rTRFromBottom, aAxisB, aY, false); - aEnd.sort(); - - CreateBorderPrimitives( - aCrossSequence, - aOrigin + aY, - aX - aY, - rBLTR, - aStart, - aEnd, - pForceColor - ); + const size_t _nLastCol(mxImpl->GetMergedLastCol(nCol, nRow)); + const size_t _nLastRow(mxImpl->GetMergedLastRow(nCol, nRow)); + + if(rTLBR.IsUsed()) + { + /// top-left and bottom-right Style Tables + /// Fill top-left Style Table + const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow)); + const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow)); + StyleVectorTable aStart; + const basegfx::B2DVector aAxisA(aX + aY); + + aStart.add(rTLFromRight, aAxisA, aX, false); + aStart.add(rTLFromBottom, aAxisA, aY, false); + aStart.sort(); + + /// Fill bottom-right Style Table + const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow)); + const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow)); + StyleVectorTable aEnd; + const basegfx::B2DVector aAxisB(-aX -aY); + + aEnd.add(rBRFromBottom, aAxisB, -aY, true); + aEnd.add(rBRFromLeft, aAxisB, -aX, true); + aEnd.sort(); + + CreateBorderPrimitives( + aCrossSequence, + aOrigin, + aX + aY, + rTLBR, + aStart, + aEnd, + pForceColor + ); + } + + if(rBLTR.IsUsed()) + { + /// bottom-left and top-right Style Tables + /// Fill bottom-left Style Table + const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow)); + const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow)); + StyleVectorTable aStart; + const basegfx::B2DVector aAxisA(aX - aY); + + aStart.add(rBLFromTop, aAxisA, -aY, true); + aStart.add(rBLFromBottom, aAxisA, aX, false); + aStart.sort(); + + /// Fill top-right Style Table + const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow)); + const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow)); + StyleVectorTable aEnd; + const basegfx::B2DVector aAxisB(aY - aX); + + aEnd.add(rTRFromLeft, aAxisB, -aX, true); + aEnd.add(rTRFromBottom, aAxisB, aY, false); + aEnd.sort(); + + CreateBorderPrimitives( + aCrossSequence, + aOrigin + aY, + aX - aY, + rBLTR, + aStart, + aEnd, + pForceColor + ); + } } } } @@ -1259,6 +1229,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange( // to stay compatible, create order as it was formally. Also try to // merge primitives as far as possible HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence); + for(const auto& aVert : aVerticalSequences) { HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence); @@ -1279,19 +1250,9 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveArray() return aPrimitives; } -void Array::AddCellIndices() const -{ - for (size_t a(0); a < mxImpl->maCells.size(); a++) - { - const_cast<Array*>(this)->mxImpl->maCells[a].maCellIndex = a; - } -} - #undef ORIGCELL #undef CELLACC #undef CELL - - #undef DBG_FRAME_CHECK_ROW_1 #undef DBG_FRAME_CHECK_COL_1 #undef DBG_FRAME_CHECK_COLROW @@ -1299,7 +1260,6 @@ void Array::AddCellIndices() const #undef DBG_FRAME_CHECK_COL #undef DBG_FRAME_CHECK - } } diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx index d54e1b083e65..f65693d44b58 100644 --- a/svx/source/dialog/frmsel.cxx +++ b/svx/source/dialog/frmsel.cxx @@ -410,7 +410,7 @@ void FrameSelectorImpl::InitBorderGeometry() { for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow ) { - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); const tools::Rectangle aRect( basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())); @@ -469,7 +469,7 @@ void FrameSelectorImpl::InitBorderGeometry() for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow ) { // the usable area between horizonal/vertical frame borders of current quadrant - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); const tools::Rectangle aRect( basegfx::fround(aCellRange.getMinX()) + nClV + 1, basegfx::fround(aCellRange.getMinY()) + nClH + 1, basegfx::fround(aCellRange.getMaxX()) - nClV + 1, basegfx::fround(aCellRange.getMaxY()) - nClH + 1); diff --git a/sw/source/ui/table/tautofmt.cxx b/sw/source/ui/table/tautofmt.cxx index 7a342f1ff83e..5336024736fa 100644 --- a/sw/source/ui/table/tautofmt.cxx +++ b/sw/source/ui/table/tautofmt.cxx @@ -716,7 +716,7 @@ MAKENUMSTR: SvtScriptedTextHelper aScriptedText(rRenderContext); Size aStrSize; sal_uInt8 nFormatIndex = GetFormatIndex( nCol, nRow ); - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); const tools::Rectangle cellRect( basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())); @@ -811,7 +811,7 @@ void AutoFormatPreview::DrawBackground(vcl::RenderContext& rRenderContext) rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); rRenderContext.SetLineColor(); rRenderContext.SetFillColor(aBrushItem.GetColor()); - const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow, true )); rRenderContext.DrawRect( tools::Rectangle( basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), commit ea20bc176cbf575e39c602a91dd3e6919b3fc31e Author: Stephan Bergmann <sberg...@redhat.com> Date: Mon Jan 22 18:49:40 2018 +0100 USHRT_MAX -> SAL_MAX_UINT16 ...that had presumably been forgotten when the surrounding code had been changed from USHORT to sal_uInt16 in cd42389ad67b403a07a0dda8e2a6e213def49251 "removetooltypes01: #i112600# remove tooltypes from sc". Plus, turning the preprocessor checks into static_asserts. Change-Id: I78271f7027af701699865913813d6dea8b0c570b Reviewed-on: https://gerrit.libreoffice.org/48358 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Stephan Bergmann <sberg...@redhat.com> diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index bedeaa75c7c9..f08c09ce69eb 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -284,10 +284,8 @@ bool ScInterpreter::CreateDoubleArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, { // Old Add-Ins are hard limited to sal_uInt16 values. -#if MAXCOLCOUNT_DEFINE > USHRT_MAX -#error Add check for columns > USHRT_MAX! -#endif - if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX) + static_assert(MAXCOLCOUNT <= SAL_MAX_UINT16, "Add check for columns > SAL_MAX_UINT16!"); + if (nRow1 > SAL_MAX_UINT16 || nRow2 > SAL_MAX_UINT16) return false; sal_uInt16 nCount = 0; @@ -369,10 +367,8 @@ bool ScInterpreter::CreateStringArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, { // Old Add-Ins are hard limited to sal_uInt16 values. -#if MAXCOLCOUNT_DEFINE > USHRT_MAX -#error Add check for columns > USHRT_MAX! -#endif - if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX) + static_assert(MAXCOLCOUNT <= SAL_MAX_UINT16, "Add check for columns > SAL_MAX_UINT16!"); + if (nRow1 > SAL_MAX_UINT16 || nRow2 > SAL_MAX_UINT16) return false; sal_uInt16 nCount = 0; @@ -468,10 +464,8 @@ bool ScInterpreter::CreateCellArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, { // Old Add-Ins are hard limited to sal_uInt16 values. -#if MAXCOLCOUNT_DEFINE > USHRT_MAX -#error Add check for columns > USHRT_MAX! -#endif - if (nRow1 > USHRT_MAX || nRow2 > USHRT_MAX) + static_assert(MAXCOLCOUNT <= SAL_MAX_UINT16, "Add check for columns > SAL_MAX_UINT16!"); + if (nRow1 > SAL_MAX_UINT16 || nRow2 > SAL_MAX_UINT16) return false; sal_uInt16 nCount = 0; commit 8d37253e50aca502a1f80ef648deb6f5178c4c46 Author: Matthias Seidel <msei...@apache.org> Date: Fri Jan 19 18:45:59 2018 +0000 Fixed wording (cherry picked from commit 106d959da4cccda4c0342715cc06854f152c99d1) Change-Id: I51c86dfef0e0eff59ce2892d8ea07dd066fd9667 diff --git a/include/svx/gallery.hxx b/include/svx/gallery.hxx index cb2da0a856ba..19a2c9e226c7 100644 --- a/include/svx/gallery.hxx +++ b/include/svx/gallery.hxx @@ -44,7 +44,7 @@ // * share/gallery (theme files are identified by id) // // Since galleries may be copied from older offices to newer, do *never* change -// this IDs except adding new ones (and adapting GALLERY_THEME_LAST). The ID +// these IDs except adding new ones (and adapting GALLERY_THEME_LAST). The ID // *is* written into the binary file *.thm (which is a gallery theme combined // of three files, *.thm, *.sdv and *.sdg) commit 8b1a83bffe35ae0e71735569512c1586bcb37b25 Author: Michael Stahl <mst...@redhat.com> Date: Mon Jan 22 19:48:06 2018 +0100 ofz#5566 sw: HTML import: ignore <DIV> in table structure elements Looking at the HTML4 DTD https://www.w3.org/TR/html4/sgml/dtd.html, inside TABLE only various elements defining the structure of the table allowed, except inside cells (TD and TH elements). DIV in a table but outside cells may cause cursor positions to go off the rails, so better ignore such invalid DIV tags. Change-Id: Ia6195d80670631669c252d572242874b13642b74 Reviewed-on: https://gerrit.libreoffice.org/48359 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx index d2fff4c1a907..8ed2ca32707e 100644 --- a/sw/source/filter/html/htmltab.cxx +++ b/sw/source/filter/html/htmltab.cxx @@ -19,6 +19,7 @@ #include <memory> #include <hintids.hxx> +#include <comphelper/flagguard.hxx> #include <vcl/svapp.hxx> #include <vcl/wrkwin.hxx> #include <editeng/boxitem.hxx> @@ -3133,6 +3134,7 @@ void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, bool bReadOptions, if( !IsParserWorking() && !m_pPendStack ) return; + ::comphelper::FlagRestorationGuard g(m_isInTableStructure, false); std::unique_ptr<CellSaveStruct> xSaveStruct; HtmlTokenId nToken = HtmlTokenId::NONE; @@ -4946,6 +4948,7 @@ std::shared_ptr<HTMLTable> SwHTMLParser::BuildTable(SvxAdjust eParentAdjust, if (!IsParserWorking() && !m_pPendStack) return std::shared_ptr<HTMLTable>(); + ::comphelper::FlagRestorationGuard g(m_isInTableStructure, true); HtmlTokenId nToken = HtmlTokenId::NONE; bool bPending = false; std::unique_ptr<TableSaveStruct> xSaveStruct; diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx index aad798936453..4d939b4cba8d 100644 --- a/sw/source/filter/html/swhtml.cxx +++ b/sw/source/filter/html/swhtml.cxx @@ -300,6 +300,7 @@ SwHTMLParser::SwHTMLParser( SwDoc* pD, SwPaM& rCursor, SvStream& rIn, m_bRemoveHidden( false ), m_bBodySeen( false ), m_bReadingHeaderOrFooter( false ), + m_isInTableStructure(false), m_nTableDepth( 0 ), m_pTempViewFrame(nullptr) { @@ -1557,26 +1558,32 @@ void SwHTMLParser::NextToken( HtmlTokenId nToken ) // divisions case HtmlTokenId::DIVISION_ON: case HtmlTokenId::CENTER_ON: - if( m_nOpenParaToken != HtmlTokenId::NONE ) + if (!m_isInTableStructure) { - if( IsReadPRE() ) - m_nOpenParaToken = HtmlTokenId::NONE; - else - EndPara(); + if (m_nOpenParaToken != HtmlTokenId::NONE) + { + if (IsReadPRE()) + m_nOpenParaToken = HtmlTokenId::NONE; + else + EndPara(); + } + NewDivision( nToken ); } - NewDivision( nToken ); break; case HtmlTokenId::DIVISION_OFF: case HtmlTokenId::CENTER_OFF: - if( m_nOpenParaToken != HtmlTokenId::NONE ) + if (!m_isInTableStructure) { - if( IsReadPRE() ) - m_nOpenParaToken = HtmlTokenId::NONE; - else - EndPara(); + if (m_nOpenParaToken != HtmlTokenId::NONE) + { + if (IsReadPRE()) + m_nOpenParaToken = HtmlTokenId::NONE; + else + EndPara(); + } + EndDivision(); } - EndDivision(); break; case HtmlTokenId::MULTICOL_ON: diff --git a/sw/source/filter/html/swhtml.hxx b/sw/source/filter/html/swhtml.hxx index cd43c8f3f065..9674a8892eaf 100644 --- a/sw/source/filter/html/swhtml.hxx +++ b/sw/source/filter/html/swhtml.hxx @@ -492,6 +492,7 @@ class SwHTMLParser : public SfxHTMLParser, public SwClient bool m_bBodySeen : 1; bool m_bReadingHeaderOrFooter : 1; + bool m_isInTableStructure; sal_Int32 m_nTableDepth; commit 551e6881538189d03604730456ddd5563b1872dd Author: Caolán McNamara <caol...@redhat.com> Date: Mon Jan 22 17:37:33 2018 +0000 its defineresource not define resource regression from commit 64d624b65124ac02d8ee59b135593fd9d8eb9067 Date: Sat Jan 9 22:55:28 2016 +0100 Fix typos Change-Id: I9a5940027423ff0791fa7da0b79b617412ce6b86 Reviewed-on: https://gerrit.libreoffice.org/21209 Tested-by: Jenkins <c...@libreoffice.org> Change-Id: Ifdf45e97b81523c84c73b93d14ed75b7b6909f77 Reviewed-on: https://gerrit.libreoffice.org/48355 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index fc3ef412cb34..7d0d12772c42 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -3058,7 +3058,7 @@ sal_Int32 PDFWriterImpl::createToUnicodeCMap( sal_uInt8 const * pEncoding, } aContents.append( "endbfchar\n" "endcmap\n" - "CMapName currentdict /CMap define resource pop\n" + "CMapName currentdict /CMap defineresource pop\n" "end\n" "end\n" ); SvMemoryStream aStream; commit 44af50465a02b6f5566be45913a34fdbdba90133 Author: Telesto <tele...@surfxs.nl> Date: Mon Jan 22 16:49:21 2018 +0200 tdf#112153: Set button theme properly Change-Id: I0665880c0d0348fcbb3bcf04d9172405c8e31eb7 Reviewed-on: https://gerrit.libreoffice.org/48334 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Tor Lillqvist <t...@collabora.com> diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx index d311526c0168..811960f1b92e 100644 --- a/vcl/osx/salnativewidgets.cxx +++ b/vcl/osx/salnativewidgets.cxx @@ -106,11 +106,11 @@ static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue ) break; case ButtonValue::Off: + case ButtonValue::DontKnow: return kThemeButtonOff; break; case ButtonValue::Mixed: - case ButtonValue::DontKnow: default: return kThemeButtonMixed; break; commit ce88f2a7374bb8c53d57e8263e0701db19d62f30 Author: Telesto <tele...@surfxs.nl> Date: Mon Jan 22 15:16:52 2018 +0200 tdf#114985: Tell NSWindow to never use automatic window tabbing Based on https://codereview.chromium.org/2325313002/ Change-Id: I8838449d57b1d1b010491a405c87645d38199fdf Reviewed-on: https://gerrit.libreoffice.org/48330 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Tor Lillqvist <t...@collabora.com> diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index f805df6959d4..26f826467677 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -75,6 +75,11 @@ SAL_WNODEPRECATED_DECLARATIONS_PUSH SAL_WNODEPRECATED_DECLARATIONS_POP assert( pEvent ); [NSApp postEvent: pEvent atStart: NO]; + + if( [NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)] ) + { + NSWindow.allowsAutomaticWindowTabbing = NO; + } } -(void)sendEvent:(NSEvent*)pEvent commit f58a16d5987c8e8c16580c514ce0c7b0895b4105 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Mon Jan 22 22:12:04 2018 +0100 tdf#114460 vcl: handle nested parentheses in PDF roundtrip The roundtrip of the pdf image failed due to this. Change-Id: I88a9657e242dd2659f9bf06233e5fcbfeb43ceb5 Reviewed-on: https://gerrit.libreoffice.org/48362 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@libreoffice.org> diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 6921683d5054..af1eea1f57cf 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -2015,11 +2015,20 @@ bool PDFLiteralStringElement::Read(SvStream& rStream) nPrevCh = ch; rStream.ReadChar(ch); + // Start with 1 nesting level as we read a '(' above already. + int nDepth = 1; OStringBuffer aBuf; while (!rStream.eof()) { + if (ch == '(' && nPrevCh != '\\') + ++nDepth; + if (ch == ')' && nPrevCh != '\\') + --nDepth; + + if (nDepth == 0) { + // ')' of the outermost '(' is reached. m_aValue = aBuf.makeStringAndClear(); SAL_INFO("vcl.filter", "PDFLiteralStringElement::Read: m_aValue is '" << m_aValue << "'"); return true; diff --git a/xmlsecurity/qa/unit/pdfsigning/data/tdf114460.pdf b/xmlsecurity/qa/unit/pdfsigning/data/tdf114460.pdf new file mode 100644 index 000000000000..a736e5bb90cd Binary files /dev/null and b/xmlsecurity/qa/unit/pdfsigning/data/tdf114460.pdf differ diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx index b36d926a4a34..cb7fd4cfe945 100644 --- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx +++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx @@ -450,6 +450,8 @@ void PDFSigningTest::testTokenize() // File that's intentionally smaller than 1024 bytes. "small.pdf", "tdf107149.pdf", + // Nested parentheses were not handled. + "tdf114460.pdf", }; for (const auto& rName : aNames) commit 90ae1e1bbbce7be9b2ff7add75923b1891e65df6 Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Mon Jan 22 16:00:10 2018 +0100 EPUB export, fxl: silence Page <N> toc entries when have chapter names The EPUB ToC is now on par with the PDF ToC. Change-Id: Iea714fdb68c825aa14345037e909c354bbd7cf00 Reviewed-on: https://gerrit.libreoffice.org/48346 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> diff --git a/external/libepubgen/libepubgen-epub3.patch.1 b/external/libepubgen/libepubgen-epub3.patch.1 index bcec187b5218..f102eaefe7a6 100644 --- a/external/libepubgen/libepubgen-epub3.patch.1 +++ b/external/libepubgen/libepubgen-epub3.patch.1 @@ -355,3 +355,71 @@ index 8e88adb..38ddcdf 100644 -- 2.13.6 +From b6081f659e3000d9f3d5851278d8abdd33448353 Mon Sep 17 00:00:00 2001 +From: Miklos Vajna <vmik...@collabora.co.uk> +Date: Mon, 22 Jan 2018 15:54:43 +0100 +Subject: [PATCH] fixed layout: avoid Page <N> entries when chapter names are + provided + +--- + src/lib/EPUBHTMLManager.cpp | 31 ++++++++++++++++++------------- + src/test/EPUBTextGeneratorTest.cpp | 16 ++++++++++++++++ + 2 files changed, 34 insertions(+), 13 deletions(-) + +diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp +index d35bc3f..35d82e8 100644 +--- a/src/lib/EPUBHTMLManager.cpp ++++ b/src/lib/EPUBHTMLManager.cpp +@@ -7,6 +7,7 @@ + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + ++#include <algorithm> + #include <cassert> + #include <iomanip> + #include <sstream> +@@ -91,24 +92,28 @@ void EPUBHTMLManager::writeTocTo(EPUBXMLSink &sink, const EPUBPath &tocPath, int + { + if (version >= 30) + { ++ bool hasChapterNames = std::find_if(m_paths.begin(), m_paths.end(), [](const EPUBPath &path) ++ { ++ return !path.getChapters().empty(); ++ }) != m_paths.end(); + for (std::vector<EPUBPath>::size_type i = 0; m_paths.size() != i; ++i) + { + const std::vector<std::string> &chapters = m_paths[i].getChapters(); +- if (!chapters.empty()) ++ for (const auto &chapter : chapters) + { +- for (const auto &chapter : chapters) +- { +- sink.openElement("li"); +- librevenge::RVNGPropertyList anchorAttrs; +- anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); +- sink.openElement("a", anchorAttrs); +- std::ostringstream label; +- sink.insertCharacters(chapter.c_str()); +- sink.closeElement("a"); +- sink.closeElement("li"); +- } +- continue; ++ sink.openElement("li"); ++ librevenge::RVNGPropertyList anchorAttrs; ++ anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); ++ sink.openElement("a", anchorAttrs); ++ std::ostringstream label; ++ sink.insertCharacters(chapter.c_str()); ++ sink.closeElement("a"); ++ sink.closeElement("li"); + } ++ if (hasChapterNames) ++ // Chapter names are provided for this document, so never write Page ++ // <N> entries. ++ continue; + + sink.openElement("li"); + librevenge::RVNGPropertyList anchorAttrs; +-- +2.13.6 + diff --git a/writerperfect/Module_writerperfect.mk b/writerperfect/Module_writerperfect.mk index 6fa274bc8ce5..01f8a0dc5e59 100644 --- a/writerperfect/Module_writerperfect.mk +++ b/writerperfect/Module_writerperfect.mk @@ -40,7 +40,7 @@ $(eval $(call gb_Module_add_check_targets,writerperfect,\ $(eval $(call gb_Module_add_slowcheck_targets,writerperfect,\ CppunitTest_writerperfect_calc \ CppunitTest_writerperfect_draw \ - CppunitTest_writerperfect_epubexport \ + $(if $(SYSTEM_EPUBGEN),,CppunitTest_writerperfect_epubexport) \ CppunitTest_writerperfect_import \ CppunitTest_writerperfect_impress \ CppunitTest_writerperfect_writer \ commit a54787669b9283efdfdd18b0cbafc3184cdde58f Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Mon Jan 22 15:18:45 2018 +0100 EPUB export, fixed layout: add chapter names to the navigation document Extend vcl::PDFExtOutDevData so that it's possible to use it outside the PDF export; this way the EPUB export can know which chapters start on which page. This means fixed and reflowable layout has the same table of contents, instead of just Page <N> in the fixed layout case. Change-Id: I935fb23c66ec747431b91e83b0e677d4e5f704b9 Reviewed-on: https://gerrit.libreoffice.org/48332 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@libreoffice.org> diff --git a/external/libepubgen/libepubgen-epub3.patch.1 b/external/libepubgen/libepubgen-epub3.patch.1 index 4b7fe5215f05..bcec187b5218 100644 --- a/external/libepubgen/libepubgen-epub3.patch.1 +++ b/external/libepubgen/libepubgen-epub3.patch.1 @@ -197,3 +197,161 @@ index bdf3bf0..cb4efee 100644 -- 2.13.6 +From c081609849b18113340c39a73b6af432a103a102 Mon Sep 17 00:00:00 2001 +From: Miklos Vajna <vmik...@collabora.co.uk> +Date: Mon, 22 Jan 2018 14:39:19 +0100 +Subject: [PATCH] fixed layout: allow defining chapter names + +Fixed layout normally just works with SVG images (one image / page), but +readable navigation document is still expected, e.g. PDF provides it. So +add a way to mention what chapters start on a given page. +--- + src/lib/EPUBHTMLManager.cpp | 25 +++++++++++++++++++++++++ + src/lib/EPUBHTMLManager.h | 3 +++ + src/lib/EPUBPath.cpp | 11 +++++++++++ + src/lib/EPUBPath.h | 4 ++++ + src/lib/EPUBTextGenerator.cpp | 15 +++++++++++++++ + src/test/EPUBTextGeneratorTest.cpp | 37 +++++++++++++++++++++++++++++++++++++ + 6 files changed, 95 insertions(+) + +diff --git a/src/lib/EPUBHTMLManager.cpp b/src/lib/EPUBHTMLManager.cpp +index 5e96d1d..d35bc3f 100644 +--- a/src/lib/EPUBHTMLManager.cpp ++++ b/src/lib/EPUBHTMLManager.cpp +@@ -93,6 +93,23 @@ void EPUBHTMLManager::writeTocTo(EPUBXMLSink &sink, const EPUBPath &tocPath, int + { + for (std::vector<EPUBPath>::size_type i = 0; m_paths.size() != i; ++i) + { ++ const std::vector<std::string> &chapters = m_paths[i].getChapters(); ++ if (!chapters.empty()) ++ { ++ for (const auto &chapter : chapters) ++ { ++ sink.openElement("li"); ++ librevenge::RVNGPropertyList anchorAttrs; ++ anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); ++ sink.openElement("a", anchorAttrs); ++ std::ostringstream label; ++ sink.insertCharacters(chapter.c_str()); ++ sink.closeElement("a"); ++ sink.closeElement("li"); ++ } ++ continue; ++ } ++ + sink.openElement("li"); + librevenge::RVNGPropertyList anchorAttrs; + anchorAttrs.insert("href", m_paths[i].relativeTo(tocPath).str().c_str()); +@@ -140,6 +157,14 @@ void EPUBHTMLManager::insertHeadingText(const std::string &text) + m_paths.back().appendTitle(text); + } + ++void EPUBHTMLManager::addChapterName(const std::string &text) ++{ ++ if (m_paths.empty()) ++ return; ++ ++ m_paths.back().addChapter(text); ++} ++ + bool EPUBHTMLManager::hasHeadingText() const + { + if (m_paths.empty()) +diff --git a/src/lib/EPUBHTMLManager.h b/src/lib/EPUBHTMLManager.h +index 157896b..d48ddf2 100644 +--- a/src/lib/EPUBHTMLManager.h ++++ b/src/lib/EPUBHTMLManager.h +@@ -51,6 +51,9 @@ public: + /// Appends text to the title of the current heading. + void insertHeadingText(const std::string &text); + ++ /// Registers a chapter name for the current page (fixed layout case). ++ void addChapterName(const std::string &text); ++ + /// If the current heading has a title. + bool hasHeadingText() const; + +diff --git a/src/lib/EPUBPath.cpp b/src/lib/EPUBPath.cpp +index e1c05ed..be24de5 100644 +--- a/src/lib/EPUBPath.cpp ++++ b/src/lib/EPUBPath.cpp +@@ -54,6 +54,7 @@ EPUBPath::Relative::Relative(const std::vector<std::string> &components) + EPUBPath::EPUBPath(const std::string &path) + : m_components() + , m_title() ++ , m_chapters() + { + const std::string trimmed(algorithm::trim_left_copy_if(path, algorithm::is_any_of("/"))); + algorithm::split(m_components, trimmed, algorithm::is_any_of("/"), algorithm::token_compress_on); +@@ -116,6 +117,16 @@ void EPUBPath::appendTitle(const std::string &title) + m_title += title; + } + ++void EPUBPath::addChapter(const std::string &chapter) ++{ ++ m_chapters.push_back(chapter); ++} ++ ++const std::vector<std::string> &EPUBPath::getChapters() const ++{ ++ return m_chapters; ++} ++ + std::string EPUBPath::getTitle() const + { + return m_title; +diff --git a/src/lib/EPUBPath.h b/src/lib/EPUBPath.h +index 12b8f25..76f2d7b 100644 +--- a/src/lib/EPUBPath.h ++++ b/src/lib/EPUBPath.h +@@ -51,9 +51,13 @@ public: + void appendTitle(const std::string &title); + std::string getTitle() const; + ++ /// Adds chapter name (fixed layout). ++ void addChapter(const std::string &chapter); ++ const std::vector<std::string> &getChapters() const; + private: + std::vector<std::string> m_components; + std::string m_title; ++ std::vector<std::string> m_chapters; + }; + + bool operator==(const EPUBPath &left, const EPUBPath &right); +diff --git a/src/lib/EPUBTextGenerator.cpp b/src/lib/EPUBTextGenerator.cpp +index 8e88adb..38ddcdf 100644 +--- a/src/lib/EPUBTextGenerator.cpp ++++ b/src/lib/EPUBTextGenerator.cpp +@@ -270,7 +270,9 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi + { + const RVNGProperty *const breakBefore = propList["fo:break-before"]; + if (isPageBreak(breakBefore) && m_impl->getSplitGuard().splitOnPageBreak()) ++ { + m_impl->startNewHtmlFile(); ++ } + const RVNGProperty *const breakAfter = propList["fo:break-after"]; + m_impl->m_breakAfterPara = isPageBreak(breakAfter); + if (m_impl->getSplitGuard().splitOnSize()) +@@ -282,6 +284,19 @@ void EPUBTextGenerator::openParagraph(const librevenge::RVNGPropertyList &propLi + m_impl->startNewHtmlFile(); + m_impl->getSplitGuard().setCurrentHeadingLevel(outlineLevel ? outlineLevel->getInt() : 0); + ++ if (const librevenge::RVNGPropertyListVector *chapterNames = m_impl->m_pageSpanProps.child("librevenge:chapter-names")) ++ { ++ for (unsigned long i = 0; i < chapterNames->count(); i++) ++ { ++ RVNGPropertyList const &chapter=(*chapterNames)[i]; ++ const RVNGProperty *const chapterName = chapter["librevenge:name"]; ++ if (!chapterName) ++ continue; ++ ++ m_impl->getHtmlManager().addChapterName(chapterName->getStr().cstr()); ++ } ++ } ++ + m_impl->getSplitGuard().openLevel(); + + if (m_impl->m_inHeader || m_impl->m_inFooter) +-- +2.13.6 + diff --git a/filter/source/graphic/GraphicExportFilter.cxx b/filter/source/graphic/GraphicExportFilter.cxx index 5990c2d001c7..8d91d4edc605 100644 --- a/filter/source/graphic/GraphicExportFilter.cxx +++ b/filter/source/graphic/GraphicExportFilter.cxx @@ -138,7 +138,7 @@ bool GraphicExportFilter::filterRenderDocument() const if (mnTargetWidth == 0 || mnTargetHeight == 0) aTargetSizePixel = aDocumentSizePixel; - Graphic aGraphic = aRenderer.renderToGraphic(nCurrentPage, aDocumentSizePixel, aTargetSizePixel, COL_WHITE); + Graphic aGraphic = aRenderer.renderToGraphic(nCurrentPage, aDocumentSizePixel, aTargetSizePixel, COL_WHITE, /*bExtOutDevData=*/false); GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); diff --git a/include/svtools/DocumentToGraphicRenderer.hxx b/include/svtools/DocumentToGraphicRenderer.hxx index 5ed6f2ce4434..a7af217597c7 100644 --- a/include/svtools/DocumentToGraphicRenderer.hxx +++ b/include/svtools/DocumentToGraphicRenderer.hxx @@ -21,6 +21,8 @@ #ifndef INCLUDED_SVTOOLS_DOCUMENTTOGRAPHICRENDERER_HXX #define INCLUDED_SVTOOLS_DOCUMENTTOGRAPHICRENDERER_HXX +#include <vector> + #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/frame/XController.hpp> #include <com/sun/star/view/XRenderable.hpp> @@ -51,6 +53,7 @@ class SVT_DLLPUBLIC DocumentToGraphicRenderer css::uno::Any maSelection; bool mbSelectionOnly; bool mbIsWriter; + std::vector<OUString> maChapterNames; bool hasSelection() const; @@ -66,13 +69,18 @@ public: ~DocumentToGraphicRenderer(); sal_Int32 getCurrentPage(); + /** + * Get list of chapter names for a page, current page is set by + * renderToGraphic(). + */ + const std::vector<OUString>& getChapterNames() const; Size getDocumentSizeInPixels( sal_Int32 nCurrentPage ); Size getDocumentSizeIn100mm( sal_Int32 nCurrentPage ); Graphic renderToGraphic( sal_Int32 nCurrentPage, Size aDocumentSizePixel, - Size aTargetSizePixel, Color aPageColor); + Size aTargetSizePixel, Color aPageColor, bool bExtOutDevData); /** Determine whether rxController has a css::view::XSelectionSupplier at which either a css::drawing::XShapes or css::drawing::XShape is diff --git a/include/vcl/pdfextoutdevdata.hxx b/include/vcl/pdfextoutdevdata.hxx index 377760d7655c..e9a2ad04fb04 100644 --- a/include/vcl/pdfextoutdevdata.hxx +++ b/include/vcl/pdfextoutdevdata.hxx @@ -92,6 +92,7 @@ class VCL_DLLPUBLIC PDFExtOutDevData : public ExtOutDevData std::unique_ptr<GlobalSyncData> mpGlobalSyncData; std::vector< PDFExtOutDevBookmarkEntry > maBookmarks; + std::vector<OUString> maChapterNames; public: @@ -143,6 +144,7 @@ public: void SetDocumentLocale( const css::lang::Locale& rLoc ); std::vector< PDFExtOutDevBookmarkEntry >& GetBookmarks() { return maBookmarks;} + const std::vector<OUString>& GetChapterNames() { return maChapterNames; } const Graphic& GetCurrentGraphic() const; diff --git a/svtools/source/filter/DocumentToGraphicRenderer.cxx b/svtools/source/filter/DocumentToGraphicRenderer.cxx index 74275afa5c79..8d48bca87706 100644 --- a/svtools/source/filter/DocumentToGraphicRenderer.cxx +++ b/svtools/source/filter/DocumentToGraphicRenderer.cxx @@ -22,6 +22,7 @@ #include <vcl/graphicfilter.hxx> #include <vcl/svapp.hxx> #include <vcl/outdev.hxx> +#include <vcl/pdfextoutdevdata.hxx> #include <tools/fract.hxx> @@ -154,7 +155,8 @@ Graphic DocumentToGraphicRenderer::renderToGraphic( sal_Int32 nCurrentPage, Size aDocumentSizePixel, Size aTargetSizePixel, - Color aPageColor) + Color aPageColor, + bool bExtOutDevData) { if (!mxModel.is() || !mxController.is() || !mxRenderable.is()) @@ -171,7 +173,7 @@ Graphic DocumentToGraphicRenderer::renderToGraphic( double fScaleY = aTargetSizePixel.Height() / static_cast<double>(aDocumentSizePixel.Height()); PropertyValues renderProps; - renderProps.realloc( 4 ); + renderProps.realloc( 6 ); renderProps[0].Name = "IsPrinter"; renderProps[0].Value <<= true; renderProps[1].Name = "RenderDevice"; @@ -180,10 +182,22 @@ Graphic DocumentToGraphicRenderer::renderToGraphic( renderProps[2].Value <<= mxController; renderProps[3].Name = "RenderToGraphic"; renderProps[3].Value <<= true; + renderProps[4].Name = "HasPDFExtOutDevData"; + renderProps[4].Value <<= bExtOutDevData; + renderProps[5].Name = "PageRange"; + renderProps[5].Value <<= OUString::number(nCurrentPage); GDIMetaFile aMtf; OutputDevice* pOutputDev = VCLUnoHelper::GetOutputDevice( xDevice ); + + vcl::PDFExtOutDevData aPDFExtOutDevData(*pOutputDev); + if (bExtOutDevData) + { + aPDFExtOutDevData.SetIsExportBookmarks(true); + pOutputDev->SetExtOutDevData(&aPDFExtOutDevData); + } + pOutputDev->SetAntialiasing(pOutputDev->GetAntialiasing() | AntialiasingFlags::EnableB2dDraw); MapMode mm = pOutputDev->GetMapMode(); mm.SetScaleX( Fraction(fScaleX) ); @@ -205,9 +219,17 @@ Graphic DocumentToGraphicRenderer::renderToGraphic( aMtf.WindStart(); aMtf.SetPrefSize( aTargetSizePixel ); + if (bExtOutDevData) + maChapterNames = aPDFExtOutDevData.GetChapterNames(); + return Graphic(aMtf); } +const std::vector<OUString>& DocumentToGraphicRenderer::getChapterNames() const +{ + return maChapterNames; +} + sal_Int32 DocumentToGraphicRenderer::getCurrentPage() { if (hasSelection()) diff --git a/svtools/source/filter/exportdialog.cxx b/svtools/source/filter/exportdialog.cxx index a309b748e096..931e4008dd27 100644 --- a/svtools/source/filter/exportdialog.cxx +++ b/svtools/source/filter/exportdialog.cxx @@ -434,7 +434,7 @@ void ExportDialog::GetGraphicStream() aDocumentSizePixel ); Graphic aGraphic( aRenderer.renderToGraphic( nCurrentPage, - aDocumentSizePixel, aTargetSizePixel, COL_WHITE)); + aDocumentSizePixel, aTargetSizePixel, COL_WHITE, /*bExtOutDevData=*/false)); xGraphic = aGraphic.GetXGraphic(); } diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx index c03857e128b6..9d2ccc5cdd11 100644 --- a/sw/source/uibase/uno/unotxdoc.cxx +++ b/sw/source/uibase/uno/unotxdoc.cxx @@ -2893,7 +2893,8 @@ void SAL_CALL SwXTextDocument::render( if (0 > nRenderer) throw IllegalArgumentException(); - const bool bIsPDFExport = !lcl_SeqHasProperty( rxOptions, "IsPrinter" ); + const bool bHasPDFExtOutDevData = lcl_SeqHasProperty( rxOptions, "HasPDFExtOutDevData" ); + const bool bIsPDFExport = !lcl_SeqHasProperty( rxOptions, "IsPrinter" ) || bHasPDFExtOutDevData; bool bIsSwSrcView = false; SfxViewShell *pView = GetRenderView( bIsSwSrcView, rxOptions, bIsPDFExport ); @@ -2976,7 +2977,7 @@ void SAL_CALL SwXTextDocument::render( SwPrintData const& rSwPrtOptions = *m_pRenderData->GetSwPrtOptions(); - if (bIsPDFExport && bFirstPage && pWrtShell) + if (bIsPDFExport && (bFirstPage || bHasPDFExtOutDevData) && pWrtShell) { SwEnhancedPDFExportHelper aHelper( *pWrtShell, *pOut, aPageRange, bIsSkipEmptyPages, false, rSwPrtOptions ); } diff --git a/vcl/source/gdi/pdfextoutdevdata.cxx b/vcl/source/gdi/pdfextoutdevdata.cxx index db5b731393c9..d5197a04d41c 100644 --- a/vcl/source/gdi/pdfextoutdevdata.cxx +++ b/vcl/source/gdi/pdfextoutdevdata.cxx @@ -684,6 +684,10 @@ void PDFExtOutDevData::SetScreenStream(sal_Int32 nScreenId, const OUString& rURL sal_Int32 PDFExtOutDevData::CreateOutlineItem( sal_Int32 nParent, const OUString& rText, sal_Int32 nDestID ) { + if (nParent == -1) + // Has no parent, it's a chapter / heading 1. + maChapterNames.push_back(rText); + mpGlobalSyncData->mActions.push_back( PDFExtOutDevDataSync::CreateOutlineItem ); mpGlobalSyncData->mParaInts.push_back( nParent ); mpGlobalSyncData->mParaOUStrings.push_back( rText ); diff --git a/writerperfect/qa/unit/EPUBExportTest.cxx b/writerperfect/qa/unit/EPUBExportTest.cxx index 176324b0dff7..47e84ebf1bbc 100644 --- a/writerperfect/qa/unit/EPUBExportTest.cxx +++ b/writerperfect/qa/unit/EPUBExportTest.cxx @@ -348,6 +348,13 @@ void EPUBExportTest::testEPUBFixedLayoutImplicitBreak() // This was missing, implicit page break (as calculated by the layout) was lost on export. CPPUNIT_ASSERT(mxZipFile->hasByName("OEBPS/sections/section0002.xhtml")); CPPUNIT_ASSERT(!mxZipFile->hasByName("OEBPS/sections/section0003.xhtml")); + + // Make sure that fixed layout has chapter names in the navigation + // document. + mpXmlDoc = parseExport("OEBPS/toc.xhtml"); + // This was 'Page 1' instead. + assertXPathContent(mpXmlDoc, "//xhtml:li[1]/xhtml:a", "First chapter"); + assertXPathContent(mpXmlDoc, "//xhtml:li[2]/xhtml:a", "Second chapter"); } void EPUBExportTest::testPageBreakSplit() diff --git a/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt b/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt index 6a22acd0821f..40f628b5e646 100644 --- a/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt +++ b/writerperfect/qa/unit/data/writer/epubexport/fxl-2page.fodt @@ -44,6 +44,10 @@ <style:paragraph-properties text:number-lines="false" text:line-number="0"/> <style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="'Lucida Sans'" style:font-family-generic-complex="swiss"/> </style:style> + <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph" style:parent-style-name="Heading" style:next-style-name="Text_20_body" style:default-outline-level="1" style:class="text"> + <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" loext:contextual-spacing="false"/> + <style:text-properties fo:font-size="130%" fo:font-weight="bold" style:font-size-asian="130%" style:font-weight-asian="bold" style:font-size-complex="130%" style:font-weight-complex="bold"/> + </style:style> </office:styles> <office:automatic-styles> <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> @@ -65,7 +69,10 @@ </office:master-styles> <office:body> <office:text text:use-soft-page-breaks="true"> + <text:h text:style-name="Heading_20_1" text:outline-level="1">First chapter</text:h> <text:p text:style-name="P1"><text:span text:style-name="T1">He heard quiet steps behind him. That didn't bode well. Who could be following him this late at night and in this deadbeat part of town? And at this particular moment, just after he pulled off the big time and was making off with the greenbacks. Was there another crook who'd had the same idea, and was now watching him and waiting for a chance to grab the fruit of his labor? Or did the steps behind him mean that one of many law officers in town was on to him and just waiting to pounce and snap those cuffs on his wrists? He nervously looked all around. Suddenly he saw the alley. Like lightning he darted off to the left and disappeared between the two warehouses almost falling over the trash can lying in the middle of the sidewalk. He tried to nervously tap </text:span><text:soft-page-break/><text:span text:style-name="T1">his way along in the inky darkness and suddenly stiffened: it was a dead-end, he would h ave to go back the way he had come. The steps got louder and louder, he saw the black outline of a figure coming around the corner. Is this the end of the line?</text:span></text:p> + <text:h text:style-name="Heading_20_1" text:outline-level="1">Second chapter</text:h> + <text:p text:style-name="Standard">This is the end.</text:p> </office:text> </office:body> </office:document> diff --git a/writerperfect/source/writer/EPUBExportFilter.cxx b/writerperfect/source/writer/EPUBExportFilter.cxx index b25118350193..2e4286e1f80b 100644 --- a/writerperfect/source/writer/EPUBExportFilter.cxx +++ b/writerperfect/source/writer/EPUBExportFilter.cxx @@ -94,7 +94,7 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe if (xSourceModel.is()) aSourceURL = xSourceModel->getURL(); - std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> aPageMetafiles; + std::vector<exp::FixedLayoutPage> aPageMetafiles; if (nLayoutMethod == libepubgen::EPUB_LAYOUT_METHOD_FIXED) CreateMetafiles(aPageMetafiles); @@ -119,7 +119,7 @@ sal_Bool EPUBExportFilter::filter(const uno::Sequence<beans::PropertyValue> &rDe return xFilter->filter(rDescriptor); } -void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &rPageMetafiles) +void EPUBExportFilter::CreateMetafiles(std::vector<exp::FixedLayoutPage> &rPageMetafiles) { DocumentToGraphicRenderer aRenderer(mxSourceDocument, /*bSelectionOnly=*/false); uno::Reference<frame::XModel> xModel(mxSourceDocument, uno::UNO_QUERY); @@ -142,7 +142,7 @@ void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_I Size aLogic = aRenderer.getDocumentSizeIn100mm(nPage); // Get the CSS pixel size of the page (mm100 -> pixel using 96 DPI, independent from system DPI). Size aCss(static_cast<double>(aLogic.getWidth()) / 26.4583, static_cast<double>(aLogic.getHeight()) / 26.4583); - Graphic aGraphic = aRenderer.renderToGraphic(nPage, aDocumentSizePixel, aCss, COL_WHITE); + Graphic aGraphic = aRenderer.renderToGraphic(nPage, aDocumentSizePixel, aCss, COL_WHITE, /*bExtOutDevData=*/true); auto &rGDIMetaFile = const_cast<GDIMetaFile &>(aGraphic.GetGDIMetaFile()); // Set preferred map unit and size on the metafile, so the SVG size @@ -156,7 +156,11 @@ void EPUBExportFilter::CreateMetafiles(std::vector<std::pair<uno::Sequence<sal_I rGDIMetaFile.Write(aMemoryStream); uno::Sequence<sal_Int8> aSequence(static_cast<const sal_Int8 *>(aMemoryStream.GetData()), aMemoryStream.Tell()); - rPageMetafiles.emplace_back(aSequence, aCss); + exp::FixedLayoutPage aPage; + aPage.aMetafile = aSequence; + aPage.aCssPixels = aCss; + aPage.aChapterNames = aRenderer.getChapterNames(); + rPageMetafiles.push_back(aPage); } } diff --git a/writerperfect/source/writer/EPUBExportFilter.hxx b/writerperfect/source/writer/EPUBExportFilter.hxx index 188139a32843..ee676d3e1701 100644 --- a/writerperfect/source/writer/EPUBExportFilter.hxx +++ b/writerperfect/source/writer/EPUBExportFilter.hxx @@ -19,7 +19,7 @@ #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/uno/XComponentContext.hpp> -class Size; +#include "exp/xmlimp.hxx" namespace writerperfect { @@ -59,7 +59,7 @@ public: private: /// Create page metafiles in case of fixed layout. - void CreateMetafiles(std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &rPageMetafiles); + void CreateMetafiles(std::vector<exp::FixedLayoutPage> &rPageMetafiles); }; } // namespace writerperfect diff --git a/writerperfect/source/writer/exp/xmlimp.cxx b/writerperfect/source/writer/exp/xmlimp.cxx index ef681119d4cf..3ef02f69f008 100644 --- a/writerperfect/source/writer/exp/xmlimp.cxx +++ b/writerperfect/source/writer/exp/xmlimp.cxx @@ -238,7 +238,7 @@ public: rtl::Reference<XMLImportContext> CreateChildContext(const OUString &rName, const uno::Reference<xml::sax::XAttributeList> &/*xAttribs*/) override; // Handles metafile for a single page. - void HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &rPage, const Size &rSize, bool bFirst); + void HandleFixedLayoutPage(const FixedLayoutPage &rPage, bool bFirst); }; XMLOfficeDocContext::XMLOfficeDocContext(XMLImport &rImport) @@ -266,7 +266,7 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O bool bFirst = true; for (const auto &rPage : mrImport.GetPageMetafiles()) { - HandleFixedLayoutPage(rPage.first, rPage.second, bFirst); + HandleFixedLayoutPage(rPage, bFirst); if (bFirst) bFirst = false; } @@ -274,7 +274,7 @@ rtl::Reference<XMLImportContext> XMLOfficeDocContext::CreateChildContext(const O return nullptr; } -void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &rPage, const Size &rSize, bool bFirst) +void XMLOfficeDocContext::HandleFixedLayoutPage(const FixedLayoutPage &rPage, bool bFirst) { uno::Reference<uno::XComponentContext> xCtx = mrImport.GetComponentContext(); uno::Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(xCtx); @@ -292,17 +292,31 @@ void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &r SvMemoryStream aMemoryStream; xSaxWriter->setOutputStream(new utl::OStreamWrapper(aMemoryStream)); - xSVGWriter->write(xSaxWriter, rPage); + xSVGWriter->write(xSaxWriter, rPage.aMetafile); - // Have all the info, invoke libepubgen. + // Have all the info, invoke the generator. librevenge::RVNGPropertyList aPageProperties; // Pixel -> inch. - double fWidth = rSize.getWidth(); + double fWidth = rPage.aCssPixels.getWidth(); fWidth /= 96; aPageProperties.insert("fo:page-width", fWidth); - double fHeight = rSize.getHeight(); + double fHeight = rPage.aCssPixels.getHeight(); fHeight /= 96; aPageProperties.insert("fo:page-height", fHeight); + + if (!rPage.aChapterNames.empty()) + { + // Name of chapters starting on this page. + librevenge::RVNGPropertyListVector aChapterNames; + for (const auto &rName : rPage.aChapterNames) + { + librevenge::RVNGPropertyList aChapter; + aChapter.insert("librevenge:name", rName.toUtf8().getStr()); + aChapterNames.append(aChapter); + } + aPageProperties.insert("librevenge:chapter-names", aChapterNames); + } + mrImport.GetGenerator().openPageSpan(aPageProperties); librevenge::RVNGPropertyList aParagraphProperties; if (!bFirst) @@ -320,7 +334,7 @@ void XMLOfficeDocContext::HandleFixedLayoutPage(const uno::Sequence<sal_Int8> &r mrImport.GetGenerator().closePageSpan(); } -XMLImport::XMLImport(const uno::Reference<uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor, const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &rPageMetafiles) +XMLImport::XMLImport(const uno::Reference<uno::XComponentContext> &xContext, librevenge::RVNGTextInterface &rGenerator, const OUString &rURL, const uno::Sequence<beans::PropertyValue> &rDescriptor, const std::vector<FixedLayoutPage> &rPageMetafiles) : mrGenerator(rGenerator), mxContext(xContext), mrPageMetafiles(rPageMetafiles) @@ -421,7 +435,7 @@ PopupState XMLImport::FillPopupData(const OUString &rURL, librevenge::RVNGProper return PopupState::Consumed; } -const std::vector<std::pair<uno::Sequence<sal_Int8>, Size>> &XMLImport::GetPageMetafiles() const +const std::vector<FixedLayoutPage> &XMLImport::GetPageMetafiles() const { return mrPageMetafiles; } diff --git a/writerperfect/source/writer/exp/xmlimp.hxx b/writerperfect/source/writer/exp/xmlimp.hxx index 246eb45dbd16..1953c7196772 100644 --- a/writerperfect/source/writer/exp/xmlimp.hxx +++ b/writerperfect/source/writer/exp/xmlimp.hxx @@ -23,8 +23,7 @@ #include <cppuhelper/implbase.hxx> #include <rtl/ref.hxx> - -class Size; +#include <tools/gen.hxx> namespace writerperfect { @@ -33,6 +32,14 @@ namespace exp class XMLImportContext; +/// Contains info about a fixed-layout page. +struct FixedLayoutPage +{ + css::uno::Sequence<sal_Int8> aMetafile; + Size aCssPixels; + std::vector<OUString> aChapterNames; +}; + /// States describing the result of a link -> popup conversion. enum class PopupState { @@ -74,10 +81,10 @@ class XMLImport : public cppu::WeakImplHelper const css::uno::Reference<css::uno::XComponentContext> &mxContext; css::uno::Reference<css::uri::XUriReferenceFactory> mxUriReferenceFactory; OUString maMediaDir; - const std::vector<std::pair<css::uno::Sequence<sal_Int8>, Size>> &mrPageMetafiles; + const std::vector<FixedLayoutPage> &mrPageMetafiles; public: ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits