From e589d8d71a0c11bf3c982633b6da4ff181bd7fd0 Mon Sep 17 00:00:00 2001 From: Armin Le Grand Date: Wed, 24 Jan 2018 15:25:40 +0100 Subject: BorderlineFix: Use svx::frame::Array tooling in Draw/Impress For creating the needed BorderPrimitives for TableCells for the Tables used in Draw/Impress, adapt the ViewContactOfTableObj doing this to use svx::frame::Array tooling now. This will correct the error for not taking the neighboured connects for merged cells into account and unify one more space to the same tooling. Change-Id: I2e6f732985e9b963359f156628bd29ddfec1a80c --- svx/Library_svx.mk | 1 - svx/Library_svxcore.mk | 1 + svx/source/dialog/framelinkarray.cxx | 1 + svx/source/table/viewcontactoftableobj.cxx | 197 +++++++++++++---------------- 4 files changed, 92 insertions(+), 108 deletions(-) diff --git a/svx/Library_svx.mk b/svx/Library_svx.mk index 6bdbadaf2e3b..ad1b1dc3a423 100644 --- a/svx/Library_svx.mk +++ b/svx/Library_svx.mk @@ -128,7 +128,6 @@ $(eval $(call gb_Library_add_exception_objects,svx,\ svx/source/dialog/fntctrl \ svx/source/dialog/fontlb \ svx/source/dialog/fontwork \ - svx/source/dialog/framelinkarray \ svx/source/dialog/frmdirlbox \ svx/source/dialog/frmsel \ svx/source/dialog/graphctl \ diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk index 5bfbf899034d..603860d7f11b 100644 --- a/svx/Library_svxcore.mk +++ b/svx/Library_svxcore.mk @@ -116,6 +116,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\ svx/source/dialog/dlgutil \ svx/source/dialog/hexcolorcontrol \ svx/source/dialog/framelink \ + svx/source/dialog/framelinkarray \ svx/source/dialog/langbox \ svx/source/dialog/pagenumberlistbox \ svx/source/dialog/papersizelistbox \ diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index bc8a50a3d3cf..7cd4b26027dc 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx index 448a0b407f2a..4a5741cd0545 100644 --- a/svx/source/table/viewcontactoftableobj.cxx +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -36,8 +36,10 @@ #include #include #include +#include #include #include +#include #include #include "tablelayouter.hxx" @@ -196,42 +198,6 @@ namespace sdr return svx::frame::Style(); } - void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX, - const svx::frame::Style& rLine, - const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC, - const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC) - { - /// top-left and bottom-right Style Tables - const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX)); - - /// Fill top-left Style Table - svx::frame::StyleVectorTable aStart; - - aStart.add(rLeftA, rX, -aY, bHor); // bHor ? true : false)); - aStart.add(rLeftB, rX, -rX, true); // bHor ? true : true)); - aStart.add(rLeftC, rX, aY, !bHor); // bHor ? false : true)); - aStart.sort(); - - /// Fill bottom-right Style Table - svx::frame::StyleVectorTable aEnd; - const basegfx::B2DVector aAxis(-rX); - - aEnd.add(rRightA, aAxis, -aY, bHor); // bHor ? true : false)); - aEnd.add(rRightB, aAxis, rX, false); // bHor ? false : false)); - aEnd.add(rRightC, aAxis, aY, !bHor); // bHor ? false : true)); - aEnd.sort(); - - CreateBorderPrimitives( - rContainer, - rOrigin, - rX, - rLine, - aStart, - aEnd, - nullptr - ); - } - drawinglayer::primitive2d::Primitive2DContainer ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const { const sdr::table::SdrTableObj& rTableObj = static_cast(GetSdrObject()); @@ -249,7 +215,7 @@ namespace sdr if(nAllCount) { - const sdr::table::TableLayouter& rTableLayouter = rTableObj.getTableLayouter(); + const sdr::table::TableLayouter& rTableLayouter(rTableObj.getTableLayouter()); const bool bIsRTL(css::text::WritingMode_RL_TB == rTableObj.GetWritingMode()); sdr::table::CellPos aCellPos; sdr::table::CellRef xCurrentCell; @@ -258,19 +224,59 @@ namespace sdr // create range using the model data directly. This is in SdrTextObj::aRect which i will access using // GetGeoRect() to not trigger any calculations. It's the unrotated geometry. const tools::Rectangle& rObjectRectangle(rTableObj.GetGeoRect()); - const basegfx::B2DRange aObjectRange(rObjectRectangle.Left(), rObjectRectangle.Top(), rObjectRectangle.Right(), rObjectRectangle.Bottom()); + const basegfx::B2DRange aObjectRange( + rObjectRectangle.Left(), rObjectRectangle.Top(), + rObjectRectangle.Right(), rObjectRectangle.Bottom()); + + // To create the CellBorderPrimitives, use the tolling from svx::frame::Array + // which is capable of creating the needed visualization. Fill it during the + // anyways needed run over the table. + svx::frame::Array aArray; - // for each cell we need potentially a cell primitive and a border primitive - // (e.g. single cell). Prepare sequences and input counters - drawinglayer::primitive2d::Primitive2DContainer aBorderSequence; + // initialize CellBorderArray for primitive creation + aArray.Initialize(nRowCount, nColCount); // create single primitives per cell for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++) { + // add RowHeight to CellBorderArray for primitive creation + aArray.SetRowHeight(aCellPos.mnRow, rTableLayouter.getRowHeight(aCellPos.mnRow)); + for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++) { + // add ColWidth to CellBorderArray for primitive creation, only + // needs to be done in the 1st run + if(0 == aCellPos.mnRow) + { + aArray.SetColWidth(aCellPos.mnCol, rTableLayouter.getColumnWidth(aCellPos.mnCol)); + } + + // access the cell xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get())); + if(xCurrentCell.is()) + { + // copy styles for current cell to CellBorderArray for primitive creation + aArray.SetCellStyleLeft(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleRight(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol + 1, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleTop(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, true, nColCount, nRowCount, bIsRTL)); + aArray.SetCellStyleBottom(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow + 1, true, nColCount, nRowCount, bIsRTL)); + + // ignore merged cells (all except the top-left of a merged cell) + if(!xCurrentCell->isMerged()) + { + // check if we are the top-left of a merged cell + const sal_Int32 nXSpan(xCurrentCell->getColumnSpan()); + const sal_Int32 nYSpan(xCurrentCell->getRowSpan()); + + if(nXSpan > 1 || nYSpan > 1) + { + // if merged, set so at CellBorderArray for primitive creation + aArray.SetMergedRange(aCellPos.mnCol, aCellPos.mnRow, aCellPos.mnCol + nXSpan - 1, aCellPos.mnRow + nYSpan - 1); + } + } + } + if(xCurrentCell.is() && !xCurrentCell->isMerged()) { if(rTableLayouter.getCellArea(xCurrentCell, aCellPos, aCellArea)) @@ -318,77 +324,54 @@ namespace sdr aCellMatrix, aAttribute)); aRetval.append(xCellReference); } - - // handle cell borders - const sal_Int32 nX(bIsRTL ? nColCount - aCellPos.mnCol : aCellPos.mnCol); - const sal_Int32 nY(aCellPos.mnRow); - - // get access values for X,Y at the cell's end - const sal_Int32 nXSpan(xCurrentCell->getColumnSpan()); - const sal_Int32 nYSpan(xCurrentCell->getRowSpan()); - const sal_Int32 nXRight(bIsRTL ? nX - nXSpan : nX + nXSpan); - const sal_Int32 nYBottom(nY + nYSpan); - - // get basic lines - const svx::frame::Style aLeftLine(impGetLineStyle(rTableLayouter, nX, nY, false, nColCount, nRowCount, bIsRTL)); - //To resolve the bug fdo#59117 - //In RTL table as BottomLine & TopLine are drawn from Left Side to Right, nX should be nX-1 - const svx::frame::Style aBottomLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nYBottom, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightLine(impGetLineStyle(rTableLayouter, nXRight, nY, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nY, true, nColCount, nRowCount, bIsRTL)); - - if(aLeftLine.IsUsed() || aBottomLine.IsUsed() || aRightLine.IsUsed() || aTopLine.IsUsed()) - { - // get the neighbor cells' borders - const svx::frame::Style aLeftFromTLine(impGetLineStyle(rTableLayouter, nX, nY - 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aLeftFromBLine(impGetLineStyle(rTableLayouter, nX, nYBottom, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightFromTLine(impGetLineStyle(rTableLayouter, nXRight, nY - 1, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aRightFromBLine(impGetLineStyle(rTableLayouter, nXRight, nYBottom, false, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nY, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aTopFromRLine(impGetLineStyle(rTableLayouter, nXRight, nY, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aBottomFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nYBottom, true, nColCount, nRowCount, bIsRTL)); - const svx::frame::Style aBottomFromRLine(impGetLineStyle(rTableLayouter, nXRight, nYBottom, true, nColCount, nRowCount, bIsRTL)); - - // get cell coordinate system - const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0)); - const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0)); - const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0)); - - if(aLeftLine.IsUsed()) - { - createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine, - aTopLine, aLeftFromTLine, aTopFromLLine, - aBottomLine, aLeftFromBLine, aBottomFromLLine); - } - - if(aBottomLine.IsUsed()) - { - createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine, - aLeftLine, aBottomFromLLine, aLeftFromBLine, - aRightLine, aBottomFromRLine, aRightFromBLine); - } - - if(aRightLine.IsUsed()) - { - createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine, - aTopFromRLine, aRightFromTLine, aTopLine, - aBottomFromRLine, aRightFromBLine, aBottomLine); - } - - if(aTopLine.IsUsed()) - { - createForVector(true, aBorderSequence, aOrigin, aX, aTopLine, - aLeftFromTLine, aTopFromLLine, aLeftLine, - aRightFromTLine, aTopFromRLine, aRightLine); - } - } } } } } - // append Border info to target. We want fillings and text first - aRetval.append(aBorderSequence); + // now create all CellBorderPrimitives + const drawinglayer::primitive2d::Primitive2DContainer aCellBorderPrimitives(aArray.CreateB2DPrimitiveArray()); + + if(!aCellBorderPrimitives.empty()) + { + // this is already scaled (due to Table in non-uniform coordinates), so + // first transform removing scale + basegfx::B2DHomMatrix aTransform( + basegfx::utils::createScaleB2DHomMatrix( + 1.0 / aObjectRange.getWidth(), + 1.0 / aObjectRange.getHeight())); + + // If RTL, mirror the whole unified table in X and move right. + // This is much easier than taking this into account for the whole + // index calcualtions + if(bIsRTL) + { + aTransform.scale(-1.0, 1.0); + aTransform.translate(1.0, 0.0); + } + + // create object matrix + const GeoStat& rGeoStat(rTableObj.GetGeoStat()); + const double fShearX(rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0); + const double fRotate(rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0); + const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate, + aObjectRange.getMinX(), aObjectRange.getMinY())); + + // add object matrix to transform. By doing so theoretically + // CellBorders could be also rotated/sheared for the first time ever. + // To completely make that work, the primitives already created in + // aRetval would also have to be based on ObjectMatrix, not only on + // ObjectRange as it currently is. + aTransform *= aObjectMatrix; + + // create a transform primitive with this and embed CellBorders + // and append to retval + aRetval.append( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + aCellBorderPrimitives)); + } } if(!aRetval.empty()) -- cgit