1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "viewcontactoftableobj.hxx"
22 #include <svx/svdotable.hxx>
23 #include <com/sun/star/table/XTable.hpp>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
27 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
28 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
29 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <svx/sdr/attribute/sdrtextattribute.hxx>
32 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
33 #include <editeng/borderline.hxx>
34 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
35 #include <sdr/attribute/sdrfilltextattribute.hxx>
36 #include <drawinglayer/attribute/sdrlineattribute.hxx>
37 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
38 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
39 #include <basegfx/matrix/b2dhommatrixtools.hxx>
40 #include <svx/framelink.hxx>
43 #include "tablelayouter.hxx"
46 using editeng::SvxBorderLine
;
47 using namespace com::sun::star
;
50 namespace drawinglayer
54 class SdrCellPrimitive2D
: public BufferedDecompositionPrimitive2D
57 basegfx::B2DHomMatrix maTransform
;
58 attribute::SdrFillTextAttribute maSdrFTAttribute
;
61 // local decomposition.
62 virtual void create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& aViewInformation
) const override
;
66 const basegfx::B2DHomMatrix
& rTransform
,
67 const attribute::SdrFillTextAttribute
& rSdrFTAttribute
)
68 : BufferedDecompositionPrimitive2D(),
69 maTransform(rTransform
),
70 maSdrFTAttribute(rSdrFTAttribute
)
75 const basegfx::B2DHomMatrix
& getTransform() const { return maTransform
; }
76 const attribute::SdrFillTextAttribute
& getSdrFTAttribute() const { return maSdrFTAttribute
; }
79 virtual bool operator==(const BasePrimitive2D
& rPrimitive
) const override
;
82 DeclPrimitive2DIDBlock()
85 void SdrCellPrimitive2D::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& /*aViewInformation*/) const
87 // prepare unit polygon
88 const basegfx::B2DPolyPolygon
aUnitPolyPolygon(basegfx::utils::createUnitPolygon());
91 if(!getSdrFTAttribute().getFill().isDefault())
93 basegfx::B2DPolyPolygon
aTransformed(aUnitPolyPolygon
);
95 aTransformed
.transform(getTransform());
97 createPolyPolygonFillPrimitive(
99 getSdrFTAttribute().getFill(),
100 getSdrFTAttribute().getFillFloatTransGradient()));
104 // if no fill create one for HitTest and BoundRect fallback
105 rContainer
.push_back(
106 createHiddenGeometryPrimitives2D(
113 if(!getSdrFTAttribute().getText().isDefault())
115 rContainer
.push_back(
119 getSdrFTAttribute().getText(),
120 attribute::SdrLineAttribute(),
126 bool SdrCellPrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
128 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive
))
130 const SdrCellPrimitive2D
& rCompare
= static_cast<const SdrCellPrimitive2D
&>(rPrimitive
);
132 return (getTransform() == rCompare
.getTransform()
133 && getSdrFTAttribute() == rCompare
.getSdrFTAttribute());
140 ImplPrimitive2DIDBlock(SdrCellPrimitive2D
, PRIMITIVE2D_ID_SDRCELLPRIMITIVE2D
)
142 } // end of namespace primitive2d
143 } // end of namespace drawinglayer
149 svx::frame::Style
impGetLineStyle(
150 const sdr::table::TableLayouter
& rLayouter
,
158 if(nX
>= 0 && nX
<= nColCount
&& nY
>= 0 && nY
<= nRowCount
)
160 const SvxBorderLine
* pLine
= rLayouter
.getBorderLine(nX
, nY
, bHorizontal
);
165 SvxBorderLine
aLine(*pLine
);
167 // check for mirroring. This shall always be done when it is
168 // not a top- or rightmost line
169 bool bMirror(aLine
.isDouble());
175 // mirror all bottom lines
180 // mirror all left lines
181 bMirror
= (bIsRTL
? 0 != nX
: nX
!= nColCount
);
187 aLine
.SetMirrorWidths( );
190 const double fTwipsToMM(127.0 / 72.0);
191 return svx::frame::Style(&aLine
, fTwipsToMM
);
195 // no success, copy empty line
196 return svx::frame::Style();
199 void createForVector(bool bHor
, drawinglayer::primitive2d::Primitive2DContainer
& rContainer
, const basegfx::B2DPoint
& rOrigin
, const basegfx::B2DVector
& rX
,
200 const svx::frame::Style
& rLine
,
201 const svx::frame::Style
& rLeftA
, const svx::frame::Style
& rLeftB
, const svx::frame::Style
& rLeftC
,
202 const svx::frame::Style
& rRightA
, const svx::frame::Style
& rRightB
, const svx::frame::Style
& rRightC
)
204 /// top-left and bottom-right Style Tables
205 const basegfx::B2DVector
aY(basegfx::getNormalizedPerpendicular(rX
));
207 /// Fill top-left Style Table
208 svx::frame::StyleVectorTable aStart
;
210 aStart
.add(rLeftA
, rX
, -aY
, bHor
); // bHor ? true : false));
211 aStart
.add(rLeftB
, rX
, -rX
, true); // bHor ? true : true));
212 aStart
.add(rLeftC
, rX
, aY
, !bHor
); // bHor ? false : true));
215 /// Fill bottom-right Style Table
216 svx::frame::StyleVectorTable aEnd
;
217 const basegfx::B2DVector
aAxis(-rX
);
219 aEnd
.add(rRightA
, aAxis
, -aY
, bHor
); // bHor ? true : false));
220 aEnd
.add(rRightB
, aAxis
, rX
, false); // bHor ? false : false));
221 aEnd
.add(rRightC
, aAxis
, aY
, !bHor
); // bHor ? false : true));
224 CreateBorderPrimitives(
235 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const
237 const sdr::table::SdrTableObj
& rTableObj
= static_cast<const sdr::table::SdrTableObj
&>(GetSdrObject());
238 const uno::Reference
< css::table::XTable
> xTable
= rTableObj
.getTable();
242 // create primitive representation for table. Cell info goes
243 // directly to aRetval, Border info to aBorderSequence and added
244 // later to get the correct overlapping
245 drawinglayer::primitive2d::Primitive2DContainer aRetval
;
246 const sal_Int32
nRowCount(xTable
->getRowCount());
247 const sal_Int32
nColCount(xTable
->getColumnCount());
248 const sal_Int32
nAllCount(nRowCount
* nColCount
);
252 const sdr::table::TableLayouter
& rTableLayouter
= rTableObj
.getTableLayouter();
253 const bool bIsRTL(css::text::WritingMode_RL_TB
== rTableObj
.GetWritingMode());
254 sdr::table::CellPos aCellPos
;
255 sdr::table::CellRef xCurrentCell
;
256 basegfx::B2IRectangle aCellArea
;
258 // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
259 // GetGeoRect() to not trigger any calculations. It's the unrotated geometry.
260 const tools::Rectangle
& rObjectRectangle(rTableObj
.GetGeoRect());
261 const basegfx::B2DRange
aObjectRange(rObjectRectangle
.Left(), rObjectRectangle
.Top(), rObjectRectangle
.Right(), rObjectRectangle
.Bottom());
263 // for each cell we need potentially a cell primitive and a border primitive
264 // (e.g. single cell). Prepare sequences and input counters
265 drawinglayer::primitive2d::Primitive2DContainer aBorderSequence
;
267 // create single primitives per cell
268 for(aCellPos
.mnRow
= 0; aCellPos
.mnRow
< nRowCount
; aCellPos
.mnRow
++)
270 for(aCellPos
.mnCol
= 0; aCellPos
.mnCol
< nColCount
; aCellPos
.mnCol
++)
272 xCurrentCell
.set(dynamic_cast< sdr::table::Cell
* >(xTable
->getCellByPosition(aCellPos
.mnCol
, aCellPos
.mnRow
).get()));
274 if(xCurrentCell
.is() && !xCurrentCell
->isMerged())
276 if(rTableLayouter
.getCellArea(xCurrentCell
, aCellPos
, aCellArea
))
278 // create cell transformation matrix
279 basegfx::B2DHomMatrix aCellMatrix
;
280 aCellMatrix
.set(0, 0, (double)aCellArea
.getWidth());
281 aCellMatrix
.set(1, 1, (double)aCellArea
.getHeight());
282 aCellMatrix
.set(0, 2, (double)aCellArea
.getMinX() + aObjectRange
.getMinX());
283 aCellMatrix
.set(1, 2, (double)aCellArea
.getMinY() + aObjectRange
.getMinY());
285 // handle cell fillings and text
286 const SfxItemSet
& rCellItemSet
= xCurrentCell
->GetItemSet();
287 const sal_uInt32
nTextIndex(nColCount
* aCellPos
.mnRow
+ aCellPos
.mnCol
);
288 const SdrText
* pSdrText
= rTableObj
.getText(nTextIndex
);
289 drawinglayer::attribute::SdrFillTextAttribute aAttribute
;
293 // #i101508# take cell's local text frame distances into account
294 const sal_Int32
nLeft(xCurrentCell
->GetTextLeftDistance());
295 const sal_Int32
nRight(xCurrentCell
->GetTextRightDistance());
296 const sal_Int32
nUpper(xCurrentCell
->GetTextUpperDistance());
297 const sal_Int32
nLower(xCurrentCell
->GetTextLowerDistance());
299 aAttribute
= drawinglayer::primitive2d::createNewSdrFillTextAttribute(
309 aAttribute
= drawinglayer::primitive2d::createNewSdrFillTextAttribute(
314 // always create cell primitives for BoundRect and HitTest
316 const drawinglayer::primitive2d::Primitive2DReference
xCellReference(
317 new drawinglayer::primitive2d::SdrCellPrimitive2D(
318 aCellMatrix
, aAttribute
));
319 aRetval
.append(xCellReference
);
322 // handle cell borders
323 const sal_Int32
nX(bIsRTL
? nColCount
- aCellPos
.mnCol
: aCellPos
.mnCol
);
324 const sal_Int32
nY(aCellPos
.mnRow
);
326 // get access values for X,Y at the cell's end
327 const sal_Int32
nXSpan(xCurrentCell
->getColumnSpan());
328 const sal_Int32
nYSpan(xCurrentCell
->getRowSpan());
329 const sal_Int32
nXRight(bIsRTL
? nX
- nXSpan
: nX
+ nXSpan
);
330 const sal_Int32
nYBottom(nY
+ nYSpan
);
333 const svx::frame::Style
aLeftLine(impGetLineStyle(rTableLayouter
, nX
, nY
, false, nColCount
, nRowCount
, bIsRTL
));
334 //To resolve the bug fdo#59117
335 //In RTL table as BottomLine & TopLine are drawn from Left Side to Right, nX should be nX-1
336 const svx::frame::Style
aBottomLine(impGetLineStyle(rTableLayouter
, bIsRTL
?nX
-1:nX
, nYBottom
, true, nColCount
, nRowCount
, bIsRTL
));
337 const svx::frame::Style
aRightLine(impGetLineStyle(rTableLayouter
, nXRight
, nY
, false, nColCount
, nRowCount
, bIsRTL
));
338 const svx::frame::Style
aTopLine(impGetLineStyle(rTableLayouter
, bIsRTL
?nX
-1:nX
, nY
, true, nColCount
, nRowCount
, bIsRTL
));
340 if(aLeftLine
.IsUsed() || aBottomLine
.IsUsed() || aRightLine
.IsUsed() || aTopLine
.IsUsed())
342 // get the neighbor cells' borders
343 const svx::frame::Style
aLeftFromTLine(impGetLineStyle(rTableLayouter
, nX
, nY
- 1, false, nColCount
, nRowCount
, bIsRTL
));
344 const svx::frame::Style
aLeftFromBLine(impGetLineStyle(rTableLayouter
, nX
, nYBottom
+ 1, false, nColCount
, nRowCount
, bIsRTL
));
345 const svx::frame::Style
aRightFromTLine(impGetLineStyle(rTableLayouter
, nXRight
, nY
- 1, false, nColCount
, nRowCount
, bIsRTL
));
346 const svx::frame::Style
aRightFromBLine(impGetLineStyle(rTableLayouter
, nXRight
, nYBottom
+ 1, false, nColCount
, nRowCount
, bIsRTL
));
347 const svx::frame::Style
aTopFromLLine(impGetLineStyle(rTableLayouter
, nX
- 1, nY
, true, nColCount
, nRowCount
, bIsRTL
));
348 const svx::frame::Style
aTopFromRLine(impGetLineStyle(rTableLayouter
, nXRight
+ 1, nY
, true, nColCount
, nRowCount
, bIsRTL
));
349 const svx::frame::Style
aBottomFromLLine(impGetLineStyle(rTableLayouter
, nX
- 1, nYBottom
, true, nColCount
, nRowCount
, bIsRTL
));
350 const svx::frame::Style
aBottomFromRLine(impGetLineStyle(rTableLayouter
, nXRight
+ 1, nYBottom
, true, nColCount
, nRowCount
, bIsRTL
));
352 // get cell coordinate system
353 const basegfx::B2DPoint
aOrigin(aCellMatrix
* basegfx::B2DPoint(0.0, 0.0));
354 const basegfx::B2DVector
aX(aCellMatrix
* basegfx::B2DVector(1.0, 0.0));
355 const basegfx::B2DVector
aY(aCellMatrix
* basegfx::B2DVector(0.0, 1.0));
357 if(aLeftLine
.IsUsed())
359 createForVector(false, aBorderSequence
, aOrigin
, aY
, aLeftLine
,
360 aTopLine
, aLeftFromTLine
, aTopFromLLine
,
361 aBottomLine
, aLeftFromBLine
, aBottomFromLLine
);
364 if(aBottomLine
.IsUsed())
366 createForVector(true, aBorderSequence
, aOrigin
+ aY
, aX
, aBottomLine
,
367 aLeftLine
, aBottomFromLLine
, aLeftFromBLine
,
368 aRightLine
, aBottomFromRLine
, aRightFromBLine
);
371 if(aRightLine
.IsUsed())
373 createForVector(false, aBorderSequence
, aOrigin
+ aX
, aY
, aRightLine
,
374 aTopFromRLine
, aRightFromTLine
, aTopLine
,
375 aBottomFromRLine
, aRightFromBLine
, aBottomLine
);
378 if(aTopLine
.IsUsed())
380 createForVector(true, aBorderSequence
, aOrigin
, aX
, aTopLine
,
381 aLeftFromTLine
, aTopFromLLine
, aLeftLine
,
382 aRightFromTLine
, aTopFromRLine
, aRightLine
);
390 // append Border info to target. We want fillings and text first
391 aRetval
.append(aBorderSequence
);
396 // check and create evtl. shadow for created content
397 const SfxItemSet
& rObjectItemSet
= rTableObj
.GetMergedItemSet();
398 const drawinglayer::attribute::SdrShadowAttribute
aNewShadowAttribute(
399 drawinglayer::primitive2d::createNewSdrShadowAttribute(rObjectItemSet
));
401 if(!aNewShadowAttribute
.isDefault())
403 aRetval
= drawinglayer::primitive2d::createEmbeddedShadowPrimitive(aRetval
, aNewShadowAttribute
);
411 // take unrotated snap rect (direct model data) for position and size
412 const tools::Rectangle
& rRectangle
= rTableObj
.GetGeoRect();
413 const basegfx::B2DRange
aObjectRange(
414 rRectangle
.Left(), rRectangle
.Top(),
415 rRectangle
.Right(), rRectangle
.Bottom());
417 // create object matrix
418 const GeoStat
& rGeoStat(rTableObj
.GetGeoStat());
419 const double fShearX(rGeoStat
.nShearAngle
? tan((36000 - rGeoStat
.nShearAngle
) * F_PI18000
) : 0.0);
420 const double fRotate(rGeoStat
.nRotationAngle
? (36000 - rGeoStat
.nRotationAngle
) * F_PI18000
: 0.0);
421 const basegfx::B2DHomMatrix
aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
422 aObjectRange
.getWidth(), aObjectRange
.getHeight(), fShearX
, fRotate
,
423 aObjectRange
.getMinX(), aObjectRange
.getMinY()));
425 // created an invisible outline for the cases where no visible content exists
426 const drawinglayer::primitive2d::Primitive2DReference
xReference(
427 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
430 return drawinglayer::primitive2d::Primitive2DContainer
{ xReference
};
434 ViewContactOfTableObj::ViewContactOfTableObj(sdr::table::SdrTableObj
& rTableObj
)
435 : ViewContactOfSdrObj(rTableObj
)
439 ViewContactOfTableObj::~ViewContactOfTableObj()
442 } // end of namespace contact
443 } // end of namespace sdr
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */