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 <vcl/lazydelete.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <sfx2/printer.hxx>
24 #include <sfx2/progress.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/prntitem.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <editeng/shaditem.hxx>
29 #include <svx/ctredlin.hxx>
30 #include <svx/framelink.hxx>
31 #include <drawdoc.hxx>
32 #include <tgrditem.hxx>
34 #include <fmtsrnd.hxx>
35 #include <fmtclds.hxx>
37 #include <strings.hrc>
38 #include <swmodule.hxx>
39 #include <rootfrm.hxx>
40 #include <pagefrm.hxx>
41 #include <section.hxx>
42 #include <sectfrm.hxx>
43 #include <viewimp.hxx>
44 #include <dflyobj.hxx>
47 #include <frmtool.hxx>
48 #include <viewopt.hxx>
50 #include <dcontact.hxx>
55 #include <cellfrm.hxx>
56 #include <notxtfrm.hxx>
58 #include <pagedesc.hxx>
59 #include <ptqueue.hxx>
60 #include <noteurl.hxx>
61 #include "virtoutp.hxx"
62 #include <lineinfo.hxx>
63 #include <dbg_lay.hxx>
65 #include <svx/svdogrp.hxx>
66 #include <sortedobjs.hxx>
67 #include <EnhancedPDFExportHelper.hxx>
68 #include <bodyfrm.hxx>
71 #include <sw_primitivetypes2d.hxx>
74 #include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
75 #include <svx/sdr/contact/viewobjectcontactredirector.hxx>
76 #include <svx/sdr/contact/viewobjectcontact.hxx>
77 #include <svx/sdr/contact/viewcontact.hxx>
78 #include <DocumentSettingManager.hxx>
79 #include <IDocumentDeviceAccess.hxx>
80 #include <IDocumentDrawModelAccess.hxx>
83 #include <PostItMgr.hxx>
84 #include <FrameControlsManager.hxx>
85 #include <vcl/settings.hxx>
87 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
89 #include <svtools/borderhelper.hxx>
91 #include <bitmaps.hlst>
92 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
93 #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
94 #include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
95 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
96 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
97 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
98 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
99 #include <drawinglayer/processor2d/processor2dtools.hxx>
100 #include <svx/unoapi.hxx>
101 #include <svx/svdpagv.hxx>
102 #include <svx/xfillit0.hxx>
103 #include <basegfx/matrix/b2dhommatrixtools.hxx>
104 #include <basegfx/color/bcolortools.hxx>
105 #include <basegfx/utils/b2dclipstate.hxx>
106 #include <sal/log.hxx>
112 #include <edtwin.hxx>
114 #include <paintfrm.hxx>
115 #include <textboxhelper.hxx>
116 #include <o3tl/typed_flags_set.hxx>
118 #include <vcl/BitmapTools.hxx>
119 #include <comphelper/lok.hxx>
120 #include <svtools/optionsdrawinglayer.hxx>
121 #include <vcl/GraphicLoader.hxx>
122 #include <basegfx/polygon/b2dpolygontools.hxx>
124 #include <svl/style.hxx>
126 #include <unotools/configmgr.hxx>
127 #include <vcl/hatch.hxx>
129 using namespace ::editeng
;
130 using namespace ::com::sun::star
;
134 struct SwPaintProperties
;
136 //Class declaration; here because they are only used in this file
137 enum class SubColFlags
{
138 Page
= 0x01, //Helplines of the page
139 Tab
= 0x08, //Helplines inside tables
140 Fly
= 0x10, //Helplines inside fly frames
141 Sect
= 0x20, //Helplines inside sections
147 template<> struct typed_flags
<SubColFlags
> : is_typed_flags
<SubColFlags
, 0x39> {};
152 // Classes collecting the border lines and help lines
153 class SwLineRect
: public SwRect
156 SvxBorderLineStyle m_nStyle
;
157 const SwTabFrame
* m_pTabFrame
;
158 SubColFlags m_nSubColor
; //colorize subsidiary lines
159 bool m_bPainted
; //already painted?
160 sal_uInt8 m_nLock
; //To distinguish the line and the hell layer.
162 SwLineRect( const SwRect
&rRect
, const Color
*pCol
, const SvxBorderLineStyle nStyle
,
163 const SwTabFrame
*pT
, const SubColFlags nSCol
);
165 const Color
& GetColor() const { return m_aColor
; }
166 SvxBorderLineStyle
GetStyle() const { return m_nStyle
; }
167 const SwTabFrame
* GetTab() const { return m_pTabFrame
; }
168 void SetPainted() { m_bPainted
= true; }
169 void Lock(bool bLock
)
176 bool IsPainted() const { return m_bPainted
; }
177 bool IsLocked() const { return m_nLock
!= 0; }
178 SubColFlags
GetSubColor() const { return m_nSubColor
; }
180 bool MakeUnion(const SwRect
& rRect
, SwPaintProperties
const& properties
);
186 static void dummy_function()
188 pid_t pid
= getpid();
198 std::vector
<SwLineRect
> m_aLineRects
;
199 typedef std::vector
< SwLineRect
>::const_iterator const_iterator
;
200 typedef std::vector
< SwLineRect
>::iterator iterator
;
201 typedef std::vector
< SwLineRect
>::reverse_iterator reverse_iterator
;
202 typedef std::vector
< SwLineRect
>::size_type size_type
;
203 size_t m_nLastCount
; //avoid unnecessary cycles in PaintLines
208 // Work around what is either a compiler bug in Xcode 5.1.1,
209 // or some unknown problem in this file. If I ifdef out this
210 // call, I get a crash in SwSubsRects::PaintSubsidiary: the
211 // address of the rLi reference variable is claimed to be
216 void AddLineRect( const SwRect
& rRect
, const Color
*pColor
, const SvxBorderLineStyle nStyle
,
217 const SwTabFrame
*pTab
, const SubColFlags nSCol
, SwPaintProperties
const &properties
);
218 void ConnectEdges( OutputDevice
const *pOut
, SwPaintProperties
const &properties
);
219 void PaintLines ( OutputDevice
*pOut
, SwPaintProperties
const &properties
);
220 void LockLines( bool bLock
);
223 bool isFull() const { return m_aLineRects
.size() > 100; }
226 class SwSubsRects
: public SwLineRects
228 void RemoveSuperfluousSubsidiaryLines( const SwLineRects
&rRects
, SwPaintProperties
const &properties
);
230 void PaintSubsidiary( OutputDevice
*pOut
, const SwLineRects
*pRects
, SwPaintProperties
const &properties
);
235 drawinglayer::primitive2d::Primitive2DContainer m_Lines
;
237 void AddBorderLines(drawinglayer::primitive2d::Primitive2DContainer
&& rContainer
);
238 drawinglayer::primitive2d::Primitive2DContainer
GetBorderLines_Clear()
240 drawinglayer::primitive2d::Primitive2DContainer lines
;
248 // Default zoom factor
249 const double aEdgeScale
= 0.5;
251 //To optimize the expensive RetouchColor determination
252 Color aGlobalRetoucheColor
;
256 Color
* GetActiveRetoucheColor()
258 return &aGlobalRetoucheColor
;
265 * Container for static properties
267 struct SwPaintProperties
{
268 // Only repaint the Fly content as well as the background of the Fly content if
269 // a metafile is taken of the Fly.
271 VclPtr
<OutputDevice
> pSFlyMetafileOut
;
272 SwViewShell
*pSGlobalShell
;
274 // Retouch for transparent Flys is done by the background of the Flys.
275 // The Fly itself should certainly not be spared out. See PaintSwFrameBackground and
276 // lcl_SubtractFlys()
277 SwFlyFrame
*pSRetoucheFly
;
278 SwFlyFrame
*pSRetoucheFly2
;
279 SwFlyFrame
*pSFlyOnlyDraw
;
281 // The borders will be collected in pSLines during the Paint and later
282 // possibly merge them.
283 // The help lines will be collected and merged in gProp.pSSubsLines. These will
284 // be compared with pSLines before the work in order to avoid help lines
286 std::unique_ptr
<BorderLines
> pBLines
;
287 std::unique_ptr
<SwLineRects
> pSLines
;
288 std::unique_ptr
<SwSubsRects
> pSSubsLines
;
290 // global variable for sub-lines of body, header, footer, section and footnote frames.
291 std::unique_ptr
<SwSubsRects
> pSSpecSubsLines
;
292 SfxProgress
*pSProgress
;
294 // Sizes of a pixel and the corresponding halves. Will be reset when
295 // entering SwRootFrame::PaintSwFrame
296 tools::Long nSPixelSzW
;
297 tools::Long nSPixelSzH
;
298 tools::Long nSHalfPixelSzW
;
299 tools::Long nSHalfPixelSzH
;
300 tools::Long nSMinDistPixelW
;
301 tools::Long nSMinDistPixelH
;
303 Color aSGlobalRetoucheColor
;
305 // Current zoom factor
310 : bSFlyMetafile(false)
311 , pSFlyMetafileOut(nullptr)
312 , pSGlobalShell(nullptr)
313 , pSRetoucheFly(nullptr)
314 , pSRetoucheFly2(nullptr)
315 , pSFlyOnlyDraw(nullptr)
316 , pSProgress(nullptr)
332 static SwPaintProperties gProp
;
334 static bool isSubsidiaryLinesFlysEnabled()
336 return !gProp
.pSGlobalShell
->GetViewOptions()->IsPagePreview() &&
337 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
338 !gProp
.pSGlobalShell
->GetViewOptions()->IsFormView() &&
339 gProp
.pSGlobalShell
->GetViewOptions()->IsObjectBoundaries();
341 //other subsidiary lines enabled?
342 static bool isSubsidiaryLinesEnabled()
344 return !gProp
.pSGlobalShell
->GetViewOptions()->IsPagePreview() &&
345 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
346 !gProp
.pSGlobalShell
->GetViewOptions()->IsFormView() &&
347 !gProp
.pSGlobalShell
->GetViewOptions()->IsWhitespaceHidden() &&
348 gProp
.pSGlobalShell
->GetViewOptions()->IsDocBoundaries();
350 //subsidiary lines for sections
351 static bool isSubsidiaryLinesForSectionsEnabled()
353 return !gProp
.pSGlobalShell
->GetViewOptions()->IsPagePreview() &&
354 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
355 !gProp
.pSGlobalShell
->GetViewOptions()->IsFormView() &&
356 gProp
.pSGlobalShell
->GetViewOptions()->IsSectionBoundaries();
362 bool isTableBoundariesEnabled()
364 if (!gProp
.pSGlobalShell
->GetViewOptions()->IsTable())
367 if (gProp
.pSGlobalShell
->GetViewOptions()->IsPagePreview())
370 if (gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly())
373 if (gProp
.pSGlobalShell
->GetViewOptions()->IsFormView())
376 return gProp
.pSGlobalShell
->GetViewOptions()->IsTableBoundaries();
382 * Set borders alignment statics
383 * Adjustment for 'small' twip-to-pixel relations:
384 * For 'small' twip-to-pixel relations (less than 2:1)
385 * values of <gProp.nSHalfPixelSzW> and <gProp.nSHalfPixelSzH> are set to ZERO
387 void SwCalcPixStatics( vcl::RenderContext
const *pOut
)
389 // determine 'small' twip-to-pixel relation
390 bool bSmallTwipToPxRelW
= false;
391 bool bSmallTwipToPxRelH
= false;
393 Size
aCheckTwipToPxRelSz( pOut
->PixelToLogic( Size( 100, 100 )) );
394 if ( (aCheckTwipToPxRelSz
.Width()/100.0) < 2.0 )
396 bSmallTwipToPxRelW
= true;
398 if ( (aCheckTwipToPxRelSz
.Height()/100.0) < 2.0 )
400 bSmallTwipToPxRelH
= true;
404 Size
aSz( pOut
->PixelToLogic( Size( 1,1 )) );
406 gProp
.nSPixelSzW
= aSz
.Width();
407 if( !gProp
.nSPixelSzW
)
408 gProp
.nSPixelSzW
= 1;
409 gProp
.nSPixelSzH
= aSz
.Height();
410 if( !gProp
.nSPixelSzH
)
411 gProp
.nSPixelSzH
= 1;
413 // consider 'small' twip-to-pixel relations
414 if ( !bSmallTwipToPxRelW
)
416 gProp
.nSHalfPixelSzW
= gProp
.nSPixelSzW
/ 2 + 1;
420 gProp
.nSHalfPixelSzW
= 0;
422 // consider 'small' twip-to-pixel relations
423 if ( !bSmallTwipToPxRelH
)
425 gProp
.nSHalfPixelSzH
= gProp
.nSPixelSzH
/ 2 + 1;
429 gProp
.nSHalfPixelSzH
= 0;
432 gProp
.nSMinDistPixelW
= gProp
.nSPixelSzW
* 2 + 1;
433 gProp
.nSMinDistPixelH
= gProp
.nSPixelSzH
* 2 + 1;
435 const MapMode
&rMap
= pOut
->GetMapMode();
436 gProp
.aSScaleX
= double(rMap
.GetScaleX());
437 gProp
.aSScaleY
= double(rMap
.GetScaleY());
443 * To be able to save the statics so the paint is more or less reentrant
445 class SwSavePaintStatics
: public SwPaintProperties
448 SwSavePaintStatics();
449 ~SwSavePaintStatics();
454 SwSavePaintStatics::SwSavePaintStatics()
457 bSFlyMetafile
= gProp
.bSFlyMetafile
;
458 pSGlobalShell
= gProp
.pSGlobalShell
;
459 pSFlyMetafileOut
= gProp
.pSFlyMetafileOut
;
460 pSRetoucheFly
= gProp
.pSRetoucheFly
;
461 pSRetoucheFly2
= gProp
.pSRetoucheFly2
;
462 pSFlyOnlyDraw
= gProp
.pSFlyOnlyDraw
;
463 pBLines
= std::move(gProp
.pBLines
);
464 pSLines
= std::move(gProp
.pSLines
);
465 pSSubsLines
= std::move(gProp
.pSSubsLines
);
466 pSSpecSubsLines
= std::move(gProp
.pSSpecSubsLines
);
467 pSProgress
= gProp
.pSProgress
;
468 nSPixelSzW
= gProp
.nSPixelSzW
;
469 nSPixelSzH
= gProp
.nSPixelSzH
;
470 nSHalfPixelSzW
= gProp
.nSHalfPixelSzW
;
471 nSHalfPixelSzH
= gProp
.nSHalfPixelSzH
;
472 nSMinDistPixelW
= gProp
.nSMinDistPixelW
;
473 nSMinDistPixelH
= gProp
.nSMinDistPixelH
;
474 aSGlobalRetoucheColor
= aGlobalRetoucheColor
;
475 aSScaleX
= gProp
.aSScaleX
;
476 aSScaleY
= gProp
.aSScaleY
;
478 // Restoring globales to default
479 gProp
.bSFlyMetafile
= false;
480 gProp
.pSFlyMetafileOut
= nullptr;
481 gProp
.pSRetoucheFly
= nullptr;
482 gProp
.pSRetoucheFly2
= nullptr;
483 gProp
.nSPixelSzW
= gProp
.nSPixelSzH
=
484 gProp
.nSHalfPixelSzW
= gProp
.nSHalfPixelSzH
=
485 gProp
.nSMinDistPixelW
= gProp
.nSMinDistPixelH
= 0;
486 gProp
.aSScaleX
= gProp
.aSScaleY
= 1.0;
487 gProp
.pSProgress
= nullptr;
490 SwSavePaintStatics::~SwSavePaintStatics()
492 // Restoring globales to saved one
493 gProp
.pSGlobalShell
= pSGlobalShell
;
494 gProp
.bSFlyMetafile
= bSFlyMetafile
;
495 gProp
.pSFlyMetafileOut
= pSFlyMetafileOut
;
496 gProp
.pSRetoucheFly
= pSRetoucheFly
;
497 gProp
.pSRetoucheFly2
= pSRetoucheFly2
;
498 gProp
.pSFlyOnlyDraw
= pSFlyOnlyDraw
;
499 gProp
.pBLines
= std::move(pBLines
);
500 gProp
.pSLines
= std::move(pSLines
);
501 gProp
.pSSubsLines
= std::move(pSSubsLines
);
502 gProp
.pSSpecSubsLines
= std::move(pSSpecSubsLines
);
503 gProp
.pSProgress
= pSProgress
;
504 gProp
.nSPixelSzW
= nSPixelSzW
;
505 gProp
.nSPixelSzH
= nSPixelSzH
;
506 gProp
.nSHalfPixelSzW
= nSHalfPixelSzW
;
507 gProp
.nSHalfPixelSzH
= nSHalfPixelSzH
;
508 gProp
.nSMinDistPixelW
= nSMinDistPixelW
;
509 gProp
.nSMinDistPixelH
= nSMinDistPixelH
;
510 aGlobalRetoucheColor
= aSGlobalRetoucheColor
;
511 gProp
.aSScaleX
= aSScaleX
;
512 gProp
.aSScaleY
= aSScaleY
;
515 void BorderLines::AddBorderLines(drawinglayer::primitive2d::Primitive2DContainer
&& rContainer
)
517 if(!rContainer
.empty())
519 m_Lines
.append(std::move(rContainer
));
523 SwLineRect::SwLineRect(const SwRect
& rRect
, const Color
* pCol
, const SvxBorderLineStyle nStyl
,
524 const SwTabFrame
* pT
, const SubColFlags nSCol
)
532 if ( pCol
!= nullptr )
536 bool SwLineRect::MakeUnion( const SwRect
&rRect
, SwPaintProperties
const & properties
)
538 // It has already been tested outside, whether the rectangles have
539 // the same orientation (horizontal or vertical), color, etc.
540 if ( Height() > Width() ) //Vertical line
542 if ( Left() == rRect
.Left() && Width() == rRect
.Width() )
544 // Merge when there is no gap between the lines
545 const tools::Long nAdd
= properties
.nSPixelSzW
+ properties
.nSHalfPixelSzW
;
546 if ( Bottom() + nAdd
>= rRect
.Top() &&
547 Top() - nAdd
<= rRect
.Bottom() )
549 Bottom( std::max( Bottom(), rRect
.Bottom() ) );
550 Top ( std::min( Top(), rRect
.Top() ) );
557 if ( Top() == rRect
.Top() && Height() == rRect
.Height() )
559 // Merge when there is no gap between the lines
560 const tools::Long nAdd
= properties
.nSPixelSzW
+ properties
.nSHalfPixelSzW
;
561 if ( Right() + nAdd
>= rRect
.Left() &&
562 Left() - nAdd
<= rRect
.Right() )
564 Right( std::max( Right(), rRect
.Right() ) );
565 Left ( std::min( Left(), rRect
.Left() ) );
573 void SwLineRects::AddLineRect( const SwRect
&rRect
, const Color
*pCol
, const SvxBorderLineStyle nStyle
,
574 const SwTabFrame
*pTab
, const SubColFlags nSCol
, SwPaintProperties
const & properties
)
576 // Loop backwards because lines which can be combined, can usually be painted
577 // in the same context
578 for (reverse_iterator it
= m_aLineRects
.rbegin(); it
!= m_aLineRects
.rend(); ++it
)
580 SwLineRect
&rLRect
= *it
;
581 // Test for the orientation, color, table
582 if ( rLRect
.GetTab() == pTab
&&
583 !rLRect
.IsPainted() && rLRect
.GetSubColor() == nSCol
&&
584 (rLRect
.Height() > rLRect
.Width()) == (rRect
.Height() > rRect
.Width()) &&
585 (pCol
&& rLRect
.GetColor() == *pCol
) )
587 if ( rLRect
.MakeUnion( rRect
, properties
) )
591 m_aLineRects
.emplace_back(rRect
, pCol
, nStyle
, pTab
, nSCol
);
594 void SwLineRects::ConnectEdges( OutputDevice
const *pOut
, SwPaintProperties
const & properties
)
596 if ( pOut
->GetOutDevType() != OUTDEV_PRINTER
)
598 // I'm not doing anything for a too small zoom
599 if ( properties
.aSScaleX
< aEdgeScale
|| properties
.aSScaleY
< aEdgeScale
)
603 static const tools::Long nAdd
= 20;
605 std::vector
<SwLineRect
*> aCheck
;
607 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
609 SwLineRect
& rL1
= m_aLineRects
[i
];
610 if ( !rL1
.GetTab() || rL1
.IsPainted() || rL1
.IsLocked() )
615 const bool bVert
= rL1
.Height() > rL1
.Width();
616 tools::Long nL1a
, nL1b
, nL1c
, nL1d
;
620 nL1a
= rL1
.Top(); nL1b
= rL1
.Left();
621 nL1c
= rL1
.Right(); nL1d
= rL1
.Bottom();
625 nL1a
= rL1
.Left(); nL1b
= rL1
.Top();
626 nL1c
= rL1
.Bottom(); nL1d
= rL1
.Right();
629 // Collect all lines to possibly link with i1
630 for (iterator it2
= m_aLineRects
.begin(); it2
!= m_aLineRects
.end(); ++it2
)
632 SwLineRect
&rL2
= *it2
;
633 if ( rL2
.GetTab() != rL1
.GetTab() ||
636 (bVert
== (rL2
.Height() > rL2
.Width())) )
639 tools::Long nL2a
, nL2b
, nL2c
, nL2d
;
642 nL2a
= rL2
.Top(); nL2b
= rL2
.Left();
643 nL2c
= rL2
.Right(); nL2d
= rL2
.Bottom();
647 nL2a
= rL2
.Left(); nL2b
= rL2
.Top();
648 nL2c
= rL2
.Bottom(); nL2d
= rL2
.Right();
651 if ( (nL1a
- nAdd
< nL2d
&& nL1d
+ nAdd
> nL2a
) &&
652 ((nL1b
> nL2b
&& nL1c
< nL2c
) ||
653 (nL1c
>= nL2c
&& nL1b
- nAdd
< nL2c
) ||
654 (nL1b
<= nL2b
&& nL1c
+ nAdd
> nL2b
)) )
656 aCheck
.push_back( &rL2
);
659 if ( aCheck
.size() < 2 )
662 bool bRemove
= false;
664 // For each line test all following ones.
665 for ( size_t k
= 0; !bRemove
&& k
< aCheck
.size(); ++k
)
667 SwLineRect
&rR1
= *aCheck
[k
];
669 for ( size_t k2
= k
+1; !bRemove
&& k2
< aCheck
.size(); ++k2
)
671 SwLineRect
&rR2
= *aCheck
[k2
];
674 SwLineRect
*pLA
= nullptr;
675 SwLineRect
*pLB
= nullptr;
676 if ( rR1
.Top() < rR2
.Top() )
678 pLA
= &rR1
; pLB
= &rR2
;
680 else if ( rR1
.Top() > rR2
.Top() )
682 pLA
= &rR2
; pLB
= &rR1
;
684 // are k1 and k2 describing a double line?
685 if ( pLA
&& pLA
->Bottom() + 60 > pLB
->Top() )
687 if ( rL1
.Top() < pLA
->Top() )
689 if ( rL1
.Bottom() == pLA
->Bottom() )
690 continue; //Small mistake (where?)
693 aIns
.Bottom( pLA
->Bottom() );
694 if ( !rL1
.Contains( aIns
) )
696 m_aLineRects
.emplace_back(aIns
, &rL1
.GetColor(),
697 SvxBorderLineStyle::SOLID
, rL1
.GetTab(),
707 if ( rL1
.Bottom() > pLB
->Bottom() )
708 rL1
.Top( pLB
->Top() ); // extend i1 on the top
710 bRemove
= true; //stopping, remove i1
715 SwLineRect
*pLA
= nullptr;
716 SwLineRect
*pLB
= nullptr;
717 if ( rR1
.Left() < rR2
.Left() )
719 pLA
= &rR1
; pLB
= &rR2
;
721 else if ( rR1
.Left() > rR2
.Left() )
723 pLA
= &rR2
; pLB
= &rR1
;
725 // Is it double line?
726 if ( pLA
&& pLA
->Right() + 60 > pLB
->Left() )
728 if ( rL1
.Left() < pLA
->Left() )
730 if ( rL1
.Right() == pLA
->Right() )
731 continue; //small error
734 aIns
.Right( pLA
->Right() );
735 if ( !rL1
.Contains( aIns
) )
737 m_aLineRects
.emplace_back(aIns
, &rL1
.GetColor(),
738 SvxBorderLineStyle::SOLID
, rL1
.GetTab(),
747 if ( rL1
.Right() > pLB
->Right() )
748 rL1
.Left( pLB
->Left() );
757 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
763 void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects
&rRects
, SwPaintProperties
const & properties
)
765 // All help lines that are covered by any border will be removed or split
766 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
768 // get a copy instead of a reference, because an <insert> may destroy
769 // the object due to a necessary array resize.
770 const SwLineRect
aSubsLineRect(m_aLineRects
[i
]);
772 // add condition <aSubsLineRect.IsLocked()> in order to consider only
773 // border lines, which are *not* locked.
774 if ( aSubsLineRect
.IsPainted() ||
775 aSubsLineRect
.IsLocked() )
778 const bool bVerticalSubs
= aSubsLineRect
.Height() > aSubsLineRect
.Width();
779 SwRect
aSubsRect( aSubsLineRect
);
782 aSubsRect
.AddLeft ( - (properties
.nSPixelSzW
+properties
.nSHalfPixelSzW
) );
783 aSubsRect
.AddRight ( properties
.nSPixelSzW
+properties
.nSHalfPixelSzW
);
787 aSubsRect
.AddTop ( - (properties
.nSPixelSzH
+properties
.nSHalfPixelSzH
) );
788 aSubsRect
.AddBottom( properties
.nSPixelSzH
+properties
.nSHalfPixelSzH
);
790 for (const_iterator itK
= rRects
.m_aLineRects
.begin(); itK
!= rRects
.m_aLineRects
.end();
793 const SwLineRect
&rLine
= *itK
;
795 // do *not* consider painted or locked border lines.
796 // #i1837# - locked border lines have to be considered.
797 if ( rLine
.IsLocked () )
800 if ( !bVerticalSubs
== ( rLine
.Height() > rLine
.Width() ) ) //same direction?
803 if ( aSubsRect
.Overlaps( rLine
) )
805 if ( bVerticalSubs
) // Vertical?
807 if ( aSubsRect
.Left() <= rLine
.Right() &&
808 aSubsRect
.Right() >= rLine
.Left() )
810 tools::Long nTmp
= rLine
.Top()-(properties
.nSPixelSzH
+1);
811 if ( aSubsLineRect
.Top() < nTmp
)
813 SwRect
aNewSubsRect( aSubsLineRect
);
814 aNewSubsRect
.Bottom( nTmp
);
815 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
816 aSubsLineRect
.GetStyle(), nullptr,
817 aSubsLineRect
.GetSubColor());
819 nTmp
= rLine
.Bottom()+properties
.nSPixelSzH
+1;
820 if ( aSubsLineRect
.Bottom() > nTmp
)
822 SwRect
aNewSubsRect( aSubsLineRect
);
823 aNewSubsRect
.Top( nTmp
);
824 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
825 aSubsLineRect
.GetStyle(), nullptr,
826 aSubsLineRect
.GetSubColor());
828 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
835 if ( aSubsRect
.Top() <= rLine
.Bottom() &&
836 aSubsRect
.Bottom() >= rLine
.Top() )
838 tools::Long nTmp
= rLine
.Left()-(properties
.nSPixelSzW
+1);
839 if ( aSubsLineRect
.Left() < nTmp
)
841 SwRect
aNewSubsRect( aSubsLineRect
);
842 aNewSubsRect
.Right( nTmp
);
843 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
844 aSubsLineRect
.GetStyle(), nullptr,
845 aSubsLineRect
.GetSubColor());
847 nTmp
= rLine
.Right()+properties
.nSPixelSzW
+1;
848 if ( aSubsLineRect
.Right() > nTmp
)
850 SwRect
aNewSubsRect( aSubsLineRect
);
851 aNewSubsRect
.Left( nTmp
);
852 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
853 aSubsLineRect
.GetStyle(), nullptr,
854 aSubsLineRect
.GetSubColor());
856 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
866 void SwLineRects::LockLines( bool bLock
)
868 for (SwLineRect
& rLRect
: m_aLineRects
)
872 static void lcl_DrawDashedRect( OutputDevice
* pOut
, SwLineRect
const & rLRect
)
874 tools::Long startX
= rLRect
.Left( ), endX
;
875 tools::Long startY
= rLRect
.Top( ), endY
;
877 // Discriminate vertically stretched rect from horizontally stretched
878 // and restrict minimum nHalfLWidth to 1
879 tools::Long nHalfLWidth
= std::max( std::min( rLRect
.Width( ), rLRect
.Height( ) ) / 2, tools::Long(1) );
881 if ( rLRect
.Height( ) > rLRect
.Width( ) )
883 startX
+= nHalfLWidth
;
885 endY
= startY
+ rLRect
.Height( );
889 startY
+= nHalfLWidth
;
891 endX
= startX
+ rLRect
.Width( );
894 svtools::DrawLine( *pOut
, Point( startX
, startY
), Point( endX
, endY
),
895 sal_uInt32( nHalfLWidth
* 2 ), rLRect
.GetStyle( ) );
898 void SwLineRects::PaintLines( OutputDevice
*pOut
, SwPaintProperties
const &properties
)
900 // Paint the borders. Sadly two passes are needed.
901 // Once for the inside and once for the outside edges of tables
902 if (m_aLineRects
.size() == m_nLastCount
)
905 // #i16816# tagged pdf support
906 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
908 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
909 pOut
->SetFillColor();
910 pOut
->SetLineColor();
911 ConnectEdges( pOut
, properties
);
912 const Color
*pLast
= nullptr;
914 bool bPaint2nd
= false;
915 size_t nMinCount
= m_aLineRects
.size();
917 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
919 SwLineRect
& rLRect
= m_aLineRects
[i
];
921 if ( rLRect
.IsPainted() )
924 if ( rLRect
.IsLocked() )
926 nMinCount
= std::min( nMinCount
, i
);
930 // Paint it now or in the second pass?
932 if ( rLRect
.GetTab() )
934 if ( rLRect
.Height() > rLRect
.Width() )
936 // Vertical edge, overlapping with the table edge?
937 SwTwips nLLeft
= rLRect
.Left() - 30,
938 nLRight
= rLRect
.Right() + 30,
939 nTLeft
= rLRect
.GetTab()->getFrameArea().Left() + rLRect
.GetTab()->getFramePrintArea().Left(),
940 nTRight
= rLRect
.GetTab()->getFrameArea().Left() + rLRect
.GetTab()->getFramePrintArea().Right();
941 if ( (nTLeft
>= nLLeft
&& nTLeft
<= nLRight
) ||
942 (nTRight
>= nLLeft
&& nTRight
<= nLRight
) )
947 // Horizontal edge, overlapping with the table edge?
948 SwTwips nLTop
= rLRect
.Top() - 30,
949 nLBottom
= rLRect
.Bottom() + 30,
950 nTTop
= rLRect
.GetTab()->getFrameArea().Top() + rLRect
.GetTab()->getFramePrintArea().Top(),
951 nTBottom
= rLRect
.GetTab()->getFrameArea().Top() + rLRect
.GetTab()->getFramePrintArea().Bottom();
952 if ( (nTTop
>= nLTop
&& nTTop
<= nLBottom
) ||
953 (nTBottom
>= nLTop
&& nTBottom
<= nLBottom
) )
959 if ( !pLast
|| *pLast
!= rLRect
.GetColor() )
961 pLast
= &rLRect
.GetColor();
963 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
964 if( properties
.pSGlobalShell
->GetWin() &&
965 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
966 pOut
->SetDrawMode( DrawModeFlags::Default
);
968 pOut
->SetLineColor( *pLast
);
969 pOut
->SetFillColor( *pLast
);
970 pOut
->SetDrawMode( nOldDrawMode
);
973 if( !rLRect
.IsEmpty() )
974 lcl_DrawDashedRect( pOut
, rLRect
);
982 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
984 SwLineRect
& rLRect
= m_aLineRects
[i
];
985 if ( rLRect
.IsPainted() )
988 if ( rLRect
.IsLocked() )
990 nMinCount
= std::min( nMinCount
, i
);
994 if ( !pLast
|| *pLast
!= rLRect
.GetColor() )
996 pLast
= &rLRect
.GetColor();
998 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
999 if( properties
.pSGlobalShell
->GetWin() &&
1000 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1002 pOut
->SetDrawMode( DrawModeFlags::Default
);
1005 pOut
->SetFillColor( *pLast
);
1006 pOut
->SetDrawMode( nOldDrawMode
);
1008 if( !rLRect
.IsEmpty() )
1009 lcl_DrawDashedRect( pOut
, rLRect
);
1010 rLRect
.SetPainted();
1013 m_nLastCount
= nMinCount
;
1018 void SwSubsRects::PaintSubsidiary( OutputDevice
*pOut
,
1019 const SwLineRects
*pRects
,
1020 SwPaintProperties
const & properties
)
1022 if (m_aLineRects
.empty())
1025 // #i16816# tagged pdf support
1026 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
1028 // Remove all help line that are almost covered (tables)
1029 for (size_type i
= 0; i
!= m_aLineRects
.size(); ++i
)
1031 SwLineRect
& rLi
= m_aLineRects
[i
];
1032 const bool bVerticalSubs
= rLi
.Height() > rLi
.Width();
1034 for (size_type k
= i
+ 1; k
!= m_aLineRects
.size(); ++k
)
1036 SwLineRect
& rLk
= m_aLineRects
[k
];
1037 if ( rLi
.SSize() == rLk
.SSize() )
1039 if ( bVerticalSubs
== ( rLk
.Height() > rLk
.Width() ) )
1041 if ( bVerticalSubs
)
1043 tools::Long nLi
= rLi
.Right();
1044 tools::Long nLk
= rLk
.Right();
1045 if ( rLi
.Top() == rLk
.Top() &&
1046 ((nLi
< rLk
.Left() && nLi
+21 > rLk
.Left()) ||
1047 (nLk
< rLi
.Left() && nLk
+21 > rLi
.Left())))
1049 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
1050 // don't continue with inner loop any more:
1051 // the array may shrink!
1058 tools::Long nLi
= rLi
.Bottom();
1059 tools::Long nLk
= rLk
.Bottom();
1060 if ( rLi
.Left() == rLk
.Left() &&
1061 ((nLi
< rLk
.Top() && nLi
+21 > rLk
.Top()) ||
1062 (nLk
< rLi
.Top() && nLk
+21 > rLi
.Top())))
1064 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
1065 // don't continue with inner loop any more:
1066 // the array may shrink!
1076 if (pRects
&& (!pRects
->m_aLineRects
.empty()))
1077 RemoveSuperfluousSubsidiaryLines( *pRects
, properties
);
1079 if (m_aLineRects
.empty())
1082 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
1083 pOut
->SetLineColor();
1085 // Reset draw mode in high contrast mode in order to get fill color
1086 // set at output device. Recover draw mode after draw of lines.
1087 // Necessary for the subsidiary lines painted by the fly frames.
1088 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
1089 if( gProp
.pSGlobalShell
->GetWin() &&
1090 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1092 pOut
->SetDrawMode( DrawModeFlags::Default
);
1095 for (SwLineRect
& rLRect
: m_aLineRects
)
1097 // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
1098 if ( !rLRect
.IsPainted() &&
1099 !rLRect
.IsLocked() )
1101 const Color
*pCol
= nullptr;
1102 SwViewShell
*pShell
= properties
.pSGlobalShell
;
1103 const SwViewOption
*pOpt
= pShell
->GetViewOptions();
1104 switch ( rLRect
.GetSubColor() )
1106 case SubColFlags::Page
: pCol
= &pOpt
->GetDocBoundariesColor(); break;
1107 case SubColFlags::Fly
: pCol
= &pOpt
->GetObjectBoundariesColor(); break;
1108 case SubColFlags::Tab
: pCol
= &pOpt
->GetTableBoundariesColor(); break;
1109 case SubColFlags::Sect
: pCol
= &pOpt
->GetSectionBoundColor(); break;
1112 if (pCol
&& pOut
->GetFillColor() != *pCol
)
1113 pOut
->SetFillColor( *pCol
);
1114 pOut
->DrawRect( rLRect
.SVRect() );
1116 rLRect
.SetPainted();
1120 pOut
->SetDrawMode( nOldDrawMode
);
1125 // Various functions that are use in this file.
1128 * Function <SwAlignRect(..)> is also used outside this file
1130 * Correction: adjust rectangle on pixel level in order to make sure,
1131 * that the border "leaves its original pixel", if it has to
1132 * No prior adjustments for odd relation between pixel and twip
1134 void SwAlignRect( SwRect
&rRect
, const SwViewShell
*pSh
, const vcl::RenderContext
* pRenderContext
)
1136 if( !rRect
.HasArea() )
1139 // Make sure that view shell (parameter <pSh>) exists, if the output device
1140 // is taken from this view shell --> no output device, no alignment
1141 // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
1142 if ( !gProp
.bSFlyMetafile
&& !pSh
)
1147 const vcl::RenderContext
*pOut
= gProp
.bSFlyMetafile
?
1148 gProp
.pSFlyMetafileOut
.get() : pRenderContext
;
1150 // Hold original rectangle in pixel
1151 const tools::Rectangle aOrgPxRect
= pOut
->LogicToPixel( rRect
.SVRect() );
1152 // Determine pixel-center rectangle in twip
1153 const SwRect
aPxCenterRect( pOut
->PixelToLogic( aOrgPxRect
) );
1155 // Perform adjustments on pixel level.
1156 SwRect
aAlignedPxRect( aOrgPxRect
);
1157 if ( rRect
.Top() > aPxCenterRect
.Top() )
1159 // 'leave pixel overlapping on top'
1160 aAlignedPxRect
.AddTop( 1 );
1163 if ( rRect
.Bottom() < aPxCenterRect
.Bottom() )
1165 // 'leave pixel overlapping on bottom'
1166 aAlignedPxRect
.AddBottom( - 1 );
1169 if ( rRect
.Left() > aPxCenterRect
.Left() )
1171 // 'leave pixel overlapping on left'
1172 aAlignedPxRect
.AddLeft( 1 );
1175 if ( rRect
.Right() < aPxCenterRect
.Right() )
1177 // 'leave pixel overlapping on right'
1178 aAlignedPxRect
.AddRight( - 1 );
1181 // Consider negative width/height check, if aligned SwRect has negative width/height.
1182 // If Yes, adjust it to width/height = 0 twip.
1183 // NOTE: A SwRect with negative width/height can occur, if the width/height
1184 // of the given SwRect in twip was less than a pixel in twip and that
1185 // the alignment calculates that the aligned SwRect should not contain
1186 // the pixels the width/height is on.
1187 if ( aAlignedPxRect
.Width() < 0 )
1189 aAlignedPxRect
.Width(0);
1191 if ( aAlignedPxRect
.Height() < 0 )
1193 aAlignedPxRect
.Height(0);
1195 // Consider zero width/height for converting a rectangle from
1196 // pixel to logic it needs a width/height. Thus, set width/height
1197 // to one, if it's zero and correct this on the twip level after the conversion.
1198 bool bZeroWidth
= false;
1199 if ( aAlignedPxRect
.Width() == 0 )
1201 aAlignedPxRect
.Width(1);
1204 bool bZeroHeight
= false;
1205 if ( aAlignedPxRect
.Height() == 0 )
1207 aAlignedPxRect
.Height(1);
1211 rRect
= SwRect(pOut
->PixelToLogic( aAlignedPxRect
.SVRect() ));
1213 // Consider zero width/height and adjust calculated aligned twip rectangle.
1214 // Reset width/height to zero; previous negative width/height haven't to be considered.
1226 * Method to pixel-align rectangle for drawing graphic object
1228 * Because we are drawing graphics from the left-top-corner in conjunction
1229 * with size coordinates, these coordinates have to be calculated at a pixel
1231 * Thus, we convert the rectangle to pixel and then convert to left-top-corner
1232 * and then get size of pixel rectangle back to logic.
1233 * This calculation is necessary, because there's a different between
1234 * the conversion from logic to pixel of a normal rectangle with its left-top-
1235 * and right-bottom-corner and the same conversion of the same rectangle
1236 * with left-top-corner and size.
1238 * NOTE: Call this method before each <GraphicObject.Draw(...)>
1240 void SwAlignGrfRect( SwRect
*pGrfRect
, const vcl::RenderContext
&rOut
)
1242 tools::Rectangle aPxRect
= rOut
.LogicToPixel( pGrfRect
->SVRect() );
1243 pGrfRect
->Pos( rOut
.PixelToLogic( aPxRect
.TopLeft() ) );
1244 pGrfRect
->SSize( rOut
.PixelToLogic( aPxRect
.GetSize() ) );
1247 static tools::Long
lcl_AlignWidth( const tools::Long nWidth
, SwPaintProperties
const & properties
)
1251 const tools::Long nW
= nWidth
% properties
.nSPixelSzW
;
1253 if ( !nW
|| nW
> properties
.nSHalfPixelSzW
)
1254 return std::max(tools::Long(1), nWidth
- properties
.nSHalfPixelSzW
);
1259 static tools::Long
lcl_AlignHeight( const tools::Long nHeight
, SwPaintProperties
const & properties
)
1263 const tools::Long nH
= nHeight
% properties
.nSPixelSzH
;
1265 if ( !nH
|| nH
> properties
.nSHalfPixelSzH
)
1266 return std::max(tools::Long(1), nHeight
- properties
.nSHalfPixelSzH
);
1272 * Calculate PrtArea plus surrounding plus shadow
1274 static void lcl_CalcBorderRect( SwRect
&rRect
, const SwFrame
*pFrame
,
1275 const SwBorderAttrs
&rAttrs
,
1277 SwPaintProperties
const & properties
)
1279 // Special handling for cell frames.
1280 // The printing area of a cell frame is completely enclosed in the frame area
1281 // and a cell frame has no shadow. Thus, for cell frames the calculated
1282 // area equals the frame area.
1283 // Notes: Borders of cell frames in R2L text direction will switch its side
1284 // - left border is painted on the right; right border on the left.
1285 // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
1286 if( pFrame
->IsSctFrame() )
1288 rRect
= pFrame
->getFramePrintArea();
1289 rRect
.Pos() += pFrame
->getFrameArea().Pos();
1291 else if ( pFrame
->IsCellFrame() )
1292 rRect
= pFrame
->getFrameArea();
1295 rRect
= pFrame
->getFramePrintArea();
1296 rRect
.Pos() += pFrame
->getFrameArea().Pos();
1298 SwRectFn fnRect
= pFrame
->IsVertical() ? ( pFrame
->IsVertLR() ? (pFrame
->IsVertLRBT() ? fnRectVertL2RB2T
: fnRectVertL2R
) : fnRectVert
) : fnRectHori
;
1300 const SvxBoxItem
&rBox
= rAttrs
.GetBox();
1301 const bool bTop
= 0 != (pFrame
->*fnRect
->fnGetTopMargin
)();
1302 if ( bTop
|| rBox
.GetTop() )
1304 SwTwips nDiff
= rBox
.GetTop() ?
1305 rBox
.CalcLineSpace( SvxBoxItemLine::TOP
, /*bEvenIfNoLine=*/false, /*bAllowNegative=*/true ) :
1306 rBox
.GetDistance( SvxBoxItemLine::TOP
);
1308 (rRect
.*fnRect
->fnSubTop
)( nDiff
);
1311 const bool bBottom
= 0 != (pFrame
->*fnRect
->fnGetBottomMargin
)();
1316 if ( pFrame
->IsTabFrame() &&
1317 static_cast<const SwTabFrame
*>(pFrame
)->IsCollapsingBorders() )
1319 // For collapsing borders, we have to add the height of
1320 // the height of the last line
1321 nDiff
= static_cast<const SwTabFrame
*>(pFrame
)->GetBottomLineSize();
1325 nDiff
= rBox
.GetBottom() ?
1326 rBox
.CalcLineSpace( SvxBoxItemLine::BOTTOM
) :
1327 rBox
.GetDistance( SvxBoxItemLine::BOTTOM
);
1330 (rRect
.*fnRect
->fnAddBottom
)( nDiff
);
1333 if ( rBox
.GetLeft() )
1334 (rRect
.*fnRect
->fnSubLeft
)( rBox
.CalcLineSpace( SvxBoxItemLine::LEFT
) );
1336 (rRect
.*fnRect
->fnSubLeft
)( rBox
.GetDistance( SvxBoxItemLine::LEFT
) );
1338 if ( rBox
.GetRight() )
1339 (rRect
.*fnRect
->fnAddRight
)( rBox
.CalcLineSpace( SvxBoxItemLine::RIGHT
) );
1341 (rRect
.*fnRect
->fnAddRight
)( rBox
.GetDistance( SvxBoxItemLine::RIGHT
) );
1343 if ( bShadow
&& rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
)
1345 const SvxShadowItem
&rShadow
= rAttrs
.GetShadow();
1347 (rRect
.*fnRect
->fnSubTop
)(rShadow
.CalcShadowSpace(SvxShadowItemSide::TOP
));
1348 (rRect
.*fnRect
->fnSubLeft
)(rShadow
.CalcShadowSpace(SvxShadowItemSide::LEFT
));
1350 (rRect
.*fnRect
->fnAddBottom
)
1351 (rShadow
.CalcShadowSpace( SvxShadowItemSide::BOTTOM
));
1352 (rRect
.*fnRect
->fnAddRight
)(rShadow
.CalcShadowSpace(SvxShadowItemSide::RIGHT
));
1356 ::SwAlignRect( rRect
, properties
.pSGlobalShell
, properties
.pSGlobalShell
? properties
.pSGlobalShell
->GetOut() : nullptr );
1360 * Extend left/right border/shadow rectangle to bottom of previous frame/to
1361 * top of next frame, if border/shadow is joined with previous/next frame
1363 static void lcl_ExtendLeftAndRight( SwRect
& _rRect
,
1364 const SwFrame
& _rFrame
,
1365 const SwBorderAttrs
& _rAttrs
,
1366 const SwRectFn
& _rRectFn
)
1368 if ( _rAttrs
.JoinedWithPrev( _rFrame
) )
1370 const SwFrame
* pPrevFrame
= _rFrame
.GetPrev();
1371 (_rRect
.*_rRectFn
->fnSetTop
)( (pPrevFrame
->*_rRectFn
->fnGetPrtBottom
)() );
1373 if ( _rAttrs
.JoinedWithNext( _rFrame
) )
1375 const SwFrame
* pNextFrame
= _rFrame
.GetNext();
1376 (_rRect
.*_rRectFn
->fnSetBottom
)( (pNextFrame
->*_rRectFn
->fnGetPrtTop
)() );
1380 /// Returns a range suitable for subtraction when lcl_SubtractFlys() is used.
1381 /// Otherwise DrawFillAttributes() expands the clip path itself.
1382 static basegfx::B2DRange
lcl_ShrinkFly(const SwRect
& rRect
)
1384 static MapMode
aMapMode(MapUnit::MapTwip
);
1385 static const Size aSingleUnit
= Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode
);
1387 double x1
= rRect
.Left() + aSingleUnit
.getWidth();
1388 double y1
= rRect
.Top() + aSingleUnit
.getHeight();
1389 double x2
= rRect
.Right() - aSingleUnit
.getWidth();
1390 double y2
= rRect
.Bottom() - aSingleUnit
.getHeight();
1392 return basegfx::B2DRange(x1
, y1
, x2
, y2
);
1395 static void lcl_SubtractFlys( const SwFrame
*pFrame
, const SwPageFrame
*pPage
,
1396 const SwRect
&rRect
, SwRegionRects
&rRegion
, basegfx::utils::B2DClipState
& rClipState
, SwPaintProperties
const & rProperties
)
1398 const SwSortedObjs
& rObjs
= *pPage
->GetSortedObjs();
1399 const SwFlyFrame
* pSelfFly
= pFrame
->IsInFly() ? pFrame
->FindFlyFrame() : gProp
.pSRetoucheFly2
;
1400 if (!gProp
.pSRetoucheFly
)
1401 gProp
.pSRetoucheFly
= gProp
.pSRetoucheFly2
;
1403 for (size_t j
= 0; (j
< rObjs
.size()) && !rRegion
.empty(); ++j
)
1405 const SwAnchoredObject
* pAnchoredObj
= rObjs
[j
];
1406 const SdrObject
* pSdrObj
= pAnchoredObj
->GetDrawObj();
1408 // Do not consider invisible objects
1409 if (!pPage
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj
->GetLayer()))
1412 const SwFlyFrame
*pFly
= pAnchoredObj
->DynCastFlyFrame();
1416 if (pSelfFly
== pFly
|| gProp
.pSRetoucheFly
== pFly
|| !rRect
.Overlaps(pFly
->getFrameArea()))
1419 if (!pFly
->GetFormat()->GetPrint().GetValue() &&
1420 (OUTDEV_PRINTER
== gProp
.pSGlobalShell
->GetOut()->GetOutDevType() ||
1421 gProp
.pSGlobalShell
->IsPreview()))
1424 const bool bLowerOfSelf
= pSelfFly
&& pFly
->IsLowerOf( pSelfFly
);
1426 //For character bound Flys only examine those Flys in which it is not
1428 //Why only for character bound ones you may ask? It never makes sense to
1429 //subtract frames in which it is anchored itself right?
1430 if (pSelfFly
&& pSelfFly
->IsLowerOf(pFly
))
1433 //Any why does it not apply for the RetoucheFly too?
1434 if (gProp
.pSRetoucheFly
&& gProp
.pSRetoucheFly
->IsLowerOf(pFly
))
1437 #if OSL_DEBUG_LEVEL > 0
1438 //Flys who are anchored inside their own one, must have a bigger OrdNum
1439 //or be character bound.
1440 if (pSelfFly
&& bLowerOfSelf
)
1442 OSL_ENSURE( pFly
->IsFlyInContentFrame() ||
1443 pSdrObj
->GetOrdNumDirect() > pSelfFly
->GetVirtDrawObj()->GetOrdNumDirect(),
1444 "Fly with wrong z-Order" );
1448 bool bStopOnHell
= true;
1451 const SdrObject
*pTmp
= pSelfFly
->GetVirtDrawObj();
1452 if (pSdrObj
->GetLayer() == pTmp
->GetLayer())
1454 if (pSdrObj
->GetOrdNumDirect() < pTmp
->GetOrdNumDirect())
1455 //In the same layer we only observe those that are above.
1460 if (!bLowerOfSelf
&& !pFly
->GetFormat()->GetOpaque().GetValue())
1461 //From other layers we are only interested in non
1462 //transparent ones or those that are internal
1464 bStopOnHell
= false;
1467 if (gProp
.pSRetoucheFly
)
1469 const SdrObject
*pTmp
= gProp
.pSRetoucheFly
->GetVirtDrawObj();
1470 if ( pSdrObj
->GetLayer() == pTmp
->GetLayer() )
1472 if ( pSdrObj
->GetOrdNumDirect() < pTmp
->GetOrdNumDirect() )
1473 //In the same layer we only observe those that are above.
1478 if (!pFly
->IsLowerOf( gProp
.pSRetoucheFly
) && !pFly
->GetFormat()->GetOpaque().GetValue())
1479 //From other layers we are only interested in non
1480 //transparent ones or those that are internal
1482 bStopOnHell
= false;
1486 //If the content of the Fly is transparent, we subtract it only if it's
1487 //contained in the hell layer.
1488 const IDocumentDrawModelAccess
& rIDDMA
= pFly
->GetFormat()->getIDocumentDrawModelAccess();
1489 bool bHell
= pSdrObj
->GetLayer() == rIDDMA
.GetHellId();
1490 if ( (bStopOnHell
&& bHell
) ||
1491 /// Change internal order of condition
1492 /// first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()"
1493 /// have not to be performed, if frame is in "Hell"
1494 ( !bHell
&& pFly
->Lower() && pFly
->Lower()->IsNoTextFrame() &&
1495 (static_cast<SwNoTextFrame
const*>(pFly
->Lower())->IsTransparent() ||
1496 static_cast<SwNoTextFrame
const*>(pFly
->Lower())->HasAnimation() ||
1497 pFly
->GetFormat()->GetSurround().IsContour()
1503 // Own if-statements for transparent background/shadow of fly frames
1504 // in order to handle special conditions.
1505 if (pFly
->IsBackgroundTransparent())
1507 // Background <pFly> is transparent drawn. Thus normally, its region
1508 // have not to be subtracted from given region.
1509 // But, if method is called for a fly frame and
1510 // <pFly> is a direct lower of this fly frame and
1511 // <pFly> inherites its transparent background brush from its parent,
1512 // then <pFly> frame area have to be subtracted from given region.
1513 // NOTE: Because in Status Quo transparent backgrounds can only be
1514 // assigned to fly frames, the handle of this special case
1515 // avoids drawing of transparent areas more than once, if
1516 // a fly frame inherites a transparent background from its
1517 // parent fly frame.
1518 if (pFrame
->IsFlyFrame() &&
1519 (pFly
->GetAnchorFrame()->FindFlyFrame() == pFrame
) &&
1520 pFly
->GetFormat()->IsBackgroundBrushInherited()
1524 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(pFly
) );
1525 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
1526 ::lcl_CalcBorderRect( aRect
, pFly
, rAttrs
, true, rProperties
);
1528 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1537 if (bHell
&& pFly
->GetAnchorFrame()->IsInFly())
1539 //So the border won't get dismantled by the background of the other
1542 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(pFly
) );
1543 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
1544 ::lcl_CalcBorderRect( aRect
, pFly
, rAttrs
, true, rProperties
);
1546 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1550 SwRect
aRect( pFly
->getFramePrintArea() );
1551 aRect
+= pFly
->getFrameArea().Pos();
1553 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1556 if (gProp
.pSRetoucheFly
== gProp
.pSRetoucheFly2
)
1557 gProp
.pSRetoucheFly
= nullptr;
1560 static void lcl_implDrawGraphicBackground(const SvxBrushItem
& _rBackgrdBrush
,
1561 vcl::RenderContext
& _rOut
,
1562 const SwRect
& _rAlignedPaintRect
,
1563 const GraphicObject
& _rGraphicObj
,
1564 SwPaintProperties
const & properties
)
1566 /// determine color of background
1567 /// If color of background brush is not "no fill"/"auto fill" or
1568 /// <SwPaintProperties.bSFlyMetafile> is set, use color of background brush, otherwise
1569 /// use global retouche color.
1570 const Color
aColor( ( (_rBackgrdBrush
.GetColor() != COL_TRANSPARENT
) || properties
.bSFlyMetafile
)
1571 ? _rBackgrdBrush
.GetColor()
1572 : aGlobalRetoucheColor
);
1574 /// determine, if background color have to be drawn transparent
1575 /// and calculate transparency percent value
1576 sal_Int8 nTransparencyPercent
= 0;
1577 bool bDrawTransparent
= false;
1578 if ( aColor
.IsTransparent() )
1579 /// background color is transparent --> draw transparent.
1581 bDrawTransparent
= true;
1582 nTransparencyPercent
= ((255 - aColor
.GetAlpha())*100 + 0x7F)/0xFF;
1584 else if ( (_rGraphicObj
.GetAttr().IsTransparent()) &&
1585 (_rBackgrdBrush
.GetColor() == COL_TRANSPARENT
) )
1586 /// graphic is drawn transparent and background color is
1587 /// "no fill"/"auto fill" --> draw transparent
1589 bDrawTransparent
= true;
1590 nTransparencyPercent
= 100 - (_rGraphicObj
.GetAttr().GetAlpha() * 100 + 127) / 255;
1593 if ( bDrawTransparent
)
1595 /// draw background transparent
1596 if( _rOut
.GetFillColor() != aColor
.GetRGBColor() )
1597 _rOut
.SetFillColor( aColor
.GetRGBColor() );
1598 tools::PolyPolygon
aPoly( _rAlignedPaintRect
.SVRect() );
1599 _rOut
.DrawTransparent( aPoly
, nTransparencyPercent
);
1603 /// draw background opaque
1604 if ( _rOut
.GetFillColor() != aColor
)
1605 _rOut
.SetFillColor( aColor
);
1606 _rOut
.DrawRect( _rAlignedPaintRect
.SVRect() );
1611 * This is a local help method to draw a background for a graphic
1613 * Under certain circumstances we have to draw a background for a graphic.
1614 * This method takes care of the conditions and draws the background with the
1615 * corresponding color.
1616 * Method introduced for bug fix #103876# in order to optimize drawing tiled
1617 * background graphics. Previously, this code was integrated in method
1618 * <lcl_DrawGraphic>.
1619 * Method implemented as an inline, checking the conditions and calling method
1620 * method <lcl_implDrawGraphicBackground(..)> for the intrinsic drawing.
1622 * @param _rBackgrdBrush
1623 * background brush contain the color the background has to be drawn.
1626 * output device the background has to be drawn in.
1628 * @param _rAlignedPaintRect
1629 * paint rectangle in the output device, which has to be drawn with the background.
1630 * rectangle have to be aligned by method ::SwAlignRect
1632 * @param _rGraphicObj
1633 * graphic object, for which the background has to be drawn. Used for checking
1634 * the transparency of its bitmap, its type and if the graphic is drawn transparent
1636 * @param _bNumberingGraphic
1637 * boolean indicating that graphic is used as a numbering.
1639 * @param _bBackgrdAlreadyDrawn
1640 * boolean (optional; default: false) indicating, if the background is already drawn.
1642 static void lcl_DrawGraphicBackground( const SvxBrushItem
& _rBackgrdBrush
,
1643 OutputDevice
& _rOut
,
1644 const SwRect
& _rAlignedPaintRect
,
1645 const GraphicObject
& _rGraphicObj
,
1646 bool _bNumberingGraphic
,
1647 SwPaintProperties
const & properties
,
1648 bool _bBackgrdAlreadyDrawn
= false)
1650 // draw background with background color, if
1651 // (1) graphic is not used as a numbering AND
1652 // (2) background is not already drawn AND
1653 // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
1654 if ( !_bNumberingGraphic
&&
1655 !_bBackgrdAlreadyDrawn
&&
1656 ( _rGraphicObj
.IsTransparent() || _rGraphicObj
.GetType() == GraphicType::NONE
)
1659 lcl_implDrawGraphicBackground( _rBackgrdBrush
, _rOut
, _rAlignedPaintRect
, _rGraphicObj
, properties
);
1664 * NNOTE: the transparency of the background graphic is saved in
1665 * SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency()
1666 * and is considered in the drawing of the graphic
1668 * Thus, to provide transparent background graphic for text frames nothing
1671 * Use align rectangle for drawing graphic Pixel-align coordinates for
1673 * Outsource code for drawing background of the graphic
1674 * with a background color in method <lcl_DrawGraphicBackground>
1676 * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
1678 static void lcl_DrawGraphic( const SvxBrushItem
& rBrush
, vcl::RenderContext
&rOutDev
,
1679 const SwViewShell
&rSh
, const SwRect
&rGrf
, const SwRect
&rOut
,
1681 SwPaintProperties
const & properties
,
1682 bool bBackgrdAlreadyDrawn
)
1683 // add parameter <bBackgrdAlreadyDrawn> to indicate
1684 // that the background is already drawn.
1686 // Calculate align rectangle from parameter <rGrf> and use aligned
1687 // rectangle <aAlignedGrfRect> in the following code
1688 SwRect aAlignedGrfRect
= rGrf
;
1689 ::SwAlignRect( aAlignedGrfRect
, &rSh
, &rOutDev
);
1691 // Change type from <bool> to <bool>.
1692 const bool bNotInside
= !rOut
.Contains( aAlignedGrfRect
);
1695 rOutDev
.Push( vcl::PushFlags::CLIPREGION
);
1696 rOutDev
.IntersectClipRegion( rOut
.SVRect() );
1699 GraphicObject
*pGrf
= const_cast<GraphicObject
*>(rBrush
.GetGraphicObject());
1701 OUString aOriginURL
= pGrf
->GetGraphic().getOriginURL();
1702 if (pGrf
->GetGraphic().GetType() == GraphicType::Default
&& !aOriginURL
.isEmpty())
1704 Graphic aGraphic
= vcl::graphic::loadFromURL(aOriginURL
);
1705 pGrf
->SetGraphic(aGraphic
);
1708 // Outsource drawing of background with a background color
1709 ::lcl_DrawGraphicBackground( rBrush
, rOutDev
, aAlignedGrfRect
, *pGrf
, bGrfNum
, properties
, bBackgrdAlreadyDrawn
);
1711 // Because for drawing a graphic left-top-corner and size coordinates are
1712 // used, these coordinates have to be determined on pixel level.
1713 ::SwAlignGrfRect( &aAlignedGrfRect
, rOutDev
);
1715 const basegfx::B2DHomMatrix
aGraphicTransform(
1716 basegfx::utils::createScaleTranslateB2DHomMatrix(
1717 aAlignedGrfRect
.Width(), aAlignedGrfRect
.Height(),
1718 aAlignedGrfRect
.Left(), aAlignedGrfRect
.Top()));
1720 paintGraphicUsingPrimitivesHelper(
1733 bool DrawFillAttributes(
1734 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& rFillAttributes
,
1735 const SwRect
& rOriginalLayoutRect
,
1736 const SwRegionRects
& rPaintRegion
,
1737 const basegfx::utils::B2DClipState
& rClipState
,
1738 vcl::RenderContext
& rOut
)
1740 if(rFillAttributes
&& rFillAttributes
->isUsed())
1742 basegfx::B2DRange
aPaintRange(
1743 rPaintRegion
.GetOrigin().Left(),
1744 rPaintRegion
.GetOrigin().Top(),
1745 rPaintRegion
.GetOrigin().Right(),
1746 rPaintRegion
.GetOrigin().Bottom());
1748 if (!aPaintRange
.isEmpty() &&
1749 !rPaintRegion
.empty() &&
1750 !basegfx::fTools::equalZero(aPaintRange
.getWidth()) &&
1751 !basegfx::fTools::equalZero(aPaintRange
.getHeight()))
1753 // need to expand for correct AAed and non-AAed visualization as primitive.
1754 // This must probably be removed again when we will be able to get all Writer visualization
1755 // as primitives and Writer prepares all it's stuff in high precision coordinates (also
1756 // needs to avoid moving boundaries around to better show overlapping stuff...)
1757 if (utl::ConfigManager::IsFuzzing() || SvtOptionsDrawinglayer::IsAntiAliasing())
1759 // if AAed in principle expand by 0.5 in all directions. Since painting edges of
1760 // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
1761 // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
1762 // artifacts. Checked experimentally - a little bit more in Y is needed, probably
1763 // due to still existing integer alignment and crunching in writer.
1764 static const double fExpandX
= 0.55;
1765 static const double fExpandY
= 0.70;
1766 const basegfx::B2DVector
aSingleUnit(rOut
.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX
, fExpandY
));
1768 aPaintRange
.expand(aPaintRange
.getMinimum() - aSingleUnit
);
1769 aPaintRange
.expand(aPaintRange
.getMaximum() + aSingleUnit
);
1773 // if not AAed expand by one unit to bottom right due to the missing unit
1774 // from SwRect/Rectangle integer handling
1775 const basegfx::B2DVector
aSingleUnit(rOut
.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
1777 aPaintRange
.expand(aPaintRange
.getMaximum() + aSingleUnit
);
1780 const basegfx::B2DRange
aDefineRange(
1781 rOriginalLayoutRect
.Left(),
1782 rOriginalLayoutRect
.Top(),
1783 rOriginalLayoutRect
.Right(),
1784 rOriginalLayoutRect
.Bottom());
1786 const drawinglayer::primitive2d::Primitive2DContainer
& rSequence
= rFillAttributes
->getPrimitive2DSequence(
1790 if(rSequence
.size())
1792 drawinglayer::primitive2d::Primitive2DContainer
const*
1793 pPrimitives(&rSequence
);
1794 drawinglayer::primitive2d::Primitive2DContainer primitives
;
1795 // tdf#86578 the awful lcl_SubtractFlys hack
1796 if (rPaintRegion
.size() > 1 || rPaintRegion
[0] != rPaintRegion
.GetOrigin())
1798 basegfx::B2DPolyPolygon
const& maskRegion(rClipState
.getClipPoly());
1799 primitives
.resize(1);
1800 primitives
[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
1801 maskRegion
, drawinglayer::primitive2d::Primitive2DContainer(rSequence
));
1802 pPrimitives
= &primitives
;
1804 assert(pPrimitives
&& pPrimitives
->size());
1806 drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
1807 aViewInformation2D
.setViewTransformation(rOut
.GetViewTransformation());
1808 aViewInformation2D
.setViewport(aPaintRange
);
1810 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1812 aViewInformation2D
) );
1813 pProcessor
->process(*pPrimitives
);
1823 const SvxBrushItem
*pBrush
,
1824 vcl::RenderContext
&rOutDev
,
1827 const sal_uInt8 nGrfNum
,
1828 const bool bConsiderBackgroundTransparency
)
1829 // Add 6th parameter to indicate that method should
1830 // consider background transparency, saved in the color of the brush item
1832 SwViewShell
&rSh
= *gProp
.pSGlobalShell
;
1833 bool bReplaceGrfNum
= GRFNUM_REPLACE
== nGrfNum
;
1834 bool bGrfNum
= GRFNUM_NO
!= nGrfNum
;
1836 SvxGraphicPosition ePos
= GPOS_NONE
;
1837 if( pBrush
&& !bReplaceGrfNum
)
1839 if( rSh
.GetViewOptions()->IsGraphic() )
1842 SfxObjectShell
* sh
= rSh
.GetDoc()->GetPersist();
1843 if (sh
!= nullptr && sh
->HasName()) {
1844 referer
= sh
->GetMedium()->GetName();
1846 const Graphic
* pGrf
= pBrush
->GetGraphic(referer
);
1847 if( pGrf
&& GraphicType::NONE
!= pGrf
->GetType() )
1849 ePos
= pBrush
->GetGraphicPos();
1850 if( pGrf
->IsSupportedGraphic() )
1851 // don't the use the specific output device! Bug 94802
1852 aGrfSize
= ::GetGraphicSizeTwip( *pGrf
, nullptr );
1856 bReplaceGrfNum
= bGrfNum
;
1860 aGrf
.SSize( aGrfSize
);
1862 bool bRetouche
= true;
1866 aGrf
.Pos() = rOrg
.Pos();
1870 aGrf
.Pos().setY( rOrg
.Top() );
1871 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1875 aGrf
.Pos().setY( rOrg
.Top() );
1876 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1880 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1881 aGrf
.Pos().setX( rOrg
.Left() );
1885 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1886 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1890 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1891 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1895 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1896 aGrf
.Pos().setX( rOrg
.Left() );
1900 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1901 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1905 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1906 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1911 // Despite the fact that the background graphic has to fill the complete
1912 // area, we already checked, whether the graphic will completely fill out
1913 // the region the <rOut> that is to be painted. Thus, nothing has to be
1915 // E.g. this is the case for a Fly Frame without a background
1916 // brush positioned on the border of the page which inherited the background
1917 // brush from the page.
1918 bRetouche
= !rOut
.Contains( aGrf
);
1923 // draw background of tiled graphic before drawing tiled graphic in loop
1924 // determine graphic object
1925 GraphicObject
* pGraphicObj
= const_cast< GraphicObject
* >(pBrush
->GetGraphicObject());
1926 // calculate aligned paint rectangle
1927 SwRect aAlignedPaintRect
= rOut
;
1928 ::SwAlignRect( aAlignedPaintRect
, &rSh
, &rOutDev
);
1929 // draw background color for aligned paint rectangle
1930 lcl_DrawGraphicBackground( *pBrush
, rOutDev
, aAlignedPaintRect
, *pGraphicObj
, bGrfNum
, gProp
);
1932 // set left-top-corner of background graphic to left-top-corner of the
1933 // area, from which the background brush is determined.
1934 aGrf
.Pos() = rOrg
.Pos();
1935 // setup clipping at output device
1936 rOutDev
.Push( vcl::PushFlags::CLIPREGION
);
1937 rOutDev
.IntersectClipRegion( rOut
.SVRect() );
1938 // use new method <GraphicObject::DrawTiled(::)>
1940 // calculate paint offset
1941 Point
aPaintOffset( aAlignedPaintRect
.Pos() - aGrf
.Pos() );
1942 // draw background graphic tiled for aligned paint rectangle
1944 // For PDF export, every draw operation for bitmaps takes a
1945 // noticeable amount of place (~50 characters). Thus, optimize
1946 // between tile bitmap size and number of drawing operations here.
1949 // n_chars = k1 * ---------- + k2 * A_bitmap
1952 // minimum n_chars is obtained for (derive for A_bitmap,
1953 // set to 0, take positive solution):
1955 // A_bitmap = Sqrt( ---- A_out )
1958 // where k1 is the number of chars per draw operation, and
1959 // k2 is the number of chars per bitmap pixel.
1960 // This is approximately 50 and 7 for current PDF writer, respectively.
1962 const double k1( 50 );
1963 const double k2( 7 );
1964 const Size
aSize( aAlignedPaintRect
.SSize() );
1965 const double Abitmap( k1
/k2
* static_cast<double>(aSize
.Width())*aSize
.Height() );
1967 pGraphicObj
->DrawTiled( rOutDev
,
1968 aAlignedPaintRect
.SVRect(),
1970 Size( aPaintOffset
.X(), aPaintOffset
.Y() ),
1971 std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap
)) + .5 ) ) );
1973 // reset clipping at output device
1975 // set <bDraw> and <bRetouche> to false, indicating that background
1976 // graphic and background are already drawn.
1977 bDraw
= bRetouche
= false;
1985 default: OSL_ENSURE( false, "new Graphic position?" );
1988 /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of
1989 /// graphic is already drawn or not.
1990 bool bGrfBackgrdAlreadyDrawn
= false;
1993 rOutDev
.Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
1994 rOutDev
.SetLineColor();
1996 // check, if an existing background graphic (not filling the complete
1997 // background) is transparent drawn and the background color is
1998 // "no fill" respectively "auto fill", if background transparency
1999 // has to be considered.
2000 // If YES, memorize transparency of background graphic.
2001 // check also, if background graphic bitmap is transparent.
2002 bool bTransparentGrfWithNoFillBackgrd
= false;
2003 sal_Int32 nGrfTransparency
= 0;
2004 bool bGrfIsTransparent
= false;
2005 if ( (ePos
!= GPOS_NONE
) &&
2006 (ePos
!= GPOS_TILED
) && (ePos
!= GPOS_AREA
)
2009 GraphicObject
*pGrf
= const_cast<GraphicObject
*>(pBrush
->GetGraphicObject());
2010 if ( bConsiderBackgroundTransparency
)
2012 GraphicAttr aGrfAttr
= pGrf
->GetAttr();
2013 if ( (aGrfAttr
.IsTransparent()) &&
2014 (pBrush
->GetColor() == COL_TRANSPARENT
)
2017 bTransparentGrfWithNoFillBackgrd
= true;
2018 nGrfTransparency
= 255 - aGrfAttr
.GetAlpha();
2021 if ( pGrf
->IsTransparent() )
2023 bGrfIsTransparent
= true;
2027 // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
2028 // instead of checking, if transparency is not set.
2029 const Color
aColor( pBrush
&&
2030 ( (pBrush
->GetColor() != COL_TRANSPARENT
) ||
2031 gProp
.bSFlyMetafile
)
2032 ? pBrush
->GetColor()
2033 : aGlobalRetoucheColor
);
2035 // determine, if background region have to be
2036 // drawn transparent.
2037 // background region has to be drawn transparent, if
2038 // background transparency have to be considered
2040 // ( background color is transparent OR
2041 // background graphic is transparent and background color is "no fill"
2047 } eDrawStyle
= Default
;
2049 if (bConsiderBackgroundTransparency
&&
2050 ( ( aColor
.IsTransparent()) ||
2051 bTransparentGrfWithNoFillBackgrd
) )
2053 eDrawStyle
= Transparent
;
2056 // #i75614# reset draw mode in high contrast mode in order to get fill color set
2057 const DrawModeFlags nOldDrawMode
= rOutDev
.GetDrawMode();
2058 if ( gProp
.pSGlobalShell
->GetWin() &&
2059 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2061 rOutDev
.SetDrawMode( DrawModeFlags::Default
);
2064 // If background region has to be drawn transparent, set only the RGB values of the background color as
2065 // the fill color for the output device.
2070 if( rOutDev
.GetFillColor() != aColor
.GetRGBColor() )
2071 rOutDev
.SetFillColor( aColor
.GetRGBColor() );
2076 if( rOutDev
.GetFillColor() != aColor
)
2077 rOutDev
.SetFillColor( aColor
);
2083 // restore draw mode
2084 rOutDev
.SetDrawMode( nOldDrawMode
);
2090 // background region have to be drawn transparent.
2091 // Thus, create a poly-polygon from the region and draw it with
2092 // the corresponding transparency percent.
2093 tools::PolyPolygon
aDrawPoly( rOut
.SVRect() );
2094 if ( aGrf
.HasArea() )
2096 if ( !bGrfIsTransparent
)
2098 // subtract area of background graphic from draw area
2099 // Consider only that part of the graphic area that is overlapping with draw area.
2100 SwRect aTmpGrf
= aGrf
;
2101 aTmpGrf
.Intersection( rOut
);
2102 if ( aTmpGrf
.HasArea() )
2104 tools::Polygon
aGrfPoly( aTmpGrf
.SVRect() );
2105 aDrawPoly
.Insert( aGrfPoly
);
2109 bGrfBackgrdAlreadyDrawn
= true;
2111 // calculate transparency percent:
2112 // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
2113 // If there is a background graphic with a background color "no fill"/"auto fill",
2114 // the transparency value is taken from the background graphic,
2115 // otherwise take the transparency value from the color.
2116 sal_Int8 nTransparencyPercent
= static_cast<sal_Int8
>(
2117 (( bTransparentGrfWithNoFillBackgrd
? nGrfTransparency
: (255 - aColor
.GetAlpha())
2118 )*100 + 0x7F)/0xFF);
2119 // draw poly-polygon transparent
2120 rOutDev
.DrawTransparent( aDrawPoly
, nTransparencyPercent
);
2127 SwRegionRects
aRegion( rOut
, 4 );
2128 if ( !bGrfIsTransparent
)
2131 bGrfBackgrdAlreadyDrawn
= true;
2132 // loop rectangles of background region, which has to be drawn
2133 for( size_t i
= 0; i
< aRegion
.size(); ++i
)
2135 rOutDev
.DrawRect( aRegion
[i
].SVRect() );
2142 if( bDraw
&& aGrf
.Overlaps( rOut
) )
2143 lcl_DrawGraphic( *pBrush
, rOutDev
, rSh
, aGrf
, rOut
, bGrfNum
, gProp
,
2144 bGrfBackgrdAlreadyDrawn
);
2146 if( bReplaceGrfNum
)
2148 const BitmapEx
& rBmp
= rSh
.GetReplacementBitmap(false);
2149 vcl::Font
aTmp( rOutDev
.GetFont() );
2150 Graphic::DrawEx(rOutDev
, OUString(), aTmp
, rBmp
, rOrg
.Pos(), rOrg
.SSize());
2155 * Local helper for SwRootFrame::PaintSwFrame(..) - Adjust given rectangle to pixel size
2157 * By OD at 27.09.2002 for #103636#
2158 * In order to avoid paint errors caused by multiple alignments (e.g. ::SwAlignRect(..))
2159 * and other changes to the to be painted rectangle, this method is called for the
2160 * rectangle to be painted in order to adjust it to the pixel it is overlapping
2162 static void lcl_AdjustRectToPixelSize( SwRect
& io_aSwRect
, const vcl::RenderContext
&aOut
)
2164 // local constant object of class <Size> to determine number of Twips
2165 // representing a pixel.
2166 const Size
aTwipToPxSize( aOut
.PixelToLogic( Size( 1,1 )) );
2168 // local object of class <Rectangle> in Twip coordinates
2169 // calculated from given rectangle aligned to pixel centers.
2170 const tools::Rectangle aPxCenterRect
= aOut
.PixelToLogic(
2171 aOut
.LogicToPixel( io_aSwRect
.SVRect() ) );
2173 // local constant object of class <Rectangle> representing given rectangle
2175 const tools::Rectangle aOrgPxRect
= aOut
.LogicToPixel( io_aSwRect
.SVRect() );
2177 // calculate adjusted rectangle from pixel centered rectangle.
2178 // Due to rounding differences <aPxCenterRect> doesn't exactly represents
2179 // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
2180 // Afterwards, adjust calculated Twip-positions of the all borders.
2181 tools::Rectangle aSizedRect
= aPxCenterRect
;
2182 aSizedRect
.AdjustLeft( -(aTwipToPxSize
.Width()/2 + 1) );
2183 aSizedRect
.AdjustRight( aTwipToPxSize
.Width()/2 + 1 );
2184 aSizedRect
.AdjustTop( -(aTwipToPxSize
.Height()/2 + 1) );
2185 aSizedRect
.AdjustBottom(aTwipToPxSize
.Height()/2 + 1);
2188 while ( aOut
.LogicToPixel(aSizedRect
).Left() < aOrgPxRect
.Left() )
2190 aSizedRect
.AdjustLeft( 1 );
2193 while ( aOut
.LogicToPixel(aSizedRect
).Right() > aOrgPxRect
.Right() )
2195 aSizedRect
.AdjustRight( -1 );
2198 while ( aOut
.LogicToPixel(aSizedRect
).Top() < aOrgPxRect
.Top() )
2200 aSizedRect
.AdjustTop( 1 );
2203 while ( aOut
.LogicToPixel(aSizedRect
).Bottom() > aOrgPxRect
.Bottom() )
2205 aSizedRect
.AdjustBottom( -1 );
2208 io_aSwRect
= SwRect( aSizedRect
);
2210 #if OSL_DEBUG_LEVEL > 0
2211 tools::Rectangle aTestOrgPxRect
= aOut
.LogicToPixel( io_aSwRect
.SVRect() );
2212 tools::Rectangle aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2213 OSL_ENSURE( aTestOrgPxRect
== aTestNewPxRect
,
2214 "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
2216 aSizedRect
.AdjustLeft( -1 );
2217 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2218 OSL_ENSURE( aTestOrgPxRect
.Left() >= (aTestNewPxRect
.Left()+1),
2219 "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
2220 aSizedRect
.AdjustLeft( 1 );
2222 aSizedRect
.AdjustRight( 1 );
2223 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2224 OSL_ENSURE( aTestOrgPxRect
.Right() <= (aTestNewPxRect
.Right()-1),
2225 "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
2226 aSizedRect
.AdjustRight( -1 );
2228 aSizedRect
.AdjustTop( -1 );
2229 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2230 OSL_ENSURE( aTestOrgPxRect
.Top() >= (aTestNewPxRect
.Top()+1),
2231 "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
2232 aSizedRect
.AdjustTop( 1 );
2234 aSizedRect
.AdjustBottom( 1 );
2235 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2236 OSL_ENSURE( aTestOrgPxRect
.Bottom() <= (aTestNewPxRect
.Bottom()-1),
2237 "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
2238 aSizedRect
.AdjustBottom( -1 );
2242 // FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
2251 SwTwips mnLimitedEndPos
;
2254 svx::frame::Style maAttribute
;
2256 enum OverlapType
{ NO_OVERLAP
, OVERLAP1
, OVERLAP2
, OVERLAP3
};
2258 enum class VerticalType
{ LEFT
, RIGHT
};
2261 SwLineEntry( SwTwips nKey
,
2265 const svx::frame::Style
& rAttribute
);
2267 OverlapType
Overlaps( const SwLineEntry
& rComp
) const;
2270 * Assuming that this entry is for a Word-style covering cell and the border matching eType is
2271 * set, limit the end position of this border in case covered cells have no borders set.
2273 void LimitVerticalEndPos(const SwFrame
& rFrame
, VerticalType eType
);
2278 SwLineEntry::SwLineEntry( SwTwips nKey
,
2282 const svx::frame::Style
& rAttribute
)
2284 mnStartPos( nStartPos
),
2285 mnEndPos( nEndPos
),
2288 maAttribute( rAttribute
)
2303 4. ------------- rOld
2312 7. ------------- rOld
2322 SwLineEntry::OverlapType
SwLineEntry::Overlaps( const SwLineEntry
& rNew
) const
2324 SwLineEntry::OverlapType eRet
= OVERLAP3
;
2326 if ( mnStartPos
>= rNew
.mnEndPos
|| mnEndPos
<= rNew
.mnStartPos
)
2330 else if ( mnEndPos
< rNew
.mnEndPos
)
2334 else if (mnStartPos
<= rNew
.mnStartPos
)
2341 void SwLineEntry::LimitVerticalEndPos(const SwFrame
& rFrame
, VerticalType eType
)
2343 if (!rFrame
.IsCellFrame())
2348 const auto& rCellFrame
= static_cast<const SwCellFrame
&>(rFrame
);
2349 std::vector
<const SwCellFrame
*> aCoveredCells
= rCellFrame
.GetCoveredCells();
2350 // Iterate in reverse order, so we can stop at the first cell that has a border. This can
2351 // determine what is the minimal end position that is safe to use as a limit.
2352 for (auto it
= aCoveredCells
.rbegin(); it
!= aCoveredCells
.rend(); ++it
)
2354 const SwCellFrame
* pCoveredCell
= *it
;
2355 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pCoveredCell
);
2356 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2357 const SvxBoxItem
& rBox
= rAttrs
.GetBox();
2358 if (eType
== VerticalType::LEFT
&& rBox
.GetLeft())
2363 if (eType
== VerticalType::RIGHT
&& rBox
.GetRight())
2368 mnLimitedEndPos
= pCoveredCell
->getFrameArea().Top();
2374 struct lt_SwLineEntry
2376 bool operator()( const SwLineEntry
& e1
, const SwLineEntry
& e2
) const
2378 return e1
.mnStartPos
< e2
.mnStartPos
;
2384 typedef std::set
< SwLineEntry
, lt_SwLineEntry
> SwLineEntrySet
;
2385 typedef std::map
< SwTwips
, SwLineEntrySet
> SwLineEntryMap
;
2389 class SwTabFramePainter
2391 SwLineEntryMap maVertLines
;
2392 SwLineEntryMap maHoriLines
;
2393 const SwTabFrame
& mrTabFrame
;
2395 void Insert( SwLineEntry
&, bool bHori
);
2396 void Insert(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
, const SwRect
&rPaintArea
);
2398 /// Inserts top border at the top of a follow table.
2399 void InsertFollowTopBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2400 bool bWordTableCell
, SwTwips nTop
, SwTwips nLeft
, SwTwips nRight
,
2402 void InsertMasterBottomBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2403 bool bWordTableCell
, SwTwips nBottom
, SwTwips nLeft
, SwTwips nRight
,
2404 bool bBottomIsOuter
);
2406 void HandleFrame(const SwLayoutFrame
& rFrame
, const SwRect
& rPaintArea
);
2407 void FindStylesForLine( Point
&,
2411 bool bOuter
) const;
2414 explicit SwTabFramePainter( const SwTabFrame
& rTabFrame
);
2416 void PaintLines( OutputDevice
& rDev
, const SwRect
& rRect
) const;
2421 SwTabFramePainter::SwTabFramePainter( const SwTabFrame
& rTabFrame
)
2422 : mrTabFrame( rTabFrame
)
2424 SwRect aPaintArea
= rTabFrame
.GetUpper()->GetPaintArea();
2425 HandleFrame(rTabFrame
, aPaintArea
);
2428 void SwTabFramePainter::HandleFrame(const SwLayoutFrame
& rLayoutFrame
, const SwRect
& rPaintArea
)
2430 // Add border lines of cell frames. Skip covered cells. Skip cells
2431 // in special row span row, which do not have a negative row span:
2432 if ( rLayoutFrame
.IsCellFrame() && !rLayoutFrame
.IsCoveredCell() )
2434 const SwCellFrame
* pThisCell
= static_cast<const SwCellFrame
*>(&rLayoutFrame
);
2435 const SwRowFrame
* pRowFrame
= static_cast<const SwRowFrame
*>(pThisCell
->GetUpper());
2436 const tools::Long nRowSpan
= pThisCell
->GetTabBox()->getRowSpan();
2437 if ( !pRowFrame
->IsRowSpanLine() || nRowSpan
> 1 || nRowSpan
< -1 )
2439 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), &rLayoutFrame
);
2440 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2441 const SvxBoxItem
& rBox
= rAttrs
.GetBox();
2442 Insert(rLayoutFrame
, rBox
, rPaintArea
);
2446 // Recurse into lower layout frames, but do not recurse into lower tabframes.
2447 const SwFrame
* pLower
= rLayoutFrame
.Lower();
2450 if (pLower
->IsLayoutFrame() && !pLower
->IsTabFrame())
2452 const SwLayoutFrame
* pLowerLayFrame
= static_cast<const SwLayoutFrame
*>(pLower
);
2453 HandleFrame(*pLowerLayFrame
, rPaintArea
);
2455 pLower
= pLower
->GetNext();
2459 void SwTabFramePainter::PaintLines(OutputDevice
& rDev
, const SwRect
& rRect
) const
2461 // #i16816# tagged pdf support
2462 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev
);
2464 SwLineEntryMap::const_iterator aIter
= maHoriLines
.begin();
2467 // color for subsidiary lines:
2468 const Color
& rCol( gProp
.pSGlobalShell
->GetViewOptions()->GetTableBoundariesColor() );
2470 // high contrast mode:
2471 // overrides the color of non-subsidiary lines.
2472 const Color
* pHCColor
= nullptr;
2473 DrawModeFlags nOldDrawMode
= rDev
.GetDrawMode();
2474 if( gProp
.pSGlobalShell
->GetWin() &&
2475 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2477 pHCColor
= &gProp
.pSGlobalShell
->GetViewOptions()->GetFontColor();
2478 rDev
.SetDrawMode( DrawModeFlags::Default
);
2481 const SwFrame
* pUpper
= mrTabFrame
.GetUpper();
2482 SwRect
aUpper( pUpper
->getFramePrintArea() );
2483 aUpper
.Pos() += pUpper
->getFrameArea().Pos();
2484 SwRect
aUpperAligned( aUpper
);
2485 ::SwAlignRect( aUpperAligned
, gProp
.pSGlobalShell
, &rDev
);
2487 // prepare SdrFrameBorderDataVector
2488 drawinglayer::primitive2d::SdrFrameBorderDataVector aData
;
2492 if ( bHori
&& aIter
== maHoriLines
.end() )
2494 aIter
= maVertLines
.begin();
2498 if ( !bHori
&& aIter
== maVertLines
.end() )
2501 const SwLineEntrySet
& rEntrySet
= (*aIter
).second
;
2502 for (const SwLineEntry
& rEntry
: rEntrySet
)
2504 const svx::frame::Style
& rEntryStyle( rEntry
.maAttribute
);
2509 aStart
.setX( rEntry
.mnStartPos
);
2510 aStart
.setY( rEntry
.mnKey
);
2511 aEnd
.setX( rEntry
.mnEndPos
);
2512 aEnd
.setY( rEntry
.mnKey
);
2516 aStart
.setX( rEntry
.mnKey
);
2517 aStart
.setY( rEntry
.mnStartPos
);
2518 aEnd
.setX( rEntry
.mnKey
);
2519 aEnd
.setY( rEntry
.mnEndPos
);
2522 svx::frame::Style aStyles
[ 7 ];
2523 aStyles
[ 0 ] = rEntryStyle
;
2524 FindStylesForLine(aStart
, aEnd
, aStyles
, bHori
, rEntry
.mbOuter
);
2526 if (!bHori
&& rEntry
.mnLimitedEndPos
)
2528 aEnd
.setY(rEntry
.mnLimitedEndPos
);
2531 SwRect
aRepaintRect( aStart
, aEnd
);
2533 // the repaint rectangle has to be moved a bit for the centered lines:
2534 SwTwips nRepaintRectSize
= !rEntryStyle
.GetWidth() ? 1 : rEntryStyle
.GetWidth();
2537 aRepaintRect
.Height( 2 * nRepaintRectSize
);
2538 aRepaintRect
.Pos().AdjustY( -nRepaintRectSize
);
2540 // To decide on visibility it is also necessary to expand the RepaintRect
2541 // to left/right according existing BorderLine overlap matchings, else there
2542 // will be repaint errors when scrolling in e.t TripleLine BorderLines.
2543 // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB
2544 if(aStyles
[1].IsUsed() || aStyles
[3].IsUsed() || aStyles
[4].IsUsed() || aStyles
[6].IsUsed())
2546 const double fLineWidthMaxLeft(std::max(aStyles
[1].GetWidth(), aStyles
[3].GetWidth()));
2547 const double fLineWidthMaxRight(std::max(aStyles
[4].GetWidth(), aStyles
[6].GetWidth()));
2548 aRepaintRect
.Width(aRepaintRect
.Width() + (fLineWidthMaxLeft
+ fLineWidthMaxRight
));
2549 aRepaintRect
.Pos().AdjustX( -fLineWidthMaxLeft
);
2554 aRepaintRect
.Width( 2 * nRepaintRectSize
);
2555 aRepaintRect
.Pos().AdjustX( -nRepaintRectSize
);
2557 // Accordingly to horizontal case, but for top/bottom
2558 // aStyles[3] == aTFromR, aStyles[1] == aTFromL, aStyles[6] == aBFromR, aStyles[4] == aBFromL
2559 if(aStyles
[3].IsUsed() || aStyles
[1].IsUsed() || aStyles
[6].IsUsed() || aStyles
[4].IsUsed())
2561 const double fLineWidthMaxTop(std::max(aStyles
[3].GetWidth(), aStyles
[1].GetWidth()));
2562 const double fLineWidthMaxBottom(std::max(aStyles
[6].GetWidth(), aStyles
[4].GetWidth()));
2563 aRepaintRect
.Height(aRepaintRect
.Height() + (fLineWidthMaxTop
+ fLineWidthMaxBottom
));
2564 aRepaintRect
.Pos().AdjustY( -fLineWidthMaxTop
);
2568 if (!rRect
.Overlaps(aRepaintRect
))
2574 const Color
* pTmpColor
= nullptr;
2575 if (0 == aStyles
[ 0 ].GetWidth())
2577 if (isTableBoundariesEnabled() && gProp
.pSGlobalShell
->GetWin())
2578 aStyles
[ 0 ].Set( rCol
, rCol
, rCol
, false, 1, 0, 0 );
2580 aStyles
[0].SetType(SvxBorderLineStyle::NONE
);
2583 pTmpColor
= pHCColor
;
2585 // The (twip) positions will be adjusted to meet these requirements:
2586 // 1. The y coordinates are located in the middle of the pixel grid
2587 // 2. The x coordinated are located at the beginning of the pixel grid
2588 // This is done, because the horizontal lines are painted "at
2589 // beginning", whereas the vertical lines are painted "centered".
2590 // By making the line sizes a multiple of one pixel size, we can
2591 // assure that all lines having the same twip size have the same
2592 // pixel size, independent of their position on the screen.
2593 Point aPaintStart
= rDev
.PixelToLogic( rDev
.LogicToPixel(aStart
) );
2594 Point aPaintEnd
= rDev
.PixelToLogic( rDev
.LogicToPixel(aEnd
) );
2596 if (gProp
.pSGlobalShell
->GetWin())
2598 // The table borders do not use SwAlignRect, but all the other frames do.
2599 // Therefore we tweak the outer borders a bit to achieve that the outer
2600 // borders match the subsidiary lines of the upper:
2601 if (aStart
.X() == aUpper
.Left())
2602 aPaintStart
.setX( aUpperAligned
.Left() );
2603 else if (aStart
.X() == aUpper
.Right_())
2604 aPaintStart
.setX( aUpperAligned
.Right_() );
2605 if (aStart
.Y() == aUpper
.Top())
2606 aPaintStart
.setY( aUpperAligned
.Top() );
2607 else if (aStart
.Y() == aUpper
.Bottom_())
2608 aPaintStart
.setY( aUpperAligned
.Bottom_() );
2610 if (aEnd
.X() == aUpper
.Left())
2611 aPaintEnd
.setX( aUpperAligned
.Left() );
2612 else if (aEnd
.X() == aUpper
.Right_())
2613 aPaintEnd
.setX( aUpperAligned
.Right_() );
2614 if (aEnd
.Y() == aUpper
.Top())
2615 aPaintEnd
.setY( aUpperAligned
.Top() );
2616 else if (aEnd
.Y() == aUpper
.Bottom_())
2617 aPaintEnd
.setY( aUpperAligned
.Bottom_() );
2620 if(aStyles
[0].IsUsed())
2624 const basegfx::B2DPoint
aOrigin(aPaintStart
.X(), aPaintStart
.Y());
2625 const basegfx::B2DVector
aX(basegfx::B2DPoint(aPaintEnd
.X(), aPaintEnd
.Y()) - aOrigin
);
2629 const basegfx::B2DVector
aY(basegfx::getNormalizedPerpendicular(aX
));
2635 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
2637 rInstance
.addSdrConnectStyleData(true, aStyles
[1], -aY
, true); // aLFromT
2638 rInstance
.addSdrConnectStyleData(true, aStyles
[2], -aX
, true); // aLFromL
2639 rInstance
.addSdrConnectStyleData(true, aStyles
[3], aY
, false); // aLFromB
2641 rInstance
.addSdrConnectStyleData(false, aStyles
[4], -aY
, true); // aRFromT
2642 rInstance
.addSdrConnectStyleData(false, aStyles
[5], aX
, false); // aRFromR
2643 rInstance
.addSdrConnectStyleData(false, aStyles
[6], aY
, false); // aRFromB
2648 const basegfx::B2DPoint
aOrigin(aPaintStart
.X(), aPaintStart
.Y());
2649 const basegfx::B2DVector
aX(basegfx::B2DPoint(aPaintEnd
.X(), aPaintEnd
.Y()) - aOrigin
);
2653 const basegfx::B2DVector
aY(basegfx::getNormalizedPerpendicular(aX
));
2659 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
2661 rInstance
.addSdrConnectStyleData(true, aStyles
[3], -aY
, false); // aTFromR
2662 rInstance
.addSdrConnectStyleData(true, aStyles
[2], -aX
, true); // aTFromT
2663 rInstance
.addSdrConnectStyleData(true, aStyles
[1], aY
, true); // aTFromL
2665 rInstance
.addSdrConnectStyleData(false, aStyles
[6], -aY
, false); // aBFromR
2666 rInstance
.addSdrConnectStyleData(false, aStyles
[5], aX
, false); // aBFromB
2667 rInstance
.addSdrConnectStyleData(false, aStyles
[4], aY
, true); // aBFromL
2675 // create instance of SdrFrameBorderPrimitive2D if
2676 // SdrFrameBorderDataVector is used
2679 drawinglayer::primitive2d::Primitive2DContainer aSequence
;
2681 drawinglayer::primitive2d::Primitive2DReference(
2682 new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
2684 true))); // force visualization to minimal one discrete unit (pixel)
2686 mrTabFrame
.ProcessPrimitives(aSequence
);
2689 // restore output device:
2690 rDev
.SetDrawMode( nOldDrawMode
);
2694 * Finds the lines that join the line defined by (StartPoint, EndPoint) in either
2695 * StartPoint or Endpoint. The styles of these lines are required for DR's magic
2696 * line painting functions
2698 void SwTabFramePainter::FindStylesForLine( Point
& rStartPoint
,
2700 svx::frame::Style
* pStyles
,
2701 bool bHori
, bool bOuter
) const
2703 // For example, aLFromB means: this vertical line intersects my horizontal line at its left end,
2705 // pStyles[ 1 ] = bHori ? aLFromT : TFromL
2706 // pStyles[ 2 ] = bHori ? aLFromL : TFromT,
2707 // pStyles[ 3 ] = bHori ? aLFromB : TFromR,
2708 // pStyles[ 4 ] = bHori ? aRFromT : BFromL,
2709 // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
2710 // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
2712 bool bWordTableCell
= false;
2713 SwViewShell
* pShell
= mrTabFrame
.getRootFrame()->GetCurrShell();
2716 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
2717 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
2720 SwLineEntryMap::const_iterator aMapIter
= maVertLines
.find( rStartPoint
.X() );
2721 OSL_ENSURE( aMapIter
!= maVertLines
.end(), "FindStylesForLine: Error" );
2722 const SwLineEntrySet
& rVertSet
= (*aMapIter
).second
;
2724 for ( const SwLineEntry
& rEntry
: rVertSet
)
2728 if ( rStartPoint
.Y() == rEntry
.mnStartPos
)
2729 pStyles
[ 3 ] = rEntry
.maAttribute
;
2730 else if ( rStartPoint
.Y() == rEntry
.mnEndPos
)
2731 pStyles
[ 1 ] = rEntry
.maAttribute
;
2733 if (bWordTableCell
&& rStartPoint
.X() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2735 rStartPoint
.AdjustX(rEntry
.maAttribute
.GetWidth());
2740 if ( rStartPoint
.Y() == rEntry
.mnEndPos
)
2741 pStyles
[ 2 ] = rEntry
.maAttribute
;
2742 else if ( rEndPoint
.Y() == rEntry
.mnStartPos
)
2743 pStyles
[ 5 ] = rEntry
.maAttribute
;
2747 aMapIter
= maHoriLines
.find( rStartPoint
.Y() );
2748 OSL_ENSURE( aMapIter
!= maHoriLines
.end(), "FindStylesForLine: Error" );
2749 const SwLineEntrySet
& rHoriSet
= (*aMapIter
).second
;
2751 for ( const SwLineEntry
& rEntry
: rHoriSet
)
2755 if ( rStartPoint
.X() == rEntry
.mnEndPos
)
2756 pStyles
[ 2 ] = rEntry
.maAttribute
;
2757 else if ( rEndPoint
.X() == rEntry
.mnStartPos
)
2758 pStyles
[ 5 ] = rEntry
.maAttribute
;
2762 if ( rStartPoint
.X() == rEntry
.mnEndPos
)
2763 pStyles
[ 1 ] = rEntry
.maAttribute
;
2764 else if ( rStartPoint
.X() == rEntry
.mnStartPos
)
2765 pStyles
[ 3 ] = rEntry
.maAttribute
;
2767 if (bWordTableCell
&& rStartPoint
.Y() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2769 rStartPoint
.AdjustY(rEntry
.maAttribute
.GetWidth());
2776 aMapIter
= maVertLines
.find( rEndPoint
.X() );
2777 OSL_ENSURE( aMapIter
!= maVertLines
.end(), "FindStylesForLine: Error" );
2778 const SwLineEntrySet
& rVertSet2
= (*aMapIter
).second
;
2780 for ( const SwLineEntry
& rEntry
: rVertSet2
)
2782 if ( rEndPoint
.Y() == rEntry
.mnStartPos
)
2783 pStyles
[ 6 ] = rEntry
.maAttribute
;
2784 else if ( rEndPoint
.Y() == rEntry
.mnEndPos
)
2785 pStyles
[ 4 ] = rEntry
.maAttribute
;
2787 if (bWordTableCell
&& rEndPoint
.X() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2789 rEndPoint
.AdjustX(-rEntry
.maAttribute
.GetWidth());
2795 aMapIter
= maHoriLines
.find( rEndPoint
.Y() );
2796 OSL_ENSURE( aMapIter
!= maHoriLines
.end(), "FindStylesForLine: Error" );
2797 const SwLineEntrySet
& rHoriSet2
= (*aMapIter
).second
;
2799 for ( const SwLineEntry
& rEntry
: rHoriSet2
)
2801 if ( rEndPoint
.X() == rEntry
.mnEndPos
)
2802 pStyles
[ 4 ] = rEntry
.maAttribute
;
2803 else if ( rEndPoint
.X() == rEntry
.mnStartPos
)
2804 pStyles
[ 6 ] = rEntry
.maAttribute
;
2806 if (bWordTableCell
&& rEndPoint
.Y() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2808 rEndPoint
.AdjustY(-rEntry
.maAttribute
.GetWidth());
2815 * Special case: #i9860#
2816 * first line in follow table without repeated headlines
2817 * Special case: tdf#150308
2818 * first visible line of a table with preceding hidden deleted rows
2820 static bool lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
2821 SwTabFrame
const& rTabFrame
, SwFrame
const& rFrame
, SvxBoxItem
const& rBoxItem
)
2823 SwRowFrame
const*const pThisRowFrame
=
2824 dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2825 return (pThisRowFrame
2826 && (pThisRowFrame
->GetUpper() == &rTabFrame
)
2827 && ( rTabFrame
.IsFollow()
2828 // tdf#150308 first table row isn't equal to the table row of the first
2829 // row frame of the first table frame: there are invisible deleted rows
2830 // in Hide Changes mode before the first visible table row
2831 || rTabFrame
.GetTable()->GetTabLines().front() != pThisRowFrame
->GetTabLine() )
2832 && !rTabFrame
.GetTable()->GetRowsToRepeat()
2833 && ( !pThisRowFrame
->GetPrev()
2834 || static_cast<const SwRowFrame
*>(pThisRowFrame
->GetPrev())
2836 && !rBoxItem
.GetTop()
2837 && rBoxItem
.GetBottom());
2842 * last visible cell of a table row followed with a hidden deleted cell,
2843 * and the right border of the visible cell was painted by its left border
2845 static bool lcl_IsLastVisibleCellBeforeHiddenCellAtTheEndOfRow(
2846 SwFrame
const& rFrame
, SvxBoxItem
const& rBoxItem
)
2848 SwRowFrame
const*const pThisRowFrame
=
2849 dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2850 const SwCellFrame
* pThisCell
= static_cast<const SwCellFrame
*>(&rFrame
);
2852 return pThisRowFrame
2853 // last visible cell
2854 && !rFrame
.GetNext()
2855 // it has only left border
2856 && !rBoxItem
.GetRight()
2857 && rBoxItem
.GetLeft()
2858 // last visible table cell isn't equal to the last cell:
2859 // there are invisible deleted cells in Hide Changes mode
2860 && pThisRowFrame
->GetTabLine()->GetTabBoxes().back() != pThisCell
->GetTabBox();
2863 void SwTabFramePainter::InsertFollowTopBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2864 bool bWordTableCell
, SwTwips nTop
, SwTwips nLeft
,
2865 SwTwips nRight
, bool bTopIsOuter
)
2867 // Figure out which cell to copy.
2869 const SwFrame
* pCell
= &rFrame
;
2872 if (!pCell
->GetPrev())
2878 pCell
= pCell
->GetPrev();
2881 auto pThisRow
= dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2882 if (!pThisRow
|| pThisRow
->GetUpper() != &mrTabFrame
)
2887 if (!mrTabFrame
.IsFollow() || mrTabFrame
.GetTable()->GetRowsToRepeat())
2892 if (pThisRow
->GetPrev() || rBoxItem
.GetTop() || rBoxItem
.GetBottom())
2897 // This is then a first row in a follow table, without repeated headlines.
2898 auto pLastRow
= dynamic_cast<const SwRowFrame
*>(mrTabFrame
.GetLastLower());
2899 if (!pLastRow
|| pLastRow
== pThisRow
)
2904 const SwFrame
* pLastCell
= pLastRow
->GetLower();
2905 for (int i
= 0; i
< nCol
; ++i
)
2912 pLastCell
= pLastCell
->GetNext();
2919 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pLastCell
);
2920 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2921 const SvxBoxItem
& rLastBoxItem
= rAttrs
.GetBox();
2922 if (!rLastBoxItem
.GetBottom())
2927 // The matching (same column) row in the last row has a bottom border for us.
2928 svx::frame::Style
aFollowB(rLastBoxItem
.GetBottom(), 1.0);
2929 aFollowB
.SetWordTableCell(bWordTableCell
);
2930 SwLineEntry
aFollowTop(nTop
, nLeft
, nRight
, bTopIsOuter
, aFollowB
);
2931 aFollowB
.SetRefMode(svx::frame::RefMode::Begin
);
2932 Insert(aFollowTop
, true);
2935 void SwTabFramePainter::InsertMasterBottomBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2936 bool bWordTableCell
, SwTwips nBottom
, SwTwips nLeft
,
2937 SwTwips nRight
, bool bBottomIsOuter
)
2939 // Figure out which cell to copy.
2941 const SwFrame
* pCell
= &rFrame
;
2944 if (!pCell
->GetPrev())
2950 pCell
= pCell
->GetPrev();
2953 auto pThisRow
= dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2954 if (!pThisRow
|| pThisRow
->GetUpper() != &mrTabFrame
)
2959 if (mrTabFrame
.IsFollow() || !mrTabFrame
.GetFollow())
2964 // This is a master table that is split.
2965 if (pThisRow
->GetNext() || rBoxItem
.GetTop() || rBoxItem
.GetBottom())
2970 // This is then a last row in a master table.
2971 auto pFirstRow
= dynamic_cast<const SwRowFrame
*>(mrTabFrame
.GetLower());
2972 if (!pFirstRow
|| pFirstRow
== pThisRow
)
2977 const SwFrame
* pFirstCell
= pFirstRow
->GetLower();
2978 for (int i
= 0; i
< nCol
; ++i
)
2985 pFirstCell
= pFirstCell
->GetNext();
2992 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pFirstCell
);
2993 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2994 const SvxBoxItem
& rFirstBoxItem
= rAttrs
.GetBox();
2995 if (!rFirstBoxItem
.GetTop())
3000 // The matching (same column) row in the first row has a top border for us.
3001 svx::frame::Style
aMasterT(rFirstBoxItem
.GetTop(), 1.0);
3002 aMasterT
.SetWordTableCell(bWordTableCell
);
3003 SwLineEntry
aMasterBottom(nBottom
, nLeft
, nRight
, bBottomIsOuter
, aMasterT
);
3004 aMasterT
.SetRefMode(svx::frame::RefMode::Begin
);
3005 Insert(aMasterBottom
, true);
3008 void SwTabFramePainter::Insert(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
, const SwRect
& rPaintArea
)
3010 // build 4 line entries for the 4 borders:
3011 SwRect aBorderRect
= rFrame
.getFrameArea();
3013 aBorderRect
.Intersection(rPaintArea
);
3015 bool const bBottomAsTop(lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
3016 mrTabFrame
, rFrame
, rBoxItem
));
3017 bool const bLeftAsRight(lcl_IsLastVisibleCellBeforeHiddenCellAtTheEndOfRow(
3020 bool const bVert
= mrTabFrame
.IsVertical();
3021 bool const bR2L
= mrTabFrame
.IsRightToLeft();
3023 bool bWordTableCell
= false;
3024 SwViewShell
* pShell
= rFrame
.getRootFrame()->GetCurrShell();
3027 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
3028 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
3031 // no scaling needed, it's all in the primitives and the target device
3032 svx::frame::Style
aL(rBoxItem
.GetLeft(), 1.0);
3033 aL
.SetWordTableCell(bWordTableCell
);
3034 svx::frame::Style
aR(rBoxItem
.GetRight(), 1.0);
3035 aR
.SetWordTableCell(bWordTableCell
);
3036 svx::frame::Style
aT(rBoxItem
.GetTop(), 1.0);
3037 aT
.SetWordTableCell(bWordTableCell
);
3038 svx::frame::Style
aB(rBoxItem
.GetBottom(), 1.0);
3039 aB
.SetWordTableCell(bWordTableCell
);
3041 // First cell in a row.
3042 bool bLeftIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetLower() == &rFrame
;
3043 // Last cell in a row.
3044 bool bRightIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetNext() == nullptr;
3045 // First row in a table.
3046 bool bTopIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetUpper()->GetLower() == rFrame
.GetUpper();
3047 // Last row in a table.
3048 bool bBottomIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetNext() == nullptr;
3051 if (!bWordTableCell
|| !bBottomIsOuter
)
3053 // Outer horizontal lines are never mirrored in Word.
3057 const SwTwips nLeft
= aBorderRect
.Left_();
3058 const SwTwips nRight
= aBorderRect
.Right_();
3059 const SwTwips nTop
= aBorderRect
.Top_();
3060 const SwTwips nBottom
= aBorderRect
.Bottom_();
3062 aL
.SetRefMode( svx::frame::RefMode::Centered
);
3063 aR
.SetRefMode( svx::frame::RefMode::Centered
);
3064 aT
.SetRefMode( !bVert
? svx::frame::RefMode::Begin
: svx::frame::RefMode::End
);
3065 aB
.SetRefMode( !bVert
? svx::frame::RefMode::Begin
: svx::frame::RefMode::End
);
3067 if (bWordTableCell
&& bLeftIsOuter
)
3069 // Outer vertical lines are always mirrored in Word.
3073 SwLineEntry
aLeft (nLeft
, nTop
, nBottom
, bLeftIsOuter
,
3074 bVert
? aB
: (bR2L
? aR
: aL
));
3075 if (bWordTableCell
&& rBoxItem
.GetLeft())
3077 aLeft
.LimitVerticalEndPos(rFrame
, SwLineEntry::VerticalType::LEFT
);
3080 SwLineEntry
aRight (nRight
, nTop
, nBottom
, bRightIsOuter
,
3081 bVert
? (bBottomAsTop
? aB
: aT
) : ((bR2L
|| bLeftAsRight
) ? aL
: aR
));
3082 if (bWordTableCell
&& rBoxItem
.GetRight())
3084 aRight
.LimitVerticalEndPos(rFrame
, SwLineEntry::VerticalType::RIGHT
);
3087 SwLineEntry
aTop (nTop
, nLeft
, nRight
, bTopIsOuter
,
3088 bVert
? aL
: (bBottomAsTop
? aB
: aT
));
3090 SwLineEntry
aBottom(nBottom
, nLeft
, nRight
, bBottomIsOuter
,
3093 Insert( aLeft
, false );
3094 Insert( aRight
, false );
3095 Insert( aTop
, true );
3096 Insert( aBottom
, true );
3098 InsertMasterBottomBorder(rFrame
, rBoxItem
, bWordTableCell
, nBottom
, nLeft
, nRight
,
3100 InsertFollowTopBorder(rFrame
, rBoxItem
, bWordTableCell
, nTop
, nLeft
, nRight
, bTopIsOuter
);
3103 void SwTabFramePainter::Insert( SwLineEntry
& rNew
, bool bHori
)
3105 // get all lines from structure, that have key entry of pLE
3106 SwLineEntryMap
* pLine2
= bHori
? &maHoriLines
: &maVertLines
;
3107 const SwTwips nKey
= rNew
.mnKey
;
3108 SwLineEntryMap::iterator aMapIter
= pLine2
->find( nKey
);
3110 SwLineEntrySet
* pLineSet
= aMapIter
!= pLine2
->end() ? &((*aMapIter
).second
) : nullptr;
3113 SwLineEntrySet aNewSet
;
3114 (*pLine2
)[ nKey
] = aNewSet
;
3115 pLineSet
= &(*pLine2
)[ nKey
];
3117 SwLineEntrySet::iterator aIter
= pLineSet
->begin();
3119 bool bWordTableCell
= false;
3120 SwViewShell
* pShell
= mrTabFrame
.getRootFrame()->GetCurrShell();
3123 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
3124 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
3126 bool bR2L
= mrTabFrame
.IsRightToLeft();
3127 while ( aIter
!= pLineSet
->end() && rNew
.mnStartPos
< rNew
.mnEndPos
)
3129 const SwLineEntry
& rOld
= *aIter
;
3131 // The bWordTableCell code only works for LTR at the moment, avoid it for RTL.
3132 if (rOld
.mnLimitedEndPos
|| (bWordTableCell
&& (rOld
.mbOuter
!= rNew
.mbOuter
) && !bR2L
))
3134 // Don't merge with this line entry as it ends sooner than mnEndPos.
3139 const SwLineEntry::OverlapType nOverlapType
= rOld
.Overlaps( rNew
);
3141 const svx::frame::Style
& rOldAttr
= rOld
.maAttribute
;
3142 const svx::frame::Style
& rNewAttr
= rNew
.maAttribute
;
3143 const svx::frame::Style
& rCmpAttr
= std::max(rNewAttr
, rOldAttr
);
3145 if ( SwLineEntry::OVERLAP1
== nOverlapType
)
3147 OSL_ENSURE( rNew
.mnStartPos
>= rOld
.mnStartPos
, "Overlap type 3? How this?" );
3150 const SwLineEntry
aLeft(nKey
, rOld
.mnStartPos
, rNew
.mnStartPos
, rOld
.mbOuter
, rOldAttr
);
3152 // new middle segment
3153 const SwLineEntry
aMiddle(nKey
, rNew
.mnStartPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3155 // new right segment
3156 rNew
.mnStartPos
= rOld
.mnEndPos
;
3158 // update current lines set
3159 pLineSet
->erase( aIter
);
3160 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3161 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3163 aIter
= pLineSet
->begin();
3165 continue; // start over
3167 else if ( SwLineEntry::OVERLAP2
== nOverlapType
)
3170 const SwLineEntry
aLeft(nKey
, rOld
.mnStartPos
, rNew
.mnStartPos
, rOld
.mbOuter
, rOldAttr
);
3172 // new middle segment
3173 const SwLineEntry
aMiddle(nKey
, rNew
.mnStartPos
, rNew
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3175 // new right segment
3176 const SwLineEntry
aRight(nKey
, rNew
.mnEndPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rOldAttr
);
3178 // update current lines set
3179 pLineSet
->erase( aIter
);
3180 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3181 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3182 if ( aRight
.mnStartPos
< aRight
.mnEndPos
) pLineSet
->insert( aRight
);
3184 rNew
.mnStartPos
= rNew
.mnEndPos
; // rNew should not be inserted!
3186 break; // we are finished
3188 else if ( SwLineEntry::OVERLAP3
== nOverlapType
)
3191 const SwLineEntry
aLeft(nKey
, rNew
.mnStartPos
, rOld
.mnStartPos
, rOld
.mbOuter
, rNewAttr
);
3193 // new middle segment
3194 const SwLineEntry
aMiddle(nKey
, rOld
.mnStartPos
, rNew
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3196 // new right segment
3197 const SwLineEntry
aRight(nKey
, rNew
.mnEndPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rOldAttr
);
3199 // update current lines set
3200 pLineSet
->erase( aIter
);
3201 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3202 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3203 if ( aRight
.mnStartPos
< aRight
.mnEndPos
) pLineSet
->insert( aRight
);
3205 rNew
.mnStartPos
= rNew
.mnEndPos
; // rNew should not be inserted!
3207 break; // we are finished
3213 if ( rNew
.mnStartPos
< rNew
.mnEndPos
) // insert rest
3214 pLineSet
->insert( rNew
);
3218 * FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES END
3223 class SwViewObjectContactRedirector
: public sdr::contact::ViewObjectContactRedirector
3226 const SwViewShell
& mrViewShell
;
3229 explicit SwViewObjectContactRedirector( const SwViewShell
& rSh
)
3230 : mrViewShell( rSh
)
3233 virtual void createRedirectedPrimitive2DSequence(
3234 const sdr::contact::ViewObjectContact
& rOriginal
,
3235 const sdr::contact::DisplayInfo
& rDisplayInfo
,
3236 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) override
3238 bool bPaint( true );
3240 SdrObject
* pObj
= rOriginal
.GetViewContact().TryToGetSdrObject();
3243 bPaint
= SwFlyFrame::IsPaint( pObj
, &mrViewShell
);
3251 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
3252 rOriginal
, rDisplayInfo
, rVisitor
);
3256 } // end of anonymous namespace
3260 * Paint once for every visible page which is touched by Rect
3262 * 1. Paint borders and backgrounds
3263 * 2. Paint the draw layer (frames and drawing objects) that is
3264 * below the document (hell)
3265 * 3. Paint the document content (text)
3266 * 4. Paint the draw layer that is above the document
3268 void SwRootFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const pPrintData
) const
3270 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." );
3272 PROTOCOL( this, PROT::FileInit
, DbgAction::NONE
, nullptr)
3274 bool bResetRootPaint
= false;
3275 SwViewShell
*pSh
= mpCurrShell
;
3277 if ( pSh
->GetWin() )
3279 if ( pSh
->GetOut() == pSh
->GetWin()->GetOutDev() && !pSh
->GetWin()->IsVisible() )
3283 if (SwRootFrame::s_isInPaint
)
3285 SwPaintQueue::Add( pSh
, rRect
);
3290 SwRootFrame::s_isInPaint
= bResetRootPaint
= true;
3292 std::unique_ptr
<SwSavePaintStatics
> pStatics
;
3293 if ( gProp
.pSGlobalShell
)
3294 pStatics
.reset(new SwSavePaintStatics());
3295 gProp
.pSGlobalShell
= pSh
;
3297 if( !pSh
->GetWin() )
3298 gProp
.pSProgress
= SfxProgress::GetActiveProgress( static_cast<SfxObjectShell
*>(pSh
->GetDoc()->GetDocShell()) );
3300 ::SwCalcPixStatics( pSh
->GetOut() );
3301 aGlobalRetoucheColor
= pSh
->Imp()->GetRetoucheColor();
3303 // Copy rRect; for one, rRect could become dangling during the below action, and for another it
3304 // needs to be copied to aRect anyway as that is modified further down below:
3305 SwRect
aRect( rRect
);
3307 //Trigger an action to clear things up if needed.
3308 //Using this trick we can ensure that all values are valid in all paints -
3309 //no problems, no special case(s).
3311 // Extend check on certain states of the 'current' <SwViewShell> instance to
3312 // all existing <SwViewShell> instances.
3313 bool bPerformLayoutAction( true );
3315 for(SwViewShell
& rTmpViewShell
: pSh
->GetRingContainer())
3317 if ( rTmpViewShell
.IsInEndAction() ||
3318 rTmpViewShell
.IsPaintInProgress() ||
3319 ( rTmpViewShell
.Imp()->IsAction() &&
3320 rTmpViewShell
.Imp()->GetLayAction().IsActionInProgress() ) )
3322 bPerformLayoutAction
= false;
3325 if(!bPerformLayoutAction
)
3329 if ( bPerformLayoutAction
)
3331 const_cast<SwRootFrame
*>(this)->ResetTurbo();
3332 SwLayAction
aAction( const_cast<SwRootFrame
*>(this), pSh
->Imp() );
3333 aAction
.SetPaint( false );
3334 aAction
.SetComplete( false );
3335 aAction
.SetReschedule( gProp
.pSProgress
!= nullptr );
3336 aAction
.Action(&rRenderContext
);
3338 if ( !pSh
->ActionPend() )
3339 pSh
->Imp()->DeletePaintRegion();
3342 aRect
.Intersection( pSh
->VisArea() );
3344 const bool bExtraData
= ::IsExtraData( GetFormat()->GetDoc() );
3346 gProp
.pSLines
.reset(new SwLineRects
); // Container for borders.
3348 // #104289#. During painting, something (OLE) can
3349 // load the linguistic, which in turn can cause a reformat
3350 // of the document. Dangerous! We better set this flag to
3351 // avoid the reformat.
3352 const bool bOldAction
= IsCallbackActionEnabled();
3353 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( false );
3355 const SwPageFrame
*pPage
= pSh
->Imp()->GetFirstVisPage(&rRenderContext
);
3357 // #126222. The positions of headers and footers of the previous
3358 // pages have to be updated, else these headers and footers could
3359 // get visible at a wrong position.
3360 const SwPageFrame
*pPageDeco
= static_cast<const SwPageFrame
*>(pPage
->GetPrev());
3363 pPageDeco
->PaintDecorators();
3364 OSL_ENSURE(!pPageDeco
->GetPrev() || pPageDeco
->GetPrev()->IsPageFrame(),
3365 "Neighbour of page is not a page.");
3366 pPageDeco
= static_cast<const SwPageFrame
*>(pPageDeco
->GetPrev());
3369 const bool bBookMode
= gProp
.pSGlobalShell
->GetViewOptions()->IsViewLayoutBookMode();
3370 if ( bBookMode
&& pPage
->GetPrev() && static_cast<const SwPageFrame
*>(pPage
->GetPrev())->IsEmptyPage() )
3371 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetPrev());
3374 const bool bGridPainting(pSh
->GetWin() && pSh
->Imp()->HasDrawView() && pSh
->Imp()->GetDrawView()->IsGridVisible());
3376 // Hide all page break controls before showing them again
3377 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
3380 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
3381 SwFrameControlsManager
& rMngr
= rEditWin
.GetFrameControlsManager();
3382 const SwPageFrame
* pHiddenPage
= pPage
;
3383 while ( pHiddenPage
->GetPrev() != nullptr )
3385 pHiddenPage
= static_cast< const SwPageFrame
* >( pHiddenPage
->GetPrev() );
3386 SwFrameControlPtr pControl
= rMngr
.GetControl( FrameControlType::PageBreak
, pHiddenPage
);
3388 pControl
->ShowAll( false );
3393 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
3397 const bool bPaintRightShadow
= pPage
->IsRightShadowNeeded();
3398 const bool bPaintLeftShadow
= pPage
->IsLeftShadowNeeded();
3399 const bool bRightSidebar
= pPage
->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT
;
3401 if ( !pPage
->IsEmptyPage() )
3404 SwPageFrame::GetBorderAndShadowBoundRect( pPage
->getFrameArea(), pSh
, &rRenderContext
, aPaintRect
,
3405 bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3407 if ( aRect
.Overlaps( aPaintRect
) )
3409 if ( pSh
->GetWin() )
3411 gProp
.pSSubsLines
.reset(new SwSubsRects
);
3412 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
3414 gProp
.pBLines
.reset(new BorderLines
);
3416 aPaintRect
.Intersection_( aRect
);
3419 pSh
->GetWin() && pSh
->IsInEndAction() )
3421 // enlarge paint rectangle to complete page width, subtract
3422 // current paint area and invalidate the resulting region.
3423 SwRectFnSet
aRectFnSet(pPage
);
3424 SwRect
aPageRectTemp( aPaintRect
);
3425 aRectFnSet
.SetLeftAndWidth( aPageRectTemp
,
3426 aRectFnSet
.GetLeft(pPage
->getFrameArea()),
3427 aRectFnSet
.GetWidth(pPage
->getFrameArea()) );
3428 aPageRectTemp
.Intersection_( pSh
->VisArea() );
3429 vcl::Region
aPageRectRegion( aPageRectTemp
.SVRect() );
3430 aPageRectRegion
.Exclude( aPaintRect
.SVRect() );
3431 pSh
->GetWin()->Invalidate( aPageRectRegion
, InvalidateFlags::Children
);
3435 // enlarge paint rectangle for objects overlapping the same pixel
3436 // in all cases and before the DrawingLayer overlay is initialized.
3437 lcl_AdjustRectToPixelSize( aPaintRect
, *(pSh
->GetOut()) );
3440 // moved paint pre-process for DrawingLayer overlay here since the above
3441 // code dependent from bExtraData may expand the PaintRect
3443 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3444 // really be used but handled by SwViewShell::ImplEndAction already
3445 const vcl::Region
aDLRegion(aPaintRect
.SVRect());
3446 pSh
->DLPrePaint2(aDLRegion
);
3449 if(OUTDEV_WINDOW
== gProp
.pSGlobalShell
->GetOut()->GetOutDevType())
3451 // changed method SwLayVout::Enter(..)
3452 // 2nd parameter is no longer <const> and will be set to the
3453 // rectangle the virtual output device is calculated from <aPaintRect>,
3454 // if the virtual output is used.
3455 s_pVout
->Enter(pSh
, aPaintRect
, !s_isNoVirDev
);
3457 // Adjust paint rectangle to pixel size
3458 // Thus, all objects overlapping on pixel level with the unadjusted
3459 // paint rectangle will be considered in the paint.
3460 lcl_AdjustRectToPixelSize( aPaintRect
, *(pSh
->GetOut()) );
3463 // maybe this can be put in the above scope. Since we are not sure, just leave it ATM
3464 s_pVout
->SetOrgRect( aPaintRect
);
3466 // determine background color of page for <PaintLayer> method
3467 // calls, paint <hell> or <heaven>
3468 const Color
aPageBackgrdColor(pPage
->GetDrawBackgroundColor());
3470 pPage
->PaintBaBo( aPaintRect
, pPage
);
3472 if ( pSh
->Imp()->HasDrawView() )
3474 gProp
.pSLines
->LockLines( true );
3475 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
3476 pSh
->Imp()->PaintLayer( rIDDMA
.GetHellId(),
3478 *pPage
, pPage
->getFrameArea(),
3480 pPage
->IsRightToLeft(),
3482 gProp
.pSLines
->PaintLines( pSh
->GetOut(), gProp
);
3483 gProp
.pSLines
->LockLines( false );
3486 if ( pSh
->GetDoc()->GetDocumentSettingManager().get( DocumentSettingId::BACKGROUND_PARA_OVER_DRAWINGS
) )
3487 pPage
->PaintBaBo( aPaintRect
, pPage
, /*bOnlyTextBackground=*/true );
3491 // collect sub-lines
3492 pPage
->RefreshSubsidiary( aPaintRect
);
3493 // paint special sub-lines
3494 gProp
.pSSpecSubsLines
->PaintSubsidiary( pSh
->GetOut(), nullptr, gProp
);
3497 pPage
->PaintSwFrame( rRenderContext
, aPaintRect
);
3499 // no paint of page border and shadow, if writer is in place mode.
3500 if( pSh
->GetWin() && pSh
->GetDoc()->GetDocShell() &&
3501 !pSh
->GetDoc()->GetDocShell()->IsInPlaceActive() )
3503 SwPageFrame::PaintBorderAndShadow( pPage
->getFrameArea(), pSh
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3504 SwPageFrame::PaintNotesSidebar( pPage
->getFrameArea(), pSh
, pPage
->GetPhyPageNum(), bRightSidebar
);
3507 gProp
.pSLines
->PaintLines( pSh
->GetOut(), gProp
);
3508 if ( pSh
->GetWin() )
3510 gProp
.pSSubsLines
->PaintSubsidiary( pSh
->GetOut(), gProp
.pSLines
.get(), gProp
);
3511 gProp
.pSSubsLines
.reset();
3512 gProp
.pSSpecSubsLines
.reset();
3514 // fdo#42750: delay painting these until after subsidiary lines
3515 // fdo#45562: delay painting these until after hell layer
3516 // fdo#47717: but do it before heaven layer
3518 SwTaggedPDFHelper
tag(nullptr, nullptr, nullptr, rRenderContext
);
3519 ProcessPrimitives(gProp
.pBLines
->GetBorderLines_Clear());
3522 if ( pSh
->Imp()->HasDrawView() )
3524 pSh
->Imp()->PaintLayer( pSh
->GetDoc()->getIDocumentDrawModelAccess().GetHeavenId(),
3526 *pPage
, pPage
->getFrameArea(),
3528 pPage
->IsRightToLeft(),
3533 pPage
->RefreshExtraData( aPaintRect
);
3535 gProp
.pBLines
.reset();
3539 // needed to move grid painting inside Begin/EndDrawLayer bounds and to change
3540 // output rect for it accordingly
3543 SdrPaintView
* pPaintView
= pSh
->Imp()->GetDrawView();
3544 SdrPageView
* pPageView
= pPaintView
->GetSdrPageView();
3545 pPageView
->DrawPageViewGrid(*pSh
->GetOut(), aPaintRect
.SVRect(), pSh
->GetViewOptions()->GetTextGridColor() );
3549 // moved paint post-process for DrawingLayer overlay here, see above
3551 pSh
->DLPostPaint2(true);
3555 pPage
->PaintDecorators( );
3556 pPage
->PaintBreak();
3558 else if ( bBookMode
&& pSh
->GetWin() && !pSh
->GetDoc()->GetDocShell()->IsInPlaceActive() )
3562 SwRect
aEmptyPageRect( pPage
->getFrameArea() );
3564 // code from vprint.cxx
3565 const SwPageFrame
& rFormatPage
= pPage
->GetFormatPage();
3566 aEmptyPageRect
.SSize( rFormatPage
.getFrameArea().SSize() );
3568 SwPageFrame::GetBorderAndShadowBoundRect( aEmptyPageRect
, pSh
, &rRenderContext
, aPaintRect
,
3569 bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3570 aPaintRect
.Intersection_( aRect
);
3572 if ( aRect
.Overlaps( aEmptyPageRect
) )
3574 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3575 // really be used but handled by SwViewShell::ImplEndAction already
3577 const vcl::Region
aDLRegion(aPaintRect
.SVRect());
3578 pSh
->DLPrePaint2(aDLRegion
);
3581 if( pSh
->GetOut()->GetFillColor() != aGlobalRetoucheColor
)
3582 pSh
->GetOut()->SetFillColor( aGlobalRetoucheColor
);
3584 pSh
->GetOut()->SetLineColor();
3585 // Use aligned page rectangle
3587 SwRect
aTmpPageRect( aEmptyPageRect
);
3588 ::SwAlignRect( aTmpPageRect
, pSh
, &rRenderContext
);
3589 aEmptyPageRect
= aTmpPageRect
;
3592 pSh
->GetOut()->DrawRect( aEmptyPageRect
.SVRect() );
3594 // paint empty page text
3595 const vcl::Font
& rEmptyPageFont
= SwPageFrame::GetEmptyPageFont();
3596 const vcl::Font
aOldFont( pSh
->GetOut()->GetFont() );
3598 pSh
->GetOut()->SetFont( rEmptyPageFont
);
3599 pSh
->GetOut()->DrawText( aEmptyPageRect
.SVRect(), SwResId( STR_EMPTYPAGE
),
3600 DrawTextFlags::VCenter
|
3601 DrawTextFlags::Center
|
3602 DrawTextFlags::Clip
);
3604 pSh
->GetOut()->SetFont( aOldFont
);
3605 // paint shadow and border for empty page
3606 SwPageFrame::PaintBorderAndShadow( aEmptyPageRect
, pSh
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3607 SwPageFrame::PaintNotesSidebar( aEmptyPageRect
, pSh
, pPage
->GetPhyPageNum(), bRightSidebar
);
3610 pSh
->DLPostPaint2(true);
3615 OSL_ENSURE( !pPage
->GetNext() || pPage
->GetNext()->IsPageFrame(),
3616 "Neighbour of page is not a page." );
3617 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
3620 gProp
.pSLines
.reset();
3622 if ( bResetRootPaint
)
3623 SwRootFrame::s_isInPaint
= false;
3628 gProp
.pSProgress
= nullptr;
3629 gProp
.pSGlobalShell
= nullptr;
3632 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( bOldAction
);
3635 static void lcl_EmergencyFormatFootnoteCont( SwFootnoteContFrame
*pCont
)
3637 vcl::RenderContext
* pRenderContext
= pCont
->getRootFrame()->GetCurrShell()->GetOut();
3639 //It's possible that the Cont will get destroyed.
3640 SwContentFrame
*pCnt
= pCont
->ContainsContent();
3641 while ( pCnt
&& pCnt
->IsInFootnote() )
3643 pCnt
->Calc(pRenderContext
);
3644 pCnt
= pCnt
->GetNextContentFrame();
3652 SwRectDist m_fnCheck
;
3653 tools::Long m_nLimit
;
3656 SwShortCut( const SwFrame
& rFrame
, const SwRect
& rRect
);
3657 bool Stop(const SwRect
& rRect
) const { return (rRect
.*m_fnCheck
)(m_nLimit
) > 0; }
3662 SwShortCut::SwShortCut( const SwFrame
& rFrame
, const SwRect
& rRect
)
3664 bool bVert
= rFrame
.IsVertical();
3665 bool bR2L
= rFrame
.IsRightToLeft();
3666 if( rFrame
.IsNeighbourFrame() && bVert
== bR2L
)
3670 m_fnCheck
= &SwRect::GetBottomDistance
;
3671 m_nLimit
= rRect
.Top();
3675 m_fnCheck
= &SwRect::GetLeftDistance
;
3676 m_nLimit
= rRect
.Left() + rRect
.Width();
3679 else if( bVert
== rFrame
.IsNeighbourFrame() )
3681 m_fnCheck
= &SwRect::GetTopDistance
;
3682 m_nLimit
= rRect
.Top() + rRect
.Height();
3686 if ( rFrame
.IsVertLR() )
3688 m_fnCheck
= &SwRect::GetLeftDistance
;
3689 m_nLimit
= rRect
.Right();
3693 m_fnCheck
= &SwRect::GetRightDistance
;
3694 m_nLimit
= rRect
.Left();
3699 void SwLayoutFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const) const
3701 // #i16816# tagged pdf support
3702 Frame_Info
aFrameInfo(*this, false);
3703 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, &aFrameInfo
, nullptr, rRenderContext
);
3704 ::std::optional
<SwTaggedPDFHelper
> oTaggedLink
;
3707 // tdf#154939 Link nested inside Figure
3708 auto const pItem(GetFormat()->GetAttrSet().GetItemIfSet(RES_URL
));
3709 if (pItem
&& !pItem
->GetURL().isEmpty())
3711 Frame_Info
linkInfo(*this, true);
3712 oTaggedLink
.emplace(nullptr, &linkInfo
, nullptr, rRenderContext
);
3716 const SwFrame
*pFrame
= Lower();
3720 SwFrameDeleteGuard
g(const_cast<SwLayoutFrame
*>(this)); // lock because Calc() and recursion
3721 SwShortCut
aShortCut( *pFrame
, rRect
);
3722 bool bCnt
= pFrame
->IsContentFrame();
3724 pFrame
->Calc(&rRenderContext
);
3726 if ( pFrame
->IsFootnoteContFrame() )
3728 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pFrame
)) );
3732 const SwPageFrame
*pPage
= nullptr;
3733 bool bWin
= gProp
.pSGlobalShell
->GetWin() != nullptr;
3734 if (comphelper::LibreOfficeKit::isTiledPainting())
3735 // Tiled rendering is similar to printing in this case: painting transparently multiple
3736 // times will result in darker colors: avoid that.
3739 while ( IsAnLower( pFrame
) )
3741 SwRect
aPaintRect( pFrame
->GetPaintArea() );
3742 if( aShortCut
.Stop( aPaintRect
) )
3744 if ( bCnt
&& gProp
.pSProgress
)
3745 SfxProgress::Reschedule();
3747 //We need to retouch if a frame explicitly requests it.
3748 //First do the retouch, because this could flatten the borders.
3749 if ( pFrame
->IsRetouche() )
3751 if ( pFrame
->IsRetoucheFrame() && bWin
&& !pFrame
->GetNext() )
3754 pPage
= FindPageFrame();
3755 pFrame
->Retouch( pPage
, rRect
);
3757 pFrame
->ResetRetouche();
3760 if ( rRect
.Overlaps( aPaintRect
) )
3762 if ( bCnt
&& pFrame
->IsCompletePaint() &&
3763 !rRect
.Contains( aPaintRect
) && Application::AnyInput( VclInputFlags::KEYBOARD
) )
3765 //fix(8104): It may happen, that the processing wasn't complete
3766 //but some parts of the paragraph were still repainted.
3767 //This could lead to the situation, that other parts of the
3768 //paragraph won't be repainted at all. The only solution seems
3769 //to be an invalidation of the window.
3770 //To not make it too severe the rectangle is limited by
3771 //painting the desired part and only invalidating the
3772 //remaining paragraph parts.
3773 if ( aPaintRect
.Left() == rRect
.Left() &&
3774 aPaintRect
.Right() == rRect
.Right() )
3776 aPaintRect
.Bottom( rRect
.Top() - 1 );
3777 if ( aPaintRect
.Height() > 0 )
3778 gProp
.pSGlobalShell
->InvalidateWindows(aPaintRect
);
3779 aPaintRect
.Top( rRect
.Bottom() + 1 );
3780 aPaintRect
.Bottom( pFrame
->getFrameArea().Bottom() );
3781 if ( aPaintRect
.Height() > 0 )
3782 gProp
.pSGlobalShell
->InvalidateWindows(aPaintRect
);
3783 aPaintRect
.Top( pFrame
->getFrameArea().Top() );
3784 aPaintRect
.Bottom( pFrame
->getFrameArea().Bottom() );
3788 gProp
.pSGlobalShell
->InvalidateWindows( aPaintRect
);
3789 pFrame
= pFrame
->GetNext();
3792 bCnt
= pFrame
->IsContentFrame();
3794 pFrame
->Calc(&rRenderContext
);
3799 pFrame
->ResetCompletePaint();
3800 aPaintRect
.Intersection_( rRect
);
3802 pFrame
->PaintSwFrame( rRenderContext
, aPaintRect
);
3804 if ( Lower() && Lower()->IsColumnFrame() )
3806 //Paint the column separator line if needed. The page is
3807 //responsible for the page frame - not the upper.
3808 const SwFrameFormat
*pFormat
= GetUpper() && GetUpper()->IsPageFrame()
3809 ? GetUpper()->GetFormat()
3811 const SwFormatCol
&rCol
= pFormat
->GetCol();
3812 if ( rCol
.GetLineAdj() != COLADJ_NONE
)
3815 pPage
= pFrame
->FindPageFrame();
3817 PaintColLines( aPaintRect
, rCol
, pPage
);
3821 if ( !bCnt
&& pFrame
->GetNext() && pFrame
->GetNext()->IsFootnoteContFrame() )
3822 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pFrame
->GetNext())) );
3824 pFrame
= pFrame
->GetNext();
3828 bCnt
= pFrame
->IsContentFrame();
3830 pFrame
->Calc(&rRenderContext
);
3835 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateDashedIndicatorPrimitive(
3836 const basegfx::B2DPoint
& rStart
, const basegfx::B2DPoint
& rEnd
,
3837 basegfx::BColor aColor
)
3839 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 1 );
3841 std::vector
< double > aStrokePattern
;
3842 basegfx::B2DPolygon aLinePolygon
;
3843 aLinePolygon
.append(rStart
);
3844 aLinePolygon
.append(rEnd
);
3846 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
3847 if ( rSettings
.GetHighContrastMode( ) )
3849 // Only a solid line in high contrast mode
3850 aColor
= rSettings
.GetDialogTextColor().getBColor();
3854 // Get a color for the contrast
3855 basegfx::BColor aHslLine
= basegfx::utils::rgb2hsl( aColor
);
3856 double nLuminance
= aHslLine
.getZ() * 2.5;
3857 if ( nLuminance
== 0 )
3859 else if ( nLuminance
>= 1.0 )
3860 nLuminance
= aHslLine
.getZ() * 0.4;
3861 aHslLine
.setZ( nLuminance
);
3862 const basegfx::BColor aOtherColor
= basegfx::utils::hsl2rgb( aHslLine
);
3864 // Compute the plain line
3866 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
3867 aLinePolygon
, aOtherColor
);
3869 // Dashed line in twips
3870 aStrokePattern
.push_back( 40 );
3871 aStrokePattern
.push_back( 40 );
3876 // Compute the dashed line primitive
3877 aSeq
[ aSeq
.size( ) - 1 ] =
3878 new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D (
3879 basegfx::B2DPolyPolygon( aLinePolygon
),
3880 drawinglayer::attribute::LineAttribute( aColor
),
3881 drawinglayer::attribute::StrokeAttribute( std::move(aStrokePattern
) ) );
3887 void SwPageFrame::PaintBreak( ) const
3889 if ( gProp
.pSGlobalShell
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
3890 gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() ||
3891 gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() ||
3892 gProp
.pSGlobalShell
->IsPreview() )
3895 const SwFrame
* pBodyFrame
= Lower();
3896 while ( pBodyFrame
&& !pBodyFrame
->IsBodyFrame() )
3897 pBodyFrame
= pBodyFrame
->GetNext();
3901 const SwLayoutFrame
* pLayBody
= static_cast< const SwLayoutFrame
* >( pBodyFrame
);
3902 const SwFlowFrame
*pFlowFrame
= pLayBody
->ContainsContent();
3904 // Test if the first node is a table
3905 const SwFrame
* pFirstFrame
= pLayBody
->Lower();
3906 if ( pFirstFrame
&& pFirstFrame
->IsTabFrame() )
3907 pFlowFrame
= static_cast< const SwTabFrame
* >( pFirstFrame
);
3909 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
3912 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
3913 SwFrameControlsManager
& rMngr
= rEditWin
.GetFrameControlsManager();
3915 if ( pFlowFrame
&& pFlowFrame
->IsPageBreak( true ) )
3916 rMngr
.SetPageBreakControl( this );
3918 rMngr
.RemoveControlsByType( FrameControlType::PageBreak
, this );
3921 SwLayoutFrame::PaintBreak( );
3924 void SwColumnFrame::PaintBreak( ) const
3926 if ( gProp
.pSGlobalShell
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
3927 gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() ||
3928 gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() ||
3929 gProp
.pSGlobalShell
->IsPreview() )
3932 const SwFrame
* pBodyFrame
= Lower();
3933 while ( pBodyFrame
&& !pBodyFrame
->IsBodyFrame() )
3934 pBodyFrame
= pBodyFrame
->GetNext();
3939 const SwContentFrame
*pCnt
= static_cast< const SwLayoutFrame
* >( pBodyFrame
)->ContainsContent();
3940 if ( !(pCnt
&& pCnt
->IsColBreak( true )) )
3943 // Paint the break only if:
3944 // * Not in header footer edition, to avoid conflicts with the
3945 // header/footer marker
3946 // * Non-printing characters are shown, as this is more consistent
3947 // with other formatting marks
3948 if ( !(!gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) &&
3949 !gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) &&
3950 gProp
.pSGlobalShell
->GetViewOptions()->IsLineBreak()) )
3953 SwRect
aRect( pCnt
->getFramePrintArea() );
3954 aRect
.Pos() += pCnt
->getFrameArea().Pos();
3957 basegfx::B2DPoint
aStart( double( aRect
.Left() ), aRect
.Top() );
3958 basegfx::B2DPoint
aEnd( double( aRect
.Right() ), aRect
.Top() );
3959 double nWidth
= aRect
.Width();
3960 if ( IsVertical( ) )
3962 aStart
= basegfx::B2DPoint( double( aRect
.Right() ), double( aRect
.Top() ) );
3963 aEnd
= basegfx::B2DPoint( double( aRect
.Right() ), double( aRect
.Bottom() ) );
3964 nWidth
= aRect
.Height();
3967 basegfx::BColor aLineColor
= gProp
.pSGlobalShell
->GetViewOptions()->GetPageBreakColor().getBColor();
3969 drawinglayer::primitive2d::Primitive2DContainer aSeq
=
3970 lcl_CreateDashedIndicatorPrimitive( aStart
, aEnd
, aLineColor
);
3972 // Add the text above
3973 OUString aBreakText
= SwResId(STR_COLUMN_BREAK
);
3975 basegfx::B2DVector aFontSize
;
3976 OutputDevice
* pOut
= gProp
.pSGlobalShell
->GetOut();
3977 vcl::Font aFont
= pOut
->GetSettings().GetStyleSettings().GetToolFont();
3978 aFont
.SetFontHeight( 8 * 20 );
3979 pOut
->SetFont( aFont
);
3980 drawinglayer::attribute::FontAttribute aFontAttr
= drawinglayer::primitive2d::getFontAttributeFromVclFont(
3981 aFontSize
, aFont
, IsRightToLeft(), false );
3983 tools::Rectangle aTextRect
;
3984 pOut
->GetTextBoundRect( aTextRect
, aBreakText
);
3985 tools::Long nTextOff
= ( nWidth
- aTextRect
.GetWidth() ) / 2;
3987 basegfx::B2DHomMatrix
aTextMatrix( basegfx::utils::createScaleTranslateB2DHomMatrix(
3988 aFontSize
.getX(), aFontSize
.getY(),
3989 aRect
.Left() + nTextOff
, aRect
.Top() ) );
3992 aTextMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix (
3993 aFontSize
.getX(), aFontSize
.getY(), 0.0, M_PI_2
,
3994 aRect
.Right(), aRect
.Top() + nTextOff
);
3998 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
4000 aBreakText
, 0, aBreakText
.getLength(),
4001 std::vector
< double >(),
4003 std::move(aFontAttr
),
4007 ProcessPrimitives( aSeq
);
4010 void SwLayoutFrame::PaintBreak( ) const
4012 const SwFrame
* pFrame
= Lower();
4015 if ( pFrame
->IsLayoutFrame() )
4016 static_cast< const SwLayoutFrame
*>( pFrame
)->PaintBreak( );
4017 pFrame
= pFrame
->GetNext();
4021 void SwPageFrame::PaintDecorators( ) const
4023 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
4027 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
4029 const SwLayoutFrame
* pBody
= FindBodyCont();
4033 SwRect
aBodyRect( pBody
->getFrameArea() );
4035 if ( !(gProp
.pSGlobalShell
->GetOut()->GetOutDevType() != OUTDEV_PRINTER
&&
4036 !gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() &&
4037 !gProp
.pSGlobalShell
->IsPreview() &&
4038 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
4039 !gProp
.pSGlobalShell
->GetViewOptions()->getBrowseMode() &&
4040 ( gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) ||
4041 gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) )) )
4044 bool bRtl
= AllSettings::GetLayoutRTL();
4045 const SwRect
& rVisArea
= gProp
.pSGlobalShell
->VisArea();
4046 tools::Long nXOff
= std::min( aBodyRect
.Right(), rVisArea
.Right() );
4048 nXOff
= std::max( aBodyRect
.Left(), rVisArea
.Left() );
4051 if ( gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) )
4053 const SwFrame
* pHeaderFrame
= Lower();
4054 if ( !pHeaderFrame
->IsHeaderFrame() )
4055 pHeaderFrame
= nullptr;
4057 tools::Long nHeaderYOff
= aBodyRect
.Top();
4058 Point nOutputOff
= rEditWin
.LogicToPixel( Point( nXOff
, nHeaderYOff
) );
4059 rEditWin
.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Header
, nOutputOff
);
4063 if ( !gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) )
4066 const SwFrame
* pFootnoteContFrame
= Lower();
4067 while ( pFootnoteContFrame
)
4069 if ( pFootnoteContFrame
->IsFootnoteContFrame() )
4070 aBodyRect
.AddBottom( pFootnoteContFrame
->getFrameArea().Bottom() - aBodyRect
.Bottom() );
4071 pFootnoteContFrame
= pFootnoteContFrame
->GetNext();
4074 tools::Long nFooterYOff
= aBodyRect
.Bottom();
4075 Point nOutputOff
= rEditWin
.LogicToPixel( Point( nXOff
, nFooterYOff
) );
4076 rEditWin
.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Footer
, nOutputOff
);
4080 * For feature #99657#
4083 * determines, if background of fly frame has to be drawn transparent
4084 * declaration found in /core/inc/flyfrm.cxx
4086 * OD 08.10.2002 #103898# - If the background of the fly frame itself is not
4087 * transparent and the background is inherited from its parent/grandparent,
4088 * the background brush, used for drawing, has to be investigated for transparency.
4090 * @return true, if background is transparent drawn
4092 bool SwFlyFrame::IsBackgroundTransparent() const
4094 bool bBackgroundTransparent
= GetFormat()->IsBackgroundTransparent();
4095 if ( !bBackgroundTransparent
&&
4096 GetFormat()->IsBackgroundBrushInherited() )
4098 const SvxBrushItem
* pBackgroundBrush
= nullptr;
4099 std::optional
<Color
> xSectionTOXColor
;
4101 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
4103 if ( GetBackgroundBrush( aFillAttributes
, pBackgroundBrush
, xSectionTOXColor
, aDummyRect
, false, /*bConsiderTextBox=*/false) )
4105 if ( xSectionTOXColor
&&
4106 (xSectionTOXColor
->IsTransparent()) &&
4107 (xSectionTOXColor
!= COL_TRANSPARENT
) )
4109 bBackgroundTransparent
= true;
4111 else if(aFillAttributes
&& aFillAttributes
->isUsed())
4113 bBackgroundTransparent
= aFillAttributes
->isTransparent();
4115 else if ( pBackgroundBrush
)
4117 if ( (pBackgroundBrush
->GetColor().IsTransparent()) &&
4118 (pBackgroundBrush
->GetColor() != COL_TRANSPARENT
) )
4120 bBackgroundTransparent
= true;
4124 const GraphicObject
*pTmpGrf
=
4125 pBackgroundBrush
->GetGraphicObject();
4127 (pTmpGrf
->GetAttr().IsTransparent())
4130 bBackgroundTransparent
= true;
4137 return bBackgroundTransparent
;
4140 bool SwFlyFrame::IsPaint( SdrObject
*pObj
, const SwViewShell
*pSh
)
4142 SdrObjUserCall
*pUserCall
= GetUserCall(pObj
);
4144 if ( nullptr == pUserCall
)
4147 //Attribute dependent, don't paint for printer or Preview
4148 bool bPaint
= gProp
.pSFlyOnlyDraw
||
4149 static_cast<SwContact
*>(pUserCall
)->GetFormat()->GetPrint().GetValue();
4151 bPaint
= pSh
->GetWin() && !pSh
->IsPreview();
4155 //The paint may be prevented by the superior Flys.
4156 SwFrame
*pAnch
= nullptr;
4157 if ( dynamic_cast< const SwFlyDrawObj
*>( pObj
) != nullptr ) // i#117962#
4161 if ( auto pFlyDraw
= dynamic_cast<SwVirtFlyDrawObj
*>( pObj
) )
4163 SwFlyFrame
*pFly
= pFlyDraw
->GetFlyFrame();
4164 if ( gProp
.pSFlyOnlyDraw
&& gProp
.pSFlyOnlyDraw
== pFly
)
4167 //Try to avoid displaying the intermediate stage, Flys which don't
4168 //overlap with the page on which they are anchored won't be
4170 //HACK: exception: printing of frames in tables, those can overlap
4171 //a page once in a while when dealing with oversized tables (HTML).
4172 SwPageFrame
*pPage
= pFly
->FindPageFrame();
4173 if ( pPage
&& pPage
->getFrameArea().Overlaps( pFly
->getFrameArea() ) )
4175 pAnch
= pFly
->AnchorFrame();
4181 // Consider 'virtual' drawing objects
4182 SwDrawContact
* pDrawContact
= dynamic_cast<SwDrawContact
*>(pUserCall
);
4183 pAnch
= pDrawContact
? pDrawContact
->GetAnchorFrame(pObj
) : nullptr;
4186 if ( !pAnch
->isFrameAreaPositionValid() )
4188 else if ( pSh
->GetOut() == pSh
->getIDocumentDeviceAccess().getPrinter( false ))
4190 //HACK: we have to omit some of the objects for printing,
4191 //otherwise they would be printed twice.
4192 //The objects should get printed if the TableHack is active
4193 //right now. Afterwards they must not be printed if the
4194 //page over which they float position wise gets printed.
4195 const SwPageFrame
*pPage
= pAnch
->FindPageFrame();
4196 if ( !pPage
->getFrameArea().Overlaps( SwRect(pObj
->GetCurrentBoundRect()) ) )
4202 if ( dynamic_cast< const SdrObjGroup
*>( pObj
) == nullptr )
4204 OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" );
4210 if ( pAnch
->IsInFly() )
4211 bPaint
= SwFlyFrame::IsPaint( pAnch
->FindFlyFrame()->GetVirtDrawObj(),
4213 else if ( gProp
.pSFlyOnlyDraw
)
4222 void SwCellFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const) const
4224 if ( GetLayoutRowSpan() >= 1 )
4225 SwLayoutFrame::PaintSwFrame( rRenderContext
, rRect
);
4230 struct BorderLinesGuard
4232 explicit BorderLinesGuard() : m_pBorderLines(std::move(gProp
.pBLines
))
4234 gProp
.pBLines
.reset(new BorderLines
);
4238 gProp
.pBLines
= std::move(m_pBorderLines
);
4241 std::unique_ptr
<BorderLines
> m_pBorderLines
;
4246 // set strikethrough for deleted objects anchored to character
4247 void SwFrame::SetDrawObjsAsDeleted( bool bDeleted
)
4249 if ( SwSortedObjs
*pObjs
= GetDrawObjs() )
4251 for (SwAnchoredObject
* pAnchoredObj
: *pObjs
)
4253 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
4255 pFly
->SetDeleted(bDeleted
);
4261 void SwFlyFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const) const
4263 //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
4264 SwViewShell
*pShell
= getRootFrame()->GetCurrShell();
4265 if (pShell
&& pShell
->GetDoc() && pShell
->GetDoc()->GetDocShell())
4267 bool bInGenerateThumbnail
= pShell
->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail();
4268 if (bInGenerateThumbnail
)
4270 const SwRect
& aVisRect
= pShell
->VisArea();
4271 if (!aVisRect
.Overlaps(getFrameArea()))
4276 //because of the overlapping of frames and drawing objects the flys have to
4277 //paint their borders (and those of the internal ones) directly.
4279 gProp
.pSLines
->LockLines(true);
4280 BorderLinesGuard blg
; // this should not paint borders added from PaintBaBo
4282 SwRect
aRect( rRect
);
4283 aRect
.Intersection_( getFrameArea() );
4285 rRenderContext
.Push( vcl::PushFlags::CLIPREGION
);
4286 rRenderContext
.SetClipRegion();
4287 const SwPageFrame
* pPage
= FindPageFrame();
4289 const SwNoTextFrame
*pNoText
= Lower() && Lower()->IsNoTextFrame()
4290 ? static_cast<const SwNoTextFrame
*>(Lower()) : nullptr;
4292 bool bIsChart
= false; //#i102950# don't paint additional borders for charts
4293 //check whether we have a chart
4296 const SwNoTextNode
* pNoTNd
= dynamic_cast<const SwNoTextNode
*>(pNoText
->GetNode());
4299 SwOLENode
* pOLENd
= const_cast<SwOLENode
*>(pNoTNd
->GetOLENode());
4300 if( pOLENd
&& pOLENd
->GetOLEObj().GetObject().IsChart() )
4306 bool bContour
= GetFormat()->GetSurround().IsContour();
4307 tools::PolyPolygon aPoly
;
4310 // add 2nd parameter with value <true>
4311 // to indicate that method is called for paint in order to avoid
4312 // load of the intrinsic graphic.
4313 bContour
= GetContour( aPoly
, true );
4316 // #i47804# - distinguish complete background paint
4317 // and margin paint.
4318 // paint complete background for Writer text fly frames
4319 bool bPaintCompleteBack( !pNoText
);
4320 // paint complete background for transparent graphic and contour,
4321 // if own background color exists.
4322 const bool bIsGraphicTransparent
= pNoText
&& pNoText
->IsTransparent();
4323 if ( !bPaintCompleteBack
&&
4324 ( bIsGraphicTransparent
|| bContour
) )
4326 const SwFlyFrameFormat
* pSwFrameFormat
= GetFormat();
4328 if (pSwFrameFormat
&& pSwFrameFormat
->supportsFullDrawingLayerFillAttributeSet())
4330 // check for transparency
4331 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
aFillAttributes(pSwFrameFormat
->getSdrAllFillAttributesHelper());
4333 // check if the new fill attributes are used
4334 if(aFillAttributes
&& aFillAttributes
->isUsed())
4336 bPaintCompleteBack
= true;
4341 std::unique_ptr
<SvxBrushItem
> aBack
= GetFormat()->makeBackgroundBrushItem();
4342 // to determine, if background has to be painted, by checking, if
4343 // background color is not COL_TRANSPARENT ("no fill"/"auto fill")
4344 // or a background graphic exists.
4345 bPaintCompleteBack
=
4346 aBack
->GetColor() != COL_TRANSPARENT
||
4347 aBack
->GetGraphicPos() != GPOS_NONE
;
4350 // paint of margin needed.
4351 const bool bPaintMarginOnly( !bPaintCompleteBack
&&
4352 getFramePrintArea().SSize() != getFrameArea().SSize() );
4354 // #i47804# - paint background of parent fly frame
4355 // for transparent graphics in layer Hell, if parent fly frame isn't
4356 // in layer Hell. It's only painted the intersection between the
4357 // parent fly frame area and the paint area <aRect>
4358 const IDocumentDrawModelAccess
& rIDDMA
= GetFormat()->getIDocumentDrawModelAccess();
4360 if (bIsGraphicTransparent
&&
4361 GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
) &&
4362 GetVirtDrawObj()->GetLayer() == rIDDMA
.GetHellId() &&
4363 GetAnchorFrame()->FindFlyFrame() )
4365 const SwFlyFrame
* pParentFlyFrame
= GetAnchorFrame()->FindFlyFrame();
4366 if ( pParentFlyFrame
->GetDrawObj()->GetLayer() !=
4367 rIDDMA
.GetHellId() )
4369 SwFlyFrame
* pOldRet
= gProp
.pSRetoucheFly2
;
4370 gProp
.pSRetoucheFly2
= const_cast<SwFlyFrame
*>(this);
4372 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pParentFlyFrame
);
4373 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4374 SwRect
aPaintRect( aRect
);
4375 aPaintRect
.Intersection_( pParentFlyFrame
->getFrameArea() );
4376 pParentFlyFrame
->PaintSwFrameBackground( aPaintRect
, pPage
, rAttrs
);
4378 gProp
.pSRetoucheFly2
= pOldRet
;
4382 if ( bPaintCompleteBack
|| bPaintMarginOnly
)
4384 //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder
4385 //receives the original Rect but PaintSwFrameBackground only the limited
4388 rRenderContext
.Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
4389 rRenderContext
.SetLineColor();
4391 pPage
= FindPageFrame();
4393 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(this) );
4394 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4398 SwRegionRects
aRegion( aRect
);
4400 // suppress painting of background in printing area for
4401 // non-transparent graphics.
4402 if ( bPaintMarginOnly
||
4403 ( pNoText
&& !bIsGraphicTransparent
) )
4405 //What we actually want to paint is the small stripe between
4406 //PrtArea and outer border.
4407 SwRect
aTmp( getFramePrintArea() ); aTmp
+= getFrameArea().Pos();
4412 rRenderContext
.Push();
4414 // apply clip region under the same conditions, which are
4415 // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region
4416 // for painting the graphic/OLE. Thus, the clip region is
4417 // also applied for the PDF export.
4418 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
4420 if ( !rRenderContext
.GetConnectMetaFile() || !pSh
|| !pSh
->GetWin() )
4422 rRenderContext
.SetClipRegion(vcl::Region(aPoly
));
4425 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4427 PaintSwFrameBackground( aRegion
[i
], pPage
, rAttrs
, false, true );
4430 rRenderContext
.Pop();
4434 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4436 PaintSwFrameBackground( aRegion
[i
], pPage
, rAttrs
, false, true );
4441 // paint border before painting background
4442 PaintSwFrameShadowAndBorder(rRect
, pPage
, rAttrs
);
4444 rRenderContext
.Pop();
4448 // fly frame will paint it's subsidiary lines and
4449 // the subsidiary lines of its lowers on its own, due to overlapping with
4450 // other fly frames or other objects.
4451 if( gProp
.pSGlobalShell
->GetWin()
4452 && !bIsChart
) //#i102950# don't paint additional borders for charts
4454 bool bSubsLineRectsCreated
;
4455 if ( gProp
.pSSubsLines
)
4457 // Lock already existing subsidiary lines
4458 gProp
.pSSubsLines
->LockLines( true );
4459 bSubsLineRectsCreated
= false;
4463 // create new subsidiary lines
4464 gProp
.pSSubsLines
.reset(new SwSubsRects
);
4465 bSubsLineRectsCreated
= true;
4468 bool bSpecSubsLineRectsCreated
;
4469 if ( gProp
.pSSpecSubsLines
)
4471 // Lock already existing special subsidiary lines
4472 gProp
.pSSpecSubsLines
->LockLines( true );
4473 bSpecSubsLineRectsCreated
= false;
4477 // create new special subsidiary lines
4478 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
4479 bSpecSubsLineRectsCreated
= true;
4481 // Add subsidiary lines of fly frame and its lowers
4482 RefreshLaySubsidiary( pPage
, aRect
);
4483 // paint subsidiary lines of fly frame and its lowers
4484 gProp
.pSSpecSubsLines
->PaintSubsidiary( &rRenderContext
, nullptr, gProp
);
4485 gProp
.pSSubsLines
->PaintSubsidiary(&rRenderContext
, gProp
.pSLines
.get(), gProp
);
4486 if ( !bSubsLineRectsCreated
)
4487 // unlock subsidiary lines
4488 gProp
.pSSubsLines
->LockLines( false );
4491 // delete created subsidiary lines container
4492 gProp
.pSSubsLines
.reset();
4495 if ( !bSpecSubsLineRectsCreated
)
4496 // unlock special subsidiary lines
4497 gProp
.pSSpecSubsLines
->LockLines( false );
4500 // delete created special subsidiary lines container
4501 gProp
.pSSpecSubsLines
.reset();
4505 SwLayoutFrame::PaintSwFrame( rRenderContext
, aRect
);
4510 SwTaggedPDFHelper
tag(nullptr, nullptr, nullptr, rRenderContext
);
4511 // first paint lines added by fly frame paint
4512 // and then unlock other lines.
4513 gProp
.pSLines
->PaintLines( &rRenderContext
, gProp
);
4514 gProp
.pSLines
->LockLines( false );
4515 // have to paint frame borders added in heaven layer here...
4516 ProcessPrimitives(gProp
.pBLines
->GetBorderLines_Clear());
4521 // crossing out for tracked deletion
4522 if ( GetAuthor() != std::string::npos
&& IsDeleted() )
4524 tools::Long startX
= aRect
.Left( ), endX
= aRect
.Right();
4525 tools::Long startY
= aRect
.Top( ), endY
= aRect
.Bottom();
4526 rRenderContext
.SetLineColor( SwPostItMgr::GetColorAnchor(GetAuthor()) );
4527 rRenderContext
.DrawLine(Point(startX
, startY
), Point(endX
, endY
));
4528 rRenderContext
.DrawLine(Point(startX
, endY
), Point(endX
, startY
));
4531 rRenderContext
.Pop();
4533 if ( gProp
.pSProgress
&& pNoText
)
4534 SfxProgress::Reschedule();
4537 void SwFlyFrame::PaintDecorators() const
4539 // Show the un-float button
4540 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
4543 UpdateUnfloatButton(pWrtSh
, IsShowUnfloatButton(pWrtSh
));
4547 SwView
* SwTextFrame::GetView()
4549 SwWrtShell
* pWrtSh
= dynamic_cast<SwWrtShell
*>(gProp
.pSGlobalShell
);
4554 return &pWrtSh
->GetView();
4557 void SwTextFrame::PaintParagraphStylesHighlighting() const
4559 // Maybe avoid the dynamic_cast and just use GetActiveWrtShell()
4560 // NO! Multiple windows will not display the highlighting correctly if GetActiveWrtShell is used.
4561 SwWrtShell
* pWrtSh
= dynamic_cast<SwWrtShell
*>(gProp
.pSGlobalShell
);
4566 vcl::RenderContext
* pRenderContext
= pWrtSh
->GetOut();
4567 if (!pRenderContext
)
4570 StylesHighlighterColorMap
& rParaStylesColorMap
4571 = pWrtSh
->GetView().GetStylesHighlighterParaColorMap();
4573 if (rParaStylesColorMap
.empty())
4576 // draw styles highlighter
4577 OUString sStyleName
= GetTextNodeFirst()->GetTextColl()->GetName();
4578 if (rParaStylesColorMap
.find(sStyleName
) != rParaStylesColorMap
.end())
4580 SwRect
aFrameAreaRect(getFrameArea());
4582 if (IsRightToLeft())
4584 aFrameAreaRect
.AddRight(75);
4585 aFrameAreaRect
.Left(aFrameAreaRect
.Right() + 300);
4589 aFrameAreaRect
.AddLeft(-375);
4590 aFrameAreaRect
.Right(aFrameAreaRect
.Left() + 300);
4593 const tools::Rectangle
& rRect
= aFrameAreaRect
.SVRect();
4595 vcl::Font
aFont(OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS
, GetAppLanguage(),
4596 GetDefaultFontFlags::OnlyOne
, pRenderContext
));
4597 aFont
.SetFontSize(Size(0, 140 * pRenderContext
->GetDPIScaleFactor()));
4598 aFont
.SetUnderline(FontLineStyle::LINESTYLE_NONE
);
4599 aFont
.SetTransparent(false);
4600 aFont
.SetWeight(WEIGHT_NORMAL
);
4601 aFont
.SetFamily(FontFamily::FAMILY_MODERN
);
4602 aFont
.SetColor(COL_BLACK
);
4604 pRenderContext
->Push(vcl::PushFlags::ALL
);
4606 pRenderContext
->SetFillColor(rParaStylesColorMap
[sStyleName
].first
);
4607 pRenderContext
->SetLineColor(rParaStylesColorMap
[sStyleName
].first
);
4609 pRenderContext
->DrawRect(rRect
);
4611 // draw hatch pattern if paragraph has direct formatting
4612 if (SwDoc::HasParagraphDirectFormatting(SwPosition(*GetTextNodeForParaProps())))
4614 Color
aHatchColor(rParaStylesColorMap
[sStyleName
].first
);
4615 // make hatch line color 41% darker than the fill color
4616 aHatchColor
.ApplyTintOrShade(-4100);
4617 Hatch
aHatch(HatchStyle::Single
, aHatchColor
, 50, 450_deg10
);
4618 pRenderContext
->DrawHatch(tools::PolyPolygon(rRect
), aHatch
);
4621 pRenderContext
->SetFont(aFont
);
4622 pRenderContext
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default
);
4623 pRenderContext
->SetTextFillColor(rParaStylesColorMap
[sStyleName
].first
);
4624 pRenderContext
->DrawText(rRect
, OUString::number(rParaStylesColorMap
[sStyleName
].second
),
4625 DrawTextFlags::Center
| DrawTextFlags::VCenter
);
4627 pRenderContext
->Pop();
4631 void SwTextFrame::PaintOutlineContentVisibilityButton() const
4633 SwWrtShell
* pWrtSh
= dynamic_cast<SwWrtShell
*>(gProp
.pSGlobalShell
);
4634 if (pWrtSh
&& pWrtSh
->GetViewOptions()->IsShowOutlineContentVisibilityButton())
4635 UpdateOutlineContentVisibilityButton(pWrtSh
);
4638 void SwTabFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, SwPrintData
const*const) const
4640 const SwViewOption
* pViewOption
= gProp
.pSGlobalShell
->GetViewOptions();
4641 if (pViewOption
->IsTable())
4644 if ( IsCollapsingBorders() )
4646 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(this) );
4647 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4650 if ( rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
)
4653 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, true, gProp
);
4654 PaintShadow( rRect
, aRect
, rAttrs
);
4657 SwTabFramePainter
aHelper(*this);
4658 aHelper
.PaintLines(rRenderContext
, rRect
);
4661 SwLayoutFrame::PaintSwFrame( rRenderContext
, rRect
);
4663 // #i6467# - no light grey rectangle for page preview
4664 else if ( gProp
.pSGlobalShell
->GetWin() && !gProp
.pSGlobalShell
->IsPreview() )
4666 // #i6467# - intersect output rectangle with table frame
4667 SwRect
aTabRect( getFramePrintArea() );
4668 aTabRect
.Pos() += getFrameArea().Pos();
4669 SwRect
aTabOutRect( rRect
);
4670 aTabOutRect
.Intersection( aTabRect
);
4671 SwViewOption::DrawRect( &rRenderContext
, aTabOutRect
, COL_LIGHTGRAY
);
4673 const_cast<SwTabFrame
*>(this)->ResetComplete();
4677 * Paint border shadow
4679 * @param[in] rRect aligned rect to clip the result
4680 * @param[in,out] rOutRect full painting area as input
4681 * painting area reduced by shadow space for border and background as output
4682 * @param[in] rShadow includes shadow attributes
4683 * @param[in] bDrawFullShadowRectangle paint full rect of shadow
4684 * @param[in] bTop paint top part of the shadow
4685 * @param[in] bBottom paint bottom part of the shadow
4686 * @param[in] bLeft paint left part of the shadow
4687 * @param[in] bRight paint right part of the shadow
4689 static void lcl_PaintShadow( const SwRect
& rRect
, SwRect
& rOutRect
,
4690 const SvxShadowItem
& rShadow
, const bool bDrawFullShadowRectangle
,
4691 const bool bTop
, const bool bBottom
,
4692 const bool bLeft
, const bool bRight
,
4693 SwPaintProperties
const & properties
)
4695 const tools::Long nWidth
= ::lcl_AlignWidth ( rShadow
.GetWidth(), properties
);
4696 const tools::Long nHeight
= ::lcl_AlignHeight( rShadow
.GetWidth(), properties
);
4699 SwRect
aOut( rOutRect
);
4701 switch ( rShadow
.GetLocation() )
4703 case SvxShadowLocation::BottomRight
:
4705 if ( bDrawFullShadowRectangle
)
4707 // draw full shadow rectangle
4708 aOut
.Top( rOutRect
.Top() + nHeight
);
4709 aOut
.Left( rOutRect
.Left() + nWidth
);
4710 aRegion
.push_back( aOut
);
4716 aOut
.Top( rOutRect
.Bottom() - nHeight
);
4718 aOut
.Left( rOutRect
.Left() + nWidth
);
4719 aRegion
.push_back( aOut
);
4723 aOut
.Left( rOutRect
.Right() - nWidth
);
4725 aOut
.Top( rOutRect
.Top() + nHeight
);
4727 aOut
.Top( rOutRect
.Top() );
4729 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4730 aRegion
.push_back( aOut
);
4735 rOutRect
.AddRight(- nWidth
);
4737 rOutRect
.AddBottom(- nHeight
);
4740 case SvxShadowLocation::TopLeft
:
4742 if ( bDrawFullShadowRectangle
)
4744 // draw full shadow rectangle
4745 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4746 aOut
.Right( rOutRect
.Right() - nWidth
);
4747 aRegion
.push_back( aOut
);
4753 aOut
.Bottom( rOutRect
.Top() + nHeight
);
4755 aOut
.Right( rOutRect
.Right() - nWidth
);
4756 aRegion
.push_back( aOut
);
4760 aOut
.Right( rOutRect
.Left() + nWidth
);
4762 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4764 aOut
.Bottom( rOutRect
.Bottom() );
4766 aOut
.Top( rOutRect
.Top() + nHeight
);
4767 aRegion
.push_back( aOut
);
4772 rOutRect
.AddLeft( nWidth
);
4774 rOutRect
.AddTop( nHeight
);
4777 case SvxShadowLocation::TopRight
:
4779 if ( bDrawFullShadowRectangle
)
4781 // draw full shadow rectangle
4782 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4783 aOut
.Left( rOutRect
.Left() + nWidth
);
4784 aRegion
.push_back( aOut
);
4790 aOut
.Bottom( rOutRect
.Top() + nHeight
);
4792 aOut
.Left( rOutRect
.Left() + nWidth
);
4793 aRegion
.push_back( aOut
);
4797 aOut
.Left( rOutRect
.Right() - nWidth
);
4799 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4801 aOut
.Bottom( rOutRect
.Bottom() );
4803 aOut
.Top( rOutRect
.Top() + nHeight
);
4804 aRegion
.push_back( aOut
);
4809 rOutRect
.AddRight( - nWidth
);
4811 rOutRect
.AddTop( nHeight
);
4814 case SvxShadowLocation::BottomLeft
:
4816 if ( bDrawFullShadowRectangle
)
4818 // draw full shadow rectangle
4819 aOut
.Top( rOutRect
.Top() + nHeight
);
4820 aOut
.Right( rOutRect
.Right() - nWidth
);
4821 aRegion
.push_back( aOut
);
4827 aOut
.Top( rOutRect
.Bottom()- nHeight
);
4829 aOut
.Right( rOutRect
.Right() - nWidth
);
4830 aRegion
.push_back( aOut
);
4834 aOut
.Right( rOutRect
.Left() + nWidth
);
4836 aOut
.Top( rOutRect
.Top() + nHeight
);
4838 aOut
.Top( rOutRect
.Top() );
4840 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4841 aRegion
.push_back( aOut
);
4846 rOutRect
.AddLeft( nWidth
);
4848 rOutRect
.AddBottom( - nHeight
);
4856 vcl::RenderContext
*pOut
= properties
.pSGlobalShell
->GetOut();
4858 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
4859 Color
aShadowColor( rShadow
.GetColor().GetRGBColor() );
4860 if( !aRegion
.empty() && properties
.pSGlobalShell
->GetWin() &&
4861 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4863 // In high contrast mode, the output device has already set the
4864 // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function
4865 // to ignore the setting of a new color. Therefore we have to reset
4867 pOut
->SetDrawMode( DrawModeFlags::Default
);
4868 aShadowColor
= properties
.pSGlobalShell
->GetViewOptions()->GetFontColor();
4871 if ( pOut
->GetFillColor() != aShadowColor
)
4872 pOut
->SetFillColor( aShadowColor
);
4874 pOut
->SetLineColor();
4876 pOut
->SetDrawMode( nOldDrawMode
);
4878 for (const SwRect
& rOut
: aRegion
)
4881 if ( rRect
.Overlaps( aOut
) && aOut
.Height() > 0 && aOut
.Width() > 0 )
4883 aOut
.Intersection_( rRect
);
4884 pOut
->DrawRect( aOut
.SVRect() );
4890 * Paints a shadow if the format requests so.
4892 * The shadow is always painted on the outer edge of the OutRect.
4893 * If needed, the OutRect is shrunk so the painting of the border can be
4896 * @note: draw full shadow rectangle for frames with transparent drawn backgrounds (OD 23.08.2002 #99657#)
4898 void SwFrame::PaintShadow( const SwRect
& rRect
, SwRect
& rOutRect
,
4899 const SwBorderAttrs
&rAttrs
) const
4901 SvxShadowItem rShadow
= rAttrs
.GetShadow();
4903 const bool bCnt
= IsContentFrame();
4904 const bool bTop
= !bCnt
|| rAttrs
.GetTopLine ( *(this) );
4905 const bool bBottom
= !bCnt
|| rAttrs
.GetBottomLine( *(this) );
4909 switch( rShadow
.GetLocation() )
4911 case SvxShadowLocation::BottomRight
: rShadow
.SetLocation(SvxShadowLocation::BottomLeft
); break;
4912 case SvxShadowLocation::TopLeft
: rShadow
.SetLocation(SvxShadowLocation::TopRight
); break;
4913 case SvxShadowLocation::TopRight
: rShadow
.SetLocation(SvxShadowLocation::BottomRight
); break;
4914 case SvxShadowLocation::BottomLeft
: rShadow
.SetLocation(SvxShadowLocation::TopLeft
); break;
4919 // determine, if full shadow rectangle have to be drawn or only two shadow rectangles beside the frame.
4920 // draw full shadow rectangle, if frame background is drawn transparent.
4922 // SwLayoutFrame can have transparent drawn backgrounds. Thus,
4923 // "asked" their frame format.
4924 const bool bDrawFullShadowRectangle
=
4925 ( IsLayoutFrame() &&
4926 static_cast<const SwLayoutFrame
*>(this)->GetFormat()->IsBackgroundTransparent()
4929 SwRectFnSet
aRectFnSet(this);
4930 ::lcl_ExtendLeftAndRight( rOutRect
, *(this), rAttrs
, aRectFnSet
.FnRect() );
4932 lcl_PaintShadow(rRect
, rOutRect
, rShadow
, bDrawFullShadowRectangle
, bTop
, bBottom
, true, true, gProp
);
4935 void SwFrame::PaintBorderLine( const SwRect
& rRect
,
4936 const SwRect
& rOutRect
,
4937 const SwPageFrame
* pPage
,
4938 const Color
*pColor
,
4939 const SvxBorderLineStyle nStyle
) const
4941 if ( !rOutRect
.Overlaps( rRect
) )
4944 SwRect
aOut( rOutRect
);
4945 aOut
.Intersection_( rRect
);
4947 const SwTabFrame
*pTab
= IsCellFrame() ? FindTabFrame() : nullptr;
4948 SubColFlags nSubCol
= ( IsCellFrame() || IsRowFrame() )
4952 : ( IsInFly() ? SubColFlags::Fly
: SubColFlags::Page
) );
4953 if( pColor
&& gProp
.pSGlobalShell
->GetWin() &&
4954 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4956 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
4957 const SwViewOption
*pOpt
= pSh
->GetViewOptions();
4958 pColor
= &pOpt
->GetFontColor();
4961 if (pPage
->GetSortedObjs() &&
4962 pPage
->GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
))
4964 SwRegionRects
aRegion( aOut
, 4 );
4965 basegfx::utils::B2DClipState aClipState
;
4966 ::lcl_SubtractFlys( this, pPage
, aOut
, aRegion
, aClipState
, gProp
);
4967 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4968 gProp
.pSLines
->AddLineRect( aRegion
[i
], pColor
, nStyle
, pTab
, nSubCol
, gProp
);
4971 gProp
.pSLines
->AddLineRect( aOut
, pColor
, nStyle
, pTab
, nSubCol
, gProp
);
4974 namespace drawinglayer::primitive2d
4978 class SwBorderRectanglePrimitive2D
: public BufferedDecompositionPrimitive2D
4981 /// the transformation defining the geometry of this BorderRectangle
4982 basegfx::B2DHomMatrix maB2DHomMatrix
;
4984 /// the four styles to be used
4985 svx::frame::Style maStyleTop
;
4986 svx::frame::Style maStyleRight
;
4987 svx::frame::Style maStyleBottom
;
4988 svx::frame::Style maStyleLeft
;
4991 /// local decomposition.
4992 virtual void create2DDecomposition(
4993 Primitive2DContainer
& rContainer
,
4994 const geometry::ViewInformation2D
& rViewInformation
) const override
;
4998 SwBorderRectanglePrimitive2D(
4999 basegfx::B2DHomMatrix aB2DHomMatrix
,
5000 const svx::frame::Style
& rStyleTop
,
5001 const svx::frame::Style
& rStyleRight
,
5002 const svx::frame::Style
& rStyleBottom
,
5003 const svx::frame::Style
& rStyleLeft
);
5005 /// data read access
5006 const basegfx::B2DHomMatrix
& getB2DHomMatrix() const { return maB2DHomMatrix
; }
5007 const svx::frame::Style
& getStyleTop() const { return maStyleTop
; }
5008 const svx::frame::Style
& getStyleRight() const { return maStyleRight
; }
5009 const svx::frame::Style
& getStyleBottom() const { return maStyleBottom
; }
5010 const svx::frame::Style
& getStyleLeft() const { return maStyleLeft
; }
5012 /// compare operator
5013 virtual bool operator==(const BasePrimitive2D
& rPrimitive
) const override
;
5016 virtual basegfx::B2DRange
getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const override
;
5018 /// provide unique ID
5019 virtual sal_uInt32
getPrimitive2DID() const override
;
5024 void SwBorderRectanglePrimitive2D::create2DDecomposition(
5025 Primitive2DContainer
& rContainer
,
5026 const geometry::ViewInformation2D
& /*rViewInformation*/) const
5028 basegfx::B2DPoint
aTopLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 0.0));
5029 basegfx::B2DPoint
aTopRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 0.0));
5030 basegfx::B2DPoint
aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0));
5031 basegfx::B2DPoint
aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0));
5033 // prepare SdrFrameBorderDataVector
5034 drawinglayer::primitive2d::SdrFrameBorderDataVector aData
;
5036 if(getStyleTop().IsUsed())
5038 // move top left/right inwards half border width
5039 basegfx::B2DVector
aDown(getB2DHomMatrix() * basegfx::B2DVector(0.0, 1.0));
5040 aDown
.setLength(getStyleTop().GetWidth() * 0.5);
5045 if(getStyleBottom().IsUsed())
5047 // move bottom left/right inwards half border width
5048 basegfx::B2DVector
aUp(getB2DHomMatrix() * basegfx::B2DVector(0.0, -1.0));
5049 aUp
.setLength(getStyleBottom().GetWidth() * 0.5);
5051 aBottomRight
+= aUp
;
5054 if(getStyleLeft().IsUsed())
5056 // move left top/bottom inwards half border width
5057 basegfx::B2DVector
aRight(getB2DHomMatrix() * basegfx::B2DVector(1.0, 0.0));
5058 aRight
.setLength(getStyleLeft().GetWidth() * 0.5);
5060 aBottomLeft
+= aRight
;
5063 if(getStyleRight().IsUsed())
5065 // move right top/bottom inwards half border width
5066 basegfx::B2DVector
aLeft(getB2DHomMatrix() * basegfx::B2DVector(-1.0, 0.0));
5067 aLeft
.setLength(getStyleRight().GetWidth() * 0.5);
5069 aBottomRight
+= aLeft
;
5072 // go round-robin, from TopLeft to TopRight, down, left and back up. That
5073 // way, the borders will not need to be mirrored in any way
5074 if(getStyleTop().IsUsed())
5076 // create BorderPrimitive(s) for top border
5077 const basegfx::B2DVector
aVector(aTopRight
- aTopLeft
);
5083 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5085 if(getStyleLeft().IsUsed())
5087 rInstance
.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft
- aTopLeft
), false);
5090 if(getStyleRight().IsUsed())
5092 rInstance
.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight
- aTopRight
), false);
5096 if(getStyleRight().IsUsed())
5098 // create BorderPrimitive(s) for right border
5099 const basegfx::B2DVector
aVector(aBottomRight
- aTopRight
);
5105 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5107 if(getStyleTop().IsUsed())
5109 rInstance
.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft
- aTopRight
), false);
5112 if(getStyleBottom().IsUsed())
5114 rInstance
.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft
- aBottomRight
), false);
5118 if(getStyleBottom().IsUsed())
5120 // create BorderPrimitive(s) for bottom border
5121 const basegfx::B2DVector
aVector(aBottomLeft
- aBottomRight
);
5127 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5129 if(getStyleRight().IsUsed())
5131 rInstance
.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight
- aBottomRight
), false);
5134 if(getStyleLeft().IsUsed())
5136 rInstance
.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft
- aBottomLeft
), false);
5140 if(getStyleLeft().IsUsed())
5142 // create BorderPrimitive(s) for left border
5143 const basegfx::B2DVector
aVector(aTopLeft
- aBottomLeft
);
5149 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5151 if(getStyleBottom().IsUsed())
5153 rInstance
.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight
- aBottomLeft
), false);
5156 if(getStyleTop().IsUsed())
5158 rInstance
.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight
- aTopLeft
), false);
5162 // create instance of SdrFrameBorderPrimitive2D if
5163 // SdrFrameBorderDataVector is used
5167 drawinglayer::primitive2d::Primitive2DReference(
5168 new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
5170 true))); // force visualization to minimal one discrete unit (pixel)
5174 SwBorderRectanglePrimitive2D::SwBorderRectanglePrimitive2D(
5175 basegfx::B2DHomMatrix aB2DHomMatrix
,
5176 const svx::frame::Style
& rStyleTop
,
5177 const svx::frame::Style
& rStyleRight
,
5178 const svx::frame::Style
& rStyleBottom
,
5179 const svx::frame::Style
& rStyleLeft
)
5180 : maB2DHomMatrix(std::move(aB2DHomMatrix
)),
5181 maStyleTop(rStyleTop
),
5182 maStyleRight(rStyleRight
),
5183 maStyleBottom(rStyleBottom
),
5184 maStyleLeft(rStyleLeft
)
5188 bool SwBorderRectanglePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
5190 if(BasePrimitive2D::operator==(rPrimitive
))
5192 const SwBorderRectanglePrimitive2D
& rCompare
= static_cast<const SwBorderRectanglePrimitive2D
&>(rPrimitive
);
5194 return (getB2DHomMatrix() == rCompare
.getB2DHomMatrix() &&
5195 getStyleTop() == rCompare
.getStyleTop() &&
5196 getStyleRight() == rCompare
.getStyleRight() &&
5197 getStyleBottom() == rCompare
.getStyleBottom() &&
5198 getStyleLeft() == rCompare
.getStyleLeft());
5204 basegfx::B2DRange
SwBorderRectanglePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& /*rViewInformation*/) const
5206 basegfx::B2DRange
aRetval(0.0, 0.0, 1.0, 1.0);
5208 aRetval
.transform(getB2DHomMatrix());
5212 // provide unique ID
5213 sal_uInt32
SwBorderRectanglePrimitive2D::getPrimitive2DID() const
5215 return PRIMITIVE2D_ID_SWBORDERRECTANGLERIMITIVE
;
5218 } // end of namespace drawinglayer::primitive2d
5222 editeng::SvxBorderLine
const * get_ptr(std::optional
<editeng::SvxBorderLine
> const & opt
) {
5223 return opt
? &*opt
: nullptr;
5228 void PaintCharacterBorder(
5229 const SwFont
& rFont
,
5230 const SwRect
& rPaintArea
,
5231 const bool bVerticalLayout
,
5232 const bool bVerticalLayoutLRBT
,
5233 const bool bJoinWithPrev
,
5234 const bool bJoinWithNext
)
5236 SwRect
aAlignedRect(rPaintArea
);
5237 SwAlignRect(aAlignedRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut());
5240 bool bBottom
= true;
5244 switch (rFont
.GetOrientation(bVerticalLayout
, bVerticalLayoutLRBT
).get())
5247 bLeft
= !bJoinWithPrev
;
5248 bRight
= !bJoinWithNext
;
5251 bBottom
= !bJoinWithPrev
;
5252 bTop
= !bJoinWithNext
;
5255 bRight
= !bJoinWithPrev
;
5256 bLeft
= !bJoinWithNext
;
5259 bTop
= !bJoinWithPrev
;
5260 bBottom
= !bJoinWithNext
;
5264 // Paint shadow (reduce painting rect)
5266 const SvxShadowItem
aShadow(
5267 0, &rFont
.GetShadowColor(), rFont
.GetShadowWidth(),
5268 rFont
.GetAbsShadowLocation(bVerticalLayout
, bVerticalLayoutLRBT
));
5270 if( aShadow
.GetLocation() != SvxShadowLocation::NONE
)
5272 lcl_PaintShadow( rPaintArea
, aAlignedRect
, aShadow
,
5273 false, bTop
, bBottom
, bLeft
, bRight
, gProp
);
5277 const basegfx::B2DHomMatrix
aBorderTransform(
5278 basegfx::utils::createScaleTranslateB2DHomMatrix(
5279 aAlignedRect
.Width(), aAlignedRect
.Height(),
5280 aAlignedRect
.Left(), aAlignedRect
.Top()));
5281 const svx::frame::Style
aStyleTop(
5282 bTop
? get_ptr(rFont
.GetAbsTopBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5284 const svx::frame::Style
aStyleRight(
5285 bRight
? get_ptr(rFont
.GetAbsRightBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5287 const svx::frame::Style
aStyleBottom(
5288 bBottom
? get_ptr(rFont
.GetAbsBottomBorder(bVerticalLayout
, bVerticalLayoutLRBT
))
5291 const svx::frame::Style
aStyleLeft(
5292 bLeft
? get_ptr(rFont
.GetAbsLeftBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5294 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget
;
5296 aBorderLineTarget
.append(
5297 drawinglayer::primitive2d::Primitive2DReference(
5298 new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
5304 gProp
.pBLines
->AddBorderLines(std::move(aBorderLineTarget
));
5308 static const SwFrame
* lcl_HasNextCell( const SwFrame
& rFrame
)
5310 OSL_ENSURE( rFrame
.IsCellFrame(),
5311 "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame" );
5313 const SwFrame
* pTmpFrame
= &rFrame
;
5316 if ( pTmpFrame
->GetNext() )
5317 return pTmpFrame
->GetNext();
5319 pTmpFrame
= pTmpFrame
->GetUpper()->GetUpper();
5321 while ( pTmpFrame
->IsCellFrame() );
5327 * Determine cell frame, from which the border attributes
5328 * for paint of top/bottom border has to be used.
5330 * OD 21.02.2003 #b4779636#, #107692#
5332 * @param _pCellFrame
5333 * input parameter - constant pointer to cell frame for which the cell frame
5334 * for the border attributes has to be determined.
5336 * @param _rCellBorderAttrs
5337 * input parameter - constant reference to the border attributes of cell frame
5341 * input parameter - boolean, that controls, if cell frame for top border or
5342 * for bottom border has to be determined.
5344 * @return constant pointer to cell frame, for which the border attributes has
5347 static const SwFrame
* lcl_GetCellFrameForBorderAttrs( const SwFrame
* _pCellFrame
,
5348 const SwBorderAttrs
& _rCellBorderAttrs
,
5351 OSL_ENSURE( _pCellFrame
, "No cell frame available, dying soon" );
5353 // determine, if cell frame is at bottom/top border of a table frame and
5354 // the table frame has/is a follow.
5355 const SwFrame
* pTmpFrame
= _pCellFrame
;
5356 bool bCellAtBorder
= true;
5357 bool bCellAtLeftBorder
= !_pCellFrame
->GetPrev();
5358 bool bCellAtRightBorder
= !_pCellFrame
->GetNext();
5359 while( !pTmpFrame
->IsRowFrame() || !pTmpFrame
->GetUpper()->IsTabFrame() )
5361 pTmpFrame
= pTmpFrame
->GetUpper();
5362 if ( pTmpFrame
->IsRowFrame() &&
5363 (_bTop
? pTmpFrame
->GetPrev() : pTmpFrame
->GetNext())
5366 bCellAtBorder
= false;
5368 if ( pTmpFrame
->IsCellFrame() )
5370 if ( pTmpFrame
->GetPrev() )
5372 bCellAtLeftBorder
= false;
5374 if ( pTmpFrame
->GetNext() )
5376 bCellAtRightBorder
= false;
5380 OSL_ENSURE( pTmpFrame
&& pTmpFrame
->IsRowFrame(), "No RowFrame available" );
5382 const SwLayoutFrame
* pParentRowFrame
= static_cast<const SwLayoutFrame
*>(pTmpFrame
);
5383 const SwTabFrame
* pParentTabFrame
=
5384 static_cast<const SwTabFrame
*>(pParentRowFrame
->GetUpper());
5386 const bool bCellNeedsAttribute
= bCellAtBorder
&&
5388 // bCellInFirstRowWithMaster
5389 ( !pParentRowFrame
->GetPrev() &&
5390 pParentTabFrame
->IsFollow() &&
5391 0 == pParentTabFrame
->GetTable()->GetRowsToRepeat() ) :
5392 // bCellInLastRowWithFollow
5393 ( !pParentRowFrame
->GetNext() &&
5394 pParentTabFrame
->GetFollow() )
5397 const SwFrame
* pRet
= _pCellFrame
;
5398 if ( bCellNeedsAttribute
)
5400 // determine, if cell frame has no borders inside the table.
5401 const SwFrame
* pNextCell
= nullptr;
5402 bool bNoBordersInside
= false;
5404 if ( bCellAtLeftBorder
&& ( nullptr != ( pNextCell
= lcl_HasNextCell( *_pCellFrame
) ) ) )
5406 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pNextCell
);
5407 const SwBorderAttrs
&rBorderAttrs
= *aAccess
.Get();
5408 const SvxBoxItem
& rBorderBox
= rBorderAttrs
.GetBox();
5409 bCellAtRightBorder
= !lcl_HasNextCell( *pNextCell
);
5411 ( !rBorderBox
.GetTop() || !pParentRowFrame
->GetPrev() ) &&
5412 !rBorderBox
.GetLeft() &&
5413 ( !rBorderBox
.GetRight() || bCellAtRightBorder
) &&
5414 ( !rBorderBox
.GetBottom() || !pParentRowFrame
->GetNext() );
5418 const SvxBoxItem
& rBorderBox
= _rCellBorderAttrs
.GetBox();
5420 ( !rBorderBox
.GetTop() || !pParentRowFrame
->GetPrev() ) &&
5421 ( !rBorderBox
.GetLeft() || bCellAtLeftBorder
) &&
5422 ( !rBorderBox
.GetRight() || bCellAtRightBorder
) &&
5423 ( !rBorderBox
.GetBottom() || !pParentRowFrame
->GetNext() );
5426 if ( bNoBordersInside
)
5428 if ( _bTop
&& !_rCellBorderAttrs
.GetBox().GetTop() )
5431 // Cell frame has no top border and no border inside the table, but
5432 // it is at the top border of a table frame, which is a follow.
5433 // Thus, use border attributes of cell frame in first row of complete table.
5434 // First, determine first table frame of complete table.
5435 SwTabFrame
* pMasterTabFrame
= pParentTabFrame
->FindMaster( true );
5436 // determine first row of complete table.
5437 const SwFrame
* pFirstRow
= pMasterTabFrame
->GetLower();
5438 // return first cell in first row
5439 SwFrame
* pLowerCell
= const_cast<SwFrame
*>(pFirstRow
->GetLower());
5440 while ( !pLowerCell
->IsCellFrame() ||
5441 ( pLowerCell
->GetLower() && pLowerCell
->GetLower()->IsRowFrame() )
5444 pLowerCell
= pLowerCell
->GetLower();
5446 OSL_ENSURE( pLowerCell
&& pLowerCell
->IsCellFrame(), "No CellFrame available" );
5449 else if ( !_bTop
&& !_rCellBorderAttrs
.GetBox().GetBottom() )
5452 // Cell frame has no bottom border and no border inside the table,
5453 // but it is at the bottom border of a table frame, which has a follow.
5454 // Thus, use border attributes of cell frame in last row of complete table.
5455 // First, determine last table frame of complete table.
5456 SwTabFrame
* pLastTabFrame
= const_cast<SwTabFrame
*>(pParentTabFrame
->GetFollow());
5457 while ( pLastTabFrame
->GetFollow() )
5459 pLastTabFrame
= pLastTabFrame
->GetFollow();
5461 // determine last row of complete table.
5462 SwFrame
* pLastRow
= pLastTabFrame
->GetLastLower();
5463 // return first bottom border cell in last row
5464 SwFrame
* pLowerCell
= pLastRow
->GetLower();
5465 while ( !pLowerCell
->IsCellFrame() ||
5466 ( pLowerCell
->GetLower() && pLowerCell
->GetLower()->IsRowFrame() )
5469 if ( pLowerCell
->IsRowFrame() )
5471 while ( pLowerCell
->GetNext() )
5473 pLowerCell
= pLowerCell
->GetNext();
5476 pLowerCell
= pLowerCell
->GetLower();
5478 OSL_ENSURE( pLowerCell
&& pLowerCell
->IsCellFrame(), "No CellFrame available" );
5487 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> SwFrame::CreateProcessor2D( ) const
5489 basegfx::B2DRange aViewRange
;
5491 SdrPage
*pDrawPage
= getRootFrame()->GetCurrShell()->Imp()->GetPageView()->GetPage();
5492 drawinglayer::geometry::ViewInformation2D aNewViewInfos
;
5493 aNewViewInfos
.setViewTransformation(getRootFrame()->GetCurrShell()->GetOut()->GetViewTransformation());
5494 aNewViewInfos
.setViewport(aViewRange
);
5495 aNewViewInfos
.setVisualizedPage(GetXDrawPageForSdrPage( pDrawPage
));
5497 return drawinglayer::processor2d::createProcessor2DFromOutputDevice(
5498 *getRootFrame()->GetCurrShell()->GetOut(),
5502 void SwFrame::ProcessPrimitives( const drawinglayer::primitive2d::Primitive2DContainer
& rSequence
) const
5504 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor2D
= CreateProcessor2D();
5507 pProcessor2D
->process( rSequence
);
5511 /// Paints shadows and borders
5512 void SwFrame::PaintSwFrameShadowAndBorder(
5513 const SwRect
& rRect
,
5514 const SwPageFrame
* /*pPage*/,
5515 const SwBorderAttrs
& rAttrs
) const
5517 // There's nothing (Row,Body,Footnote,Root,Column,NoText) need to do here
5518 if (GetType() & (SwFrameType::NoTxt
|SwFrameType::Row
|SwFrameType::Body
|SwFrameType::Ftn
|SwFrameType::Column
|SwFrameType::Root
))
5521 if (IsCellFrame() && !gProp
.pSGlobalShell
->GetViewOptions()->IsTable())
5525 if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
5527 const SwTabFrame
* pTabFrame
= FindTabFrame();
5528 if ( pTabFrame
->IsCollapsingBorders() )
5531 if ( pTabFrame
->GetTable()->IsNewModel() && ( !IsCellFrame() || IsCoveredCell() ) )
5535 const bool bLine
= rAttrs
.IsLine();
5536 const bool bShadow
= rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
;
5538 // - flag to control,
5539 //-hack has to be used.
5540 const bool bb4779636HackActive
= true;
5542 const SwFrame
* pCellFrameForBottomBorderAttrs
= nullptr;
5543 const SwFrame
* pCellFrameForTopBorderAttrs
= nullptr;
5544 bool bFoundCellForTopOrBorderAttrs
= false;
5545 if ( bb4779636HackActive
&& IsCellFrame() )
5547 pCellFrameForBottomBorderAttrs
= lcl_GetCellFrameForBorderAttrs( this, rAttrs
, false );
5548 if ( pCellFrameForBottomBorderAttrs
!= this )
5549 bFoundCellForTopOrBorderAttrs
= true;
5550 pCellFrameForTopBorderAttrs
= lcl_GetCellFrameForBorderAttrs( this, rAttrs
, true );
5551 if ( pCellFrameForTopBorderAttrs
!= this )
5552 bFoundCellForTopOrBorderAttrs
= true;
5555 // - add condition <bFoundCellForTopOrBorderAttrs>
5557 if ( !(bLine
|| bShadow
|| bFoundCellForTopOrBorderAttrs
) )
5560 //If the rectangle is completely inside the PrtArea, no border needs to
5562 //For the PrtArea the aligned value needs to be used, otherwise it could
5563 //happen, that some parts won't be processed.
5564 SwRect
aRect( getFramePrintArea() );
5565 aRect
+= getFrameArea().Pos();
5566 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
5567 // new local boolean variable in order to
5568 // suspend border paint under special cases - see below.
5569 // NOTE: This is a fix for the implementation of feature #99657#.
5570 bool bDrawOnlyShadowForTransparentFrame
= false;
5571 if ( aRect
.Contains( rRect
) )
5573 // paint shadow, if background is transparent.
5574 // Because of introduced transparent background for fly frame #99657#,
5575 // the shadow have to be drawn if the background is transparent,
5576 // in spite the fact that the paint rectangle <rRect> lies fully
5577 // in the printing area.
5578 // NOTE to chosen solution:
5579 // On transparent background, continue processing, but suspend
5580 // drawing of border by setting <bDrawOnlyShadowForTransparentFrame>
5582 if ( IsLayoutFrame() &&
5583 static_cast<const SwLayoutFrame
*>(this)->GetFormat()->IsBackgroundTransparent() )
5585 bDrawOnlyShadowForTransparentFrame
= true;
5593 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, true, gProp
);
5594 rAttrs
.SetGetCacheLine( true );
5598 PaintShadow(rRect
, aRect
, rAttrs
);
5601 // suspend drawing of border
5602 // add condition < NOT bDrawOnlyShadowForTransparentFrame > - see above
5603 // - add condition <bFoundCellForTopOrBorderAttrs>
5605 if((bLine
|| bFoundCellForTopOrBorderAttrs
) && !bDrawOnlyShadowForTransparentFrame
)
5607 // define SvxBorderLine(s) to use
5608 const SvxBoxItem
& rBox(rAttrs
.GetBox());
5609 const SvxBorderLine
* pLeftBorder(rBox
.GetLeft());
5610 const SvxBorderLine
* pRightBorder(rBox
.GetRight());
5611 const SvxBorderLine
* pTopBorder(rBox
.GetTop());
5612 const SvxBorderLine
* pBottomBorder(rBox
.GetBottom());
5614 // if R2L, exchange Right/Left
5615 const bool bR2L(IsCellFrame() && IsRightToLeft());
5619 std::swap(pLeftBorder
, pRightBorder
);
5622 // if ContentFrame and joined Prev/Next, reset top/bottom as needed
5623 if(IsContentFrame())
5625 const SwFrame
* pDirRefFrame(IsCellFrame() ? FindTabFrame() : this);
5626 const SwRectFnSet
aRectFnSet(pDirRefFrame
);
5627 const SwRectFn
& _rRectFn(aRectFnSet
.FnRect());
5629 if(rAttrs
.JoinedWithPrev(*this))
5631 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5632 // existing gap to previous frame
5633 const SwFrame
* pPrevFrame(GetPrev());
5634 (aRect
.*_rRectFn
->fnSetTop
)( (pPrevFrame
->*_rRectFn
->fnGetPrtBottom
)() );
5636 // ...and disable top border paint/creation
5637 pTopBorder
= nullptr;
5640 if(rAttrs
.JoinedWithNext(*this))
5642 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5643 // existing gap to next frame
5644 const SwFrame
* pNextFrame(GetNext());
5645 (aRect
.*_rRectFn
->fnSetBottom
)( (pNextFrame
->*_rRectFn
->fnGetPrtTop
)() );
5647 // ...and disable bottom border paint/creation
5648 pBottomBorder
= nullptr;
5652 // necessary to replace TopBorder?
5653 if((!IsContentFrame() || rAttrs
.GetTopLine(*this)) && IsCellFrame() && pCellFrameForTopBorderAttrs
!= this)
5655 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pCellFrameForTopBorderAttrs
);
5656 pTopBorder
= aAccess
.Get()->GetBox().GetTop();
5659 // necessary to replace BottomBorder?
5660 if((!IsContentFrame() || rAttrs
.GetBottomLine(*this)) && IsCellFrame() && pCellFrameForBottomBorderAttrs
!= this)
5662 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pCellFrameForBottomBorderAttrs
);
5663 pBottomBorder
= aAccess
.Get()->GetBox().GetBottom();
5666 bool bWordBorder
= false;
5667 SwViewShell
* pShell
= getRootFrame()->GetCurrShell();
5670 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
5671 bWordBorder
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
5673 bool bInWordTableCell
= IsContentFrame() && GetUpper()->IsCellFrame() && bWordBorder
;
5674 if (bInWordTableCell
)
5676 // Compat mode: don't paint bottom border if we know the bottom of the content was cut
5678 auto pContentFrame
= static_cast<const SwContentFrame
*>(this);
5679 if (pContentFrame
->IsUndersized())
5681 pBottomBorder
= nullptr;
5685 if(nullptr != pLeftBorder
|| nullptr != pRightBorder
|| nullptr != pTopBorder
|| nullptr != pBottomBorder
)
5687 // now we have all SvxBorderLine(s) sorted out, create geometry
5688 const basegfx::B2DHomMatrix
aBorderTransform(
5689 basegfx::utils::createScaleTranslateB2DHomMatrix(
5690 aRect
.Width(), aRect
.Height(),
5691 aRect
.Left(), aRect
.Top()));
5692 const svx::frame::Style
aStyleTop(pTopBorder
, 1.0);
5693 svx::frame::Style
aStyleRight(pRightBorder
, 1.0);
5695 // Right/bottom page borders are always mirrored in Word.
5696 if (IsPageFrame() && bWordBorder
)
5698 aStyleRight
.MirrorSelf();
5701 svx::frame::Style
aStyleBottom(pBottomBorder
, 1.0);
5703 if (IsPageFrame() && bWordBorder
)
5705 aStyleBottom
.MirrorSelf();
5708 const svx::frame::Style
aStyleLeft(pLeftBorder
, 1.0);
5709 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget
;
5711 drawinglayer::primitive2d::Primitive2DReference
aRetval(
5712 new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
5719 if (bInWordTableCell
)
5721 // Compat mode: cut off the borders which are outside of our own area.
5722 const SwRect
& rClip
= getFrameArea();
5723 basegfx::B2DRectangle
aClip(rClip
.Left(), rClip
.Top(), rClip
.Right(),
5725 basegfx::B2DPolyPolygon
aPolyPolygon(
5726 basegfx::utils::createPolygonFromRect(aClip
));
5727 const drawinglayer::primitive2d::Primitive2DReference
xClipped(
5728 new drawinglayer::primitive2d::MaskPrimitive2D(std::move(aPolyPolygon
), { aRetval
}));
5732 aBorderLineTarget
.append(aRetval
);
5733 gProp
.pBLines
->AddBorderLines(std::move(aBorderLineTarget
));
5737 rAttrs
.SetGetCacheLine( false );
5741 * Special implementation because of the footnote line
5743 * Currently only the top frame needs to be taken into account
5744 * Other lines and shadows are set aside
5746 void SwFootnoteContFrame::PaintSwFrameShadowAndBorder(
5747 const SwRect
& rRect
,
5748 const SwPageFrame
* pPage
,
5749 const SwBorderAttrs
&) const
5751 //If the rectangle is completely inside the PrtArea, no border needs to
5753 SwRect
aRect( getFramePrintArea() );
5754 aRect
.Pos() += getFrameArea().Pos();
5755 if ( !aRect
.Contains( rRect
) )
5756 PaintLine( rRect
, pPage
);
5759 /// Paint footnote lines.
5760 void SwFootnoteContFrame::PaintLine( const SwRect
& rRect
,
5761 const SwPageFrame
*pPage
) const
5763 //The length of the line is derived from the percentual indication on the
5764 //PageDesc. The position is also stated on the PageDesc.
5765 //The pen can directly be taken from the PageDesc.
5768 pPage
= FindPageFrame();
5769 const SwPageFootnoteInfo
&rInf
= pPage
->GetPageDesc()->GetFootnoteInfo();
5771 SwRectFnSet
aRectFnSet(this);
5772 SwTwips nPrtWidth
= aRectFnSet
.GetWidth(getFramePrintArea());
5773 Fraction
aFract( nPrtWidth
, 1 );
5774 aFract
*= rInf
.GetWidth();
5775 const SwTwips nWidth
= static_cast<tools::Long
>(aFract
);
5777 SwTwips nX
= aRectFnSet
.GetPrtLeft(*this);
5778 switch ( rInf
.GetAdj() )
5780 case css::text::HorizontalAdjust_CENTER
:
5781 nX
+= nPrtWidth
/2 - nWidth
/2; break;
5782 case css::text::HorizontalAdjust_RIGHT
:
5783 nX
+= nPrtWidth
- nWidth
; break;
5784 case css::text::HorizontalAdjust_LEFT
:
5785 /* do nothing */; break;
5787 SAL_WARN("sw.core", "New adjustment for footnote lines?");
5790 SwTwips nLineWidth
= rInf
.GetLineWidth();
5791 const SwRect aLineRect
= aRectFnSet
.IsVert() ?
5792 SwRect( Point(getFrameArea().Left()+getFrameArea().Width()-rInf
.GetTopDist()-nLineWidth
,
5793 nX
), Size( nLineWidth
, nWidth
) )
5794 : SwRect( Point( nX
, getFrameArea().Pos().Y() + rInf
.GetTopDist() ),
5795 Size( nWidth
, rInf
.GetLineWidth()));
5796 if ( aLineRect
.HasArea() && rInf
.GetLineStyle() != SvxBorderLineStyle::NONE
)
5797 PaintBorderLine( rRect
, aLineRect
, pPage
, &rInf
.GetLineColor(),
5798 rInf
.GetLineStyle() );
5801 void SwFootnoteContFrame::dumpAsXml(xmlTextWriterPtr writer
) const
5803 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("ftncont"));
5804 dumpAsXmlAttributes(writer
);
5806 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
5807 dumpInfosAsXml(writer
);
5808 (void)xmlTextWriterEndElement(writer
);
5809 dumpChildrenAsXml(writer
);
5811 (void)xmlTextWriterEndElement(writer
);
5814 /// Paints the separator line for inside columns
5815 void SwLayoutFrame::PaintColLines( const SwRect
&rRect
, const SwFormatCol
&rFormatCol
,
5816 const SwPageFrame
*pPage
) const
5818 const SwFrame
*pCol
= Lower();
5819 if ( !pCol
|| !pCol
->IsColumnFrame() )
5822 SwRectFn fnRect
= pCol
->IsVertical() ? ( pCol
->IsVertLR() ? (pCol
->IsVertLRBT() ? fnRectVertL2RB2T
: fnRectVertL2R
) : fnRectVert
) : fnRectHori
;
5824 SwRect aLineRect
= getFramePrintArea();
5825 aLineRect
+= getFrameArea().Pos();
5827 SwTwips nTop
= ((aLineRect
.*fnRect
->fnGetHeight
)()*rFormatCol
.GetLineHeight())
5828 / 100 - (aLineRect
.*fnRect
->fnGetHeight
)();
5829 SwTwips nBottom
= 0;
5831 switch ( rFormatCol
.GetLineAdj() )
5834 nBottom
= nTop
/ 2; nTop
-= nBottom
; break;
5836 nBottom
= nTop
; nTop
= 0; break;
5840 OSL_ENSURE( false, "New adjustment for column lines?" );
5844 (aLineRect
.*fnRect
->fnSubTop
)( nTop
);
5846 (aLineRect
.*fnRect
->fnAddBottom
)( nBottom
);
5848 SwTwips nPenHalf
= rFormatCol
.GetLineWidth();
5849 (aLineRect
.*fnRect
->fnSetWidth
)( nPenHalf
);
5852 //We need to be a bit generous here, to not lose something.
5853 SwRect
aRect( rRect
);
5854 (aRect
.*fnRect
->fnSubLeft
)( nPenHalf
+ gProp
.nSPixelSzW
);
5855 (aRect
.*fnRect
->fnAddRight
)( nPenHalf
+ gProp
.nSPixelSzW
);
5856 SwRectGet fnGetX
= IsRightToLeft() ? fnRect
->fnGetLeft
: fnRect
->fnGetRight
;
5857 while ( pCol
->GetNext() )
5859 (aLineRect
.*fnRect
->fnSetPosX
)
5860 ( (pCol
->getFrameArea().*fnGetX
)() - nPenHalf
);
5861 if ( aRect
.Overlaps( aLineRect
) )
5862 PaintBorderLine( aRect
, aLineRect
, pPage
, &rFormatCol
.GetLineColor(),
5863 rFormatCol
.GetLineStyle() );
5864 pCol
= pCol
->GetNext();
5868 void SwPageFrame::PaintGrid( OutputDevice
const * pOut
, SwRect
const &rRect
) const
5870 if( !m_bHasGrid
|| gProp
.pSRetoucheFly
|| gProp
.pSRetoucheFly2
)
5872 SwTextGridItem
const*const pGrid(GetGridItem(this));
5873 if( !(pGrid
&& ( OUTDEV_PRINTER
!= pOut
->GetOutDevType() ?
5874 pGrid
->GetDisplayGrid() : pGrid
->GetPrintGrid() )) )
5877 const SwLayoutFrame
* pBody
= FindBodyCont();
5881 SwRect
aGrid( pBody
->getFramePrintArea() );
5882 aGrid
+= pBody
->getFrameArea().Pos();
5884 SwRect
aInter( aGrid
);
5885 aInter
.Intersection( rRect
);
5886 if( !aInter
.HasArea() )
5889 bool bGrid
= pGrid
->GetRubyTextBelow();
5890 bool bCell
= GRID_LINES_CHARS
== pGrid
->GetGridType();
5891 tools::Long nGrid
= pGrid
->GetBaseHeight();
5892 const SwDoc
* pDoc
= GetFormat()->GetDoc();
5893 tools::Long nGridWidth
= GetGridWidth(*pGrid
, *pDoc
);
5894 tools::Long nRuby
= pGrid
->GetRubyHeight();
5895 tools::Long nSum
= nGrid
+ nRuby
;
5896 const Color
*pCol
= &pGrid
->GetColor();
5898 SwTwips nRight
= aInter
.Left() + aInter
.Width();
5899 SwTwips nBottom
= aInter
.Top() + aInter
.Height();
5902 SwTwips nOrig
= aGrid
.Left() + aGrid
.Width();
5903 SwTwips nY
= nOrig
+ nSum
*
5904 ( ( nOrig
- aInter
.Left() ) / nSum
);
5905 SwRect
aTmp( Point( nY
, aInter
.Top() ),
5906 Size( 1, aInter
.Height() ) );
5907 SwTwips nX
= aGrid
.Top() + nGrid
*
5908 ( ( aInter
.Top() - aGrid
.Top() )/ nGrid
);
5909 if( nX
< aInter
.Top() )
5911 SwTwips nGridBottom
= aGrid
.Top() + aGrid
.Height();
5912 bool bLeft
= aGrid
.Top() >= aInter
.Top();
5913 bool bRight
= nGridBottom
<= nBottom
;
5914 bool bBorder
= bLeft
|| bRight
;
5915 while( nY
> nRight
)
5917 aTmp
.Pos().setX( nY
);
5921 SwTwips nPosY
= std::max( SwTwips(aInter
.Left()), nY
);
5922 SwTwips nHeight
= std::min(nRight
, SwTwips(aTmp
.Pos().X()))-nPosY
;
5927 SwRect
aVert( Point( nPosY
, nX
),
5928 Size( nHeight
, 1 ) );
5929 while( aVert
.Top() <= nBottom
)
5931 PaintBorderLine(rRect
,aVert
,this,pCol
);
5932 aVert
.Pos().AdjustY(nGrid
);
5937 SwRect
aVert( Point( nPosY
, aGrid
.Top() ),
5938 Size( nHeight
, 1 ) );
5940 PaintBorderLine(rRect
,aVert
,this,pCol
);
5943 aVert
.Pos().setY( nGridBottom
);
5944 PaintBorderLine(rRect
,aVert
,this,pCol
);
5954 SwTwips nPos
= std::max( SwTwips(aInter
.Left()), nY
);
5955 SwTwips nW
= std::min(nRight
, SwTwips(aTmp
.Pos().X())) - nPos
;
5956 SwRect
aVert( Point( nPos
, aGrid
.Top() ),
5961 PaintBorderLine(rRect
,aVert
,this,pCol
);
5964 aVert
.Pos().setY( nGridBottom
);
5965 PaintBorderLine(rRect
,aVert
,this,pCol
);
5972 while( nY
>= aInter
.Left() )
5974 aTmp
.Pos().setX( nY
);
5975 PaintBorderLine( rRect
, aTmp
, this, pCol
);
5979 SwTwips nHeight
= aTmp
.Pos().X()
5980 - std::max(SwTwips(aInter
.Left()), nY
);
5985 SwRect
aVert( Point(aTmp
.Pos().X()-nHeight
,
5986 nX
), Size( nHeight
, 1 ) );
5987 while( aVert
.Top() <= nBottom
)
5989 PaintBorderLine(rRect
,aVert
,this,pCol
);
5990 aVert
.Pos().AdjustY(nGrid
);
5995 SwRect
aVert( Point(aTmp
.Pos().X()-nHeight
,
5996 aGrid
.Top() ), Size( nHeight
, 1 ) );
5998 PaintBorderLine(rRect
,aVert
,this,pCol
);
6001 aVert
.Pos().setY( nGridBottom
);
6002 PaintBorderLine(rRect
,aVert
,this,pCol
);
6012 SwTwips nPos
= std::max( SwTwips(aInter
.Left()), nY
);
6013 SwTwips nW
= std::min(nRight
, SwTwips(aTmp
.Pos().X())) - nPos
;
6014 SwRect
aVert( Point( nPos
, aGrid
.Top() ),
6019 PaintBorderLine(rRect
,aVert
,this,pCol
);
6022 aVert
.Pos().setY( nGridBottom
);
6023 PaintBorderLine(rRect
,aVert
,this,pCol
);
6033 SwTwips nOrig
= aGrid
.Top();
6034 SwTwips nY
= nOrig
+ nSum
*( (aInter
.Top()-nOrig
)/nSum
);
6035 SwRect
aTmp( Point( aInter
.Left(), nY
),
6036 Size( aInter
.Width(), 1 ) );
6037 //for textgrid refactor
6038 SwTwips nX
= aGrid
.Left() + nGridWidth
*
6039 ( ( aInter
.Left() - aGrid
.Left() )/ nGridWidth
);
6040 if( nX
< aInter
.Left() )
6042 SwTwips nGridRight
= aGrid
.Left() + aGrid
.Width();
6043 bool bLeft
= aGrid
.Left() >= aInter
.Left();
6044 bool bRight
= nGridRight
<= nRight
;
6045 bool bBorder
= bLeft
|| bRight
;
6046 while( nY
< aInter
.Top() )
6048 aTmp
.Pos().setY(nY
);
6052 SwTwips nPosY
= std::max( aInter
.Top(), aTmp
.Pos().getY() );
6053 SwTwips nHeight
= std::min(nBottom
, nY
) - nPosY
;
6058 SwRect
aVert( Point( nX
, nPosY
),
6059 Size( 1, nHeight
) );
6060 while( aVert
.Left() <= nRight
)
6062 PaintBorderLine(rRect
,aVert
,this,pCol
);
6063 aVert
.Pos().AdjustX(nGridWidth
); //for textgrid refactor
6068 SwRect
aVert( Point( aGrid
.Left(), nPosY
),
6069 Size( 1, nHeight
) );
6071 PaintBorderLine(rRect
,aVert
,this,pCol
);
6074 aVert
.Pos().setX( nGridRight
);
6075 PaintBorderLine(rRect
,aVert
,this,pCol
);
6085 SwTwips nPos
= std::max(aInter
.Top(),aTmp
.Pos().getY());
6086 SwTwips nH
= std::min( nBottom
, nY
) - nPos
;
6087 SwRect
aVert( Point( aGrid
.Left(), nPos
),
6092 PaintBorderLine(rRect
,aVert
,this,pCol
);
6095 aVert
.Pos().setX(nGridRight
);
6096 PaintBorderLine(rRect
,aVert
,this,pCol
);
6103 while( nY
<= nBottom
)
6105 aTmp
.Pos().setY(nY
);
6106 PaintBorderLine( rRect
, aTmp
, this, pCol
);
6110 SwTwips nHeight
= std::min(nBottom
, nY
) - aTmp
.Pos().getY();
6115 SwRect
aVert( Point( nX
, aTmp
.Pos().getY() ),
6116 Size( 1, nHeight
) );
6117 while( aVert
.Left() <= nRight
)
6119 PaintBorderLine( rRect
, aVert
, this, pCol
);
6120 aVert
.Pos().setX(aVert
.Pos().getX() + nGridWidth
); //for textgrid refactor
6125 SwRect
aVert( Point( aGrid
.Left(),
6126 aTmp
.Pos().getY() ), Size( 1, nHeight
) );
6128 PaintBorderLine(rRect
,aVert
,this,pCol
);
6131 aVert
.Pos().setX(nGridRight
);
6132 PaintBorderLine(rRect
,aVert
,this,pCol
);
6142 SwTwips nPos
= std::max(aInter
.Top(),aTmp
.Pos().Y());
6143 SwTwips nH
= std::min( nBottom
, nY
) - nPos
;
6144 SwRect
aVert( Point( aGrid
.Left(), nPos
),
6149 PaintBorderLine(rRect
,aVert
,this,pCol
);
6152 aVert
.Pos().setX(nGridRight
);
6153 PaintBorderLine(rRect
,aVert
,this,pCol
);
6164 * Paint margin area of a page
6166 * OD 20.11.2002 for #104598#:
6167 * implement paint of margin area; margin area will be painted for a
6168 * view shell with a window and if the document is not in online layout.
6170 * @param _rOutputRect
6171 * input parameter - constant instance reference of the rectangle, for
6172 * which an output has to be generated.
6174 * @param _pViewShell
6175 * input parameter - instance of the view shell, on which the output
6176 * has to be generated.
6178 void SwPageFrame::PaintMarginArea( const SwRect
& _rOutputRect
,
6179 SwViewShell
const * _pViewShell
) const
6181 if ( !_pViewShell
->GetWin() || _pViewShell
->GetViewOptions()->getBrowseMode() )
6184 // Simplified paint with DrawingLayer FillStyle
6185 SwRect aPgRect
= getFrameArea();
6186 aPgRect
.Intersection_( _rOutputRect
);
6188 if(!aPgRect
.IsEmpty())
6190 OutputDevice
*pOut
= _pViewShell
->GetOut();
6192 if(pOut
->GetFillColor() != aGlobalRetoucheColor
)
6194 pOut
->SetFillColor(aGlobalRetoucheColor
);
6197 pOut
->DrawRect(aPgRect
.SVRect());
6201 const sal_Int8
SwPageFrame::snShadowPxWidth
= 9;
6203 bool SwPageFrame::IsRightShadowNeeded() const
6205 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6206 const bool bIsLTR
= getRootFrame()->IsLeftToRightViewLayout();
6208 // We paint the right shadow if we're not in book mode
6209 // or if we've no sibling or are the last page of the "row"
6210 return !pSh
|| (!pSh
->GetViewOptions()->IsViewLayoutBookMode()) || !GetNext()
6211 || (this == Lower()) || (bIsLTR
&& OnRightPage())
6212 || (!bIsLTR
&& !OnRightPage());
6216 bool SwPageFrame::IsLeftShadowNeeded() const
6218 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6219 const bool bIsLTR
= getRootFrame()->IsLeftToRightViewLayout();
6221 // We paint the left shadow if we're not in book mode
6222 // or if we've no sibling or are the last page of the "row"
6223 return !pSh
|| (!pSh
->GetViewOptions()->IsViewLayoutBookMode()) || !GetPrev()
6224 || (bIsLTR
&& !OnRightPage())
6225 || (!bIsLTR
&& OnRightPage());
6229 * Determine rectangle for bottom page shadow
6232 /*static*/ void SwPageFrame::GetHorizontalShadowRect( const SwRect
& _rPageRect
,
6233 const SwViewShell
* _pViewShell
,
6234 OutputDevice
const * pRenderContext
,
6235 SwRect
& _orHorizontalShadowRect
,
6236 bool bPaintLeftShadow
,
6237 bool bPaintRightShadow
,
6238 bool bRightSidebar
)
6240 const SwPostItMgr
*pMgr
= _pViewShell
->GetPostItMgr();
6241 SwRect
aAlignedPageRect( _rPageRect
);
6242 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, pRenderContext
);
6243 SwRect
aPagePxRect(pRenderContext
->LogicToPixel( aAlignedPageRect
.SVRect() ));
6245 tools::Long lShadowAdjustment
= snShadowPxWidth
- 1; // TODO: extract this
6247 _orHorizontalShadowRect
.Chg(
6248 Point( aPagePxRect
.Left() + (bPaintLeftShadow
? lShadowAdjustment
: 0), 0 ),
6249 Size( aPagePxRect
.Width() - ( (bPaintLeftShadow
? lShadowAdjustment
: 0) + (bPaintRightShadow
? lShadowAdjustment
: 0) ),
6250 snShadowPxWidth
) );
6252 if(pMgr
&& pMgr
->ShowNotes() && pMgr
->HasNotes())
6254 // Notes are displayed, we've to extend borders
6255 SwTwips aSidebarTotalWidth
= pMgr
->GetSidebarWidth(true) + pMgr
->GetSidebarBorderWidth(true);
6257 _orHorizontalShadowRect
.AddRight( aSidebarTotalWidth
);
6259 _orHorizontalShadowRect
.AddLeft( - aSidebarTotalWidth
);
6265 enum PaintArea
{LEFT
, RIGHT
, TOP
, BOTTOM
};
6269 #define BORDER_TILE_SIZE 512
6271 /// Wrapper around pOut->DrawBitmapEx.
6272 static void lcl_paintBitmapExToRect(vcl::RenderContext
*pOut
, const Point
& aPoint
, const Size
& aSize
, const BitmapEx
& rBitmapEx
, PaintArea eArea
)
6274 if(!comphelper::LibreOfficeKit::isActive())
6276 // The problem is that if we get called multiple times and the color is
6277 // partly transparent, then the result will get darker and darker. To avoid
6278 // this, always paint the background color before doing the real paint.
6279 tools::Rectangle
aRect(aPoint
, aSize
);
6281 if (!aRect
.IsEmpty())
6285 case LEFT
: aRect
.SetLeft( aRect
.Right() - 1 ); break;
6286 case RIGHT
: aRect
.SetRight( aRect
.Left() + 1 ); break;
6287 case TOP
: aRect
.SetTop( aRect
.Bottom() - 1 ); break;
6288 case BOTTOM
: aRect
.SetBottom( aRect
.Top() + 1 ); break;
6292 pOut
->SetFillColor(SwViewOption::GetCurrentViewOptions().GetAppBackgroundColor());
6293 pOut
->SetLineColor();
6294 pOut
->DrawRect(pOut
->PixelToLogic(aRect
));
6297 // Tiled render if necessary
6298 tools::Rectangle
aComplete(aPoint
, aSize
);
6299 Size
aTileSize(BORDER_TILE_SIZE
, BORDER_TILE_SIZE
);
6301 tools::Long iterX
= eArea
!= RIGHT
&& eArea
!= LEFT
? BORDER_TILE_SIZE
: 0;
6302 tools::Long iterY
= eArea
== RIGHT
|| eArea
== LEFT
? BORDER_TILE_SIZE
: 0;
6304 for (tools::Rectangle
aTile(aPoint
, aTileSize
); true; aTile
.Move(iterX
, iterY
))
6306 tools::Rectangle aRender
= aComplete
.GetIntersection(aTile
);
6307 if (aRender
.IsEmpty())
6309 pOut
->DrawBitmapEx(pOut
->PixelToLogic(aRender
.TopLeft()),
6310 pOut
->PixelToLogic(aRender
.GetSize()),
6311 Point(0, 0), aRender
.GetSize(),
6318 * Paint page border and shadow
6321 * implement paint of page border and shadow
6323 /*static*/ void SwPageFrame::PaintBorderAndShadow( const SwRect
& _rPageRect
,
6324 const SwViewShell
* _pViewShell
,
6325 bool bPaintLeftShadow
,
6326 bool bPaintRightShadow
,
6327 bool bRightSidebar
)
6329 // No shadow in prefs
6330 if (!_pViewShell
->GetViewOptions()->IsShadow())
6333 // #i16816# tagged pdf support
6334 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *_pViewShell
->GetOut() );
6336 static vcl::DeleteOnDeinit
<drawinglayer::primitive2d::DiscreteShadow
> shadowMaskObj(
6337 vcl::bitmap::loadFromName(BMP_PAGE_SHADOW_MASK
,
6338 ImageLoadFlags::IgnoreDarkTheme
| ImageLoadFlags::IgnoreScalingFactor
));
6340 drawinglayer::primitive2d::DiscreteShadow
& shadowMask
= *shadowMaskObj
.get();
6341 static vcl::DeleteOnDeinit
< BitmapEx
> aPageTopRightShadowObj
{};
6342 static vcl::DeleteOnDeinit
< BitmapEx
> aPageBottomRightShadowObj
{};
6343 static vcl::DeleteOnDeinit
< BitmapEx
> aPageBottomLeftShadowObj
{};
6344 static vcl::DeleteOnDeinit
< BitmapEx
> aPageBottomShadowBaseObj
{};
6345 static vcl::DeleteOnDeinit
< BitmapEx
> aPageRightShadowBaseObj
{};
6346 static vcl::DeleteOnDeinit
< BitmapEx
> aPageTopShadowBaseObj
{};
6347 static vcl::DeleteOnDeinit
< BitmapEx
> aPageTopLeftShadowObj
{};
6348 static vcl::DeleteOnDeinit
< BitmapEx
> aPageLeftShadowBaseObj
{};
6349 BitmapEx
& aPageTopRightShadow
= *aPageTopRightShadowObj
.get();
6350 BitmapEx
& aPageBottomRightShadow
= *aPageBottomRightShadowObj
.get();
6351 BitmapEx
& aPageBottomLeftShadow
= *aPageBottomLeftShadowObj
.get();
6352 BitmapEx
& aPageBottomShadow
= *aPageBottomShadowBaseObj
.get();
6353 BitmapEx
& aPageRightShadow
= *aPageRightShadowBaseObj
.get();
6354 BitmapEx
& aPageTopShadow
= *aPageTopShadowBaseObj
.get();
6355 BitmapEx
& aPageTopLeftShadow
= *aPageTopLeftShadowObj
.get();
6356 BitmapEx
& aPageLeftShadow
= *aPageLeftShadowBaseObj
.get();
6357 static Color
aShadowColor( COL_AUTO
);
6359 SwRect
aAlignedPageRect( _rPageRect
);
6360 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, _pViewShell
->GetOut() );
6361 SwRect
aPagePxRect(_pViewShell
->GetOut()->LogicToPixel( aAlignedPageRect
.SVRect() ));
6363 if (aShadowColor
!= _pViewShell
->GetViewOptions()->GetShadowColor())
6365 aShadowColor
= _pViewShell
->GetViewOptions()->GetShadowColor();
6367 AlphaMask
aMask( shadowMask
.getBottomRight().GetBitmap() );
6368 Bitmap
aFilledSquare(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6369 aFilledSquare
.Erase( aShadowColor
);
6370 aPageBottomRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6372 aMask
= AlphaMask( shadowMask
.getBottomLeft().GetBitmap() );
6373 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6374 aFilledSquare
.Erase( aShadowColor
);
6375 aPageBottomLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6377 aMask
= AlphaMask( shadowMask
.getBottom().GetBitmap() );
6378 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6379 aFilledSquare
.Erase( aShadowColor
);
6380 aPageBottomShadow
= BitmapEx( aFilledSquare
, aMask
);
6382 aMask
= AlphaMask( shadowMask
.getTop().GetBitmap() );
6383 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6384 aFilledSquare
.Erase( aShadowColor
);
6385 aPageTopShadow
= BitmapEx( aFilledSquare
, aMask
);
6387 aMask
= AlphaMask( shadowMask
.getTopRight().GetBitmap() );
6388 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6389 aFilledSquare
.Erase( aShadowColor
);
6390 aPageTopRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6392 aMask
= AlphaMask( shadowMask
.getRight().GetBitmap() );
6393 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6394 aFilledSquare
.Erase( aShadowColor
);
6395 aPageRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6397 aMask
= AlphaMask( shadowMask
.getTopLeft().GetBitmap() );
6398 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6399 aFilledSquare
.Erase( aShadowColor
);
6400 aPageTopLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6402 aMask
= AlphaMask( shadowMask
.getLeft().GetBitmap() );
6403 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6404 aFilledSquare
.Erase( aShadowColor
);
6405 aPageLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6409 OutputDevice
*pOut
= _pViewShell
->GetOut();
6411 SwPageFrame::GetHorizontalShadowRect( _rPageRect
, _pViewShell
, pOut
, aPaintRect
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
6413 // Right shadow & corners
6414 if ( bPaintRightShadow
)
6416 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( aPaintRect
.Right(), aPagePxRect
.Bottom() + 1 - (aPageBottomRightShadow
.GetSizePixel().Height() - snShadowPxWidth
) ) ),
6417 aPageBottomRightShadow
);
6418 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( aPaintRect
.Right(), aPagePxRect
.Top() - snShadowPxWidth
) ),
6419 aPageTopRightShadow
);
6421 if (aPagePxRect
.Height() > 2 * snShadowPxWidth
)
6423 const tools::Long nWidth
= aPageRightShadow
.GetSizePixel().Width();
6424 const tools::Long nHeight
= aPagePxRect
.Height() - 2 * (snShadowPxWidth
- 1);
6425 if (aPageRightShadow
.GetSizePixel().Height() < BORDER_TILE_SIZE
)
6426 aPageRightShadow
.Scale(Size(nWidth
, BORDER_TILE_SIZE
), BmpScaleFlag::Fast
);
6428 lcl_paintBitmapExToRect(pOut
,
6429 Point(aPaintRect
.Right() + snShadowPxWidth
, aPagePxRect
.Top() + snShadowPxWidth
- 1),
6430 Size(nWidth
, nHeight
),
6431 aPageRightShadow
, RIGHT
);
6435 // Left shadows and corners
6436 if(bPaintLeftShadow
)
6438 const tools::Long lLeft
= aPaintRect
.Left() - aPageBottomLeftShadow
.GetSizePixel().Width();
6439 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( lLeft
,
6440 aPagePxRect
.Bottom() + 1 + snShadowPxWidth
- aPageBottomLeftShadow
.GetSizePixel().Height() ) ), aPageBottomLeftShadow
);
6441 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( lLeft
, aPagePxRect
.Top() - snShadowPxWidth
) ), aPageTopLeftShadow
);
6442 if (aPagePxRect
.Height() > 2 * snShadowPxWidth
)
6444 const tools::Long nWidth
= aPageLeftShadow
.GetSizePixel().Width();
6445 const tools::Long nHeight
= aPagePxRect
.Height() - 2 * (snShadowPxWidth
- 1);
6446 if (aPageLeftShadow
.GetSizePixel().Height() < BORDER_TILE_SIZE
)
6447 aPageLeftShadow
.Scale(Size(nWidth
, BORDER_TILE_SIZE
), BmpScaleFlag::Fast
);
6449 lcl_paintBitmapExToRect(pOut
,
6450 Point(lLeft
, aPagePxRect
.Top() + snShadowPxWidth
- 1),
6451 Size(nWidth
, nHeight
),
6452 aPageLeftShadow
, LEFT
);
6457 const tools::Long nBottomHeight
= aPageBottomShadow
.GetSizePixel().Height();
6458 if (aPageBottomShadow
.GetSizePixel().Width() < BORDER_TILE_SIZE
)
6459 aPageBottomShadow
.Scale(Size(BORDER_TILE_SIZE
, nBottomHeight
), BmpScaleFlag::Fast
);
6461 lcl_paintBitmapExToRect(pOut
,
6462 Point(aPaintRect
.Left(), aPagePxRect
.Bottom() + 2),
6463 Size(aPaintRect
.Width(), nBottomHeight
),
6464 aPageBottomShadow
, BOTTOM
);
6467 const tools::Long nTopHeight
= aPageTopShadow
.GetSizePixel().Height();
6468 if (aPageTopShadow
.GetSizePixel().Width() < BORDER_TILE_SIZE
)
6469 aPageTopShadow
.Scale(Size(BORDER_TILE_SIZE
, nTopHeight
), BmpScaleFlag::Fast
);
6471 lcl_paintBitmapExToRect(pOut
,
6472 Point(aPaintRect
.Left(), aPagePxRect
.Top() - snShadowPxWidth
),
6473 Size(aPaintRect
.Width(), nTopHeight
),
6474 aPageTopShadow
, TOP
);
6478 * mod #i6193# paint sidebar for notes
6479 * IMPORTANT: if you change the rects here, also change SwPostItMgr::ScrollbarHit
6481 /*static*/void SwPageFrame::PaintNotesSidebar(const SwRect
& _rPageRect
, SwViewShell
* _pViewShell
, sal_uInt16 nPageNum
, bool bRight
)
6483 //TODO: cut out scrollbar area and arrows out of sidepane rect, otherwise it could flicker when pressing arrow buttons
6487 SwRect
aPageRect( _rPageRect
);
6488 SwAlignRect( aPageRect
, _pViewShell
, _pViewShell
->GetOut() );
6490 const SwPostItMgr
*pMgr
= _pViewShell
->GetPostItMgr();
6491 if (!(pMgr
&& pMgr
->ShowNotes() && pMgr
->HasNotes())) // do not show anything in print preview
6494 sal_Int32 nScrollerHeight
= pMgr
->GetSidebarScrollerHeight();
6495 const tools::Rectangle
&aVisRect
= _pViewShell
->VisArea().SVRect();
6496 //draw border and sidepane
6497 _pViewShell
->GetOut()->SetLineColor();
6500 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetObjectBoundariesColor());
6501 _pViewShell
->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect
.Left()-pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarBorderWidth(),aPageRect
.Height()))) ;
6502 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6503 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6505 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetSectionBoundColor());
6506 _pViewShell
->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect
.Left()-pMgr
->GetSidebarWidth()-pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarWidth(),aPageRect
.Height()))) ;
6510 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetObjectBoundariesColor());
6511 SwRect
aSidebarBorder(aPageRect
.TopRight(),Size(pMgr
->GetSidebarBorderWidth(),aPageRect
.Height()));
6512 _pViewShell
->GetOut()->DrawRect(aSidebarBorder
.SVRect());
6513 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6514 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6516 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetSectionBoundColor());
6517 SwRect
aSidebar(Point(aPageRect
.Right()+pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarWidth(),aPageRect
.Height()));
6518 _pViewShell
->GetOut()->DrawRect(aSidebar
.SVRect());
6520 if (!pMgr
->ShowScrollbar(nPageNum
))
6523 // draw scrollbar area and arrows
6526 aPointBottom
= !bRight
? Point(aPageRect
.Left() - pMgr
->GetSidebarWidth() - pMgr
->GetSidebarBorderWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- _pViewShell
->GetOut()->PixelToLogic(Size(0,2+pMgr
->GetSidebarScrollerHeight())).Height()) :
6527 Point(aPageRect
.Right() + pMgr
->GetSidebarBorderWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- _pViewShell
->GetOut()->PixelToLogic(Size(0,2+pMgr
->GetSidebarScrollerHeight())).Height());
6528 aPointTop
= !bRight
? Point(aPageRect
.Left() - pMgr
->GetSidebarWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + _pViewShell
->GetOut()->PixelToLogic(Size(0,2)).Height()) :
6529 Point(aPageRect
.Right() + pMgr
->GetSidebarBorderWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + _pViewShell
->GetOut()->PixelToLogic(Size(0,2)).Height());
6530 Size
aSize(pMgr
->GetSidebarWidth() - _pViewShell
->GetOut()->PixelToLogic(Size(4,0)).Width(), _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()) ;
6531 tools::Rectangle
aRectBottom(aPointBottom
,aSize
);
6532 tools::Rectangle
aRectTop(aPointTop
,aSize
);
6534 if (aRectBottom
.Overlaps(aVisRect
))
6537 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6539 _pViewShell
->GetOut()->SetLineColor(COL_WHITE
);
6540 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6544 _pViewShell
->GetOut()->SetLineColor(COL_BLACK
);
6545 _pViewShell
->GetOut()->SetFillColor(COL_LIGHTGRAY
);
6547 _pViewShell
->GetOut()->DrawRect(aRectBottom
);
6548 _pViewShell
->GetOut()->DrawLine(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3,0), aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3 , _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()));
6550 _pViewShell
->GetOut()->SetLineColor();
6551 Point
aMiddleFirst(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/6,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6552 Point
aMiddleSecond(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3*2,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6553 PaintNotesSidebarArrows(aMiddleFirst
,aMiddleSecond
,_pViewShell
,pMgr
->GetArrowColor(KEY_PAGEUP
,nPageNum
), pMgr
->GetArrowColor(KEY_PAGEDOWN
,nPageNum
));
6555 if (!aRectTop
.Overlaps(aVisRect
))
6558 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6560 _pViewShell
->GetOut()->SetLineColor(COL_WHITE
);
6561 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6565 _pViewShell
->GetOut()->SetLineColor(COL_BLACK
);
6566 _pViewShell
->GetOut()->SetFillColor(COL_LIGHTGRAY
);
6568 _pViewShell
->GetOut()->DrawRect(aRectTop
);
6569 _pViewShell
->GetOut()->DrawLine(aPointTop
+ Point(pMgr
->GetSidebarWidth()/3*2,0), aPointTop
+ Point(pMgr
->GetSidebarWidth()/3*2 , _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()));
6571 _pViewShell
->GetOut()->SetLineColor();
6572 Point
aMiddleFirst(aPointTop
+ Point(pMgr
->GetSidebarWidth()/3,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6573 Point
aMiddleSecond(aPointTop
+ Point(pMgr
->GetSidebarWidth()/6*5,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6574 PaintNotesSidebarArrows(aMiddleFirst
,aMiddleSecond
,_pViewShell
, pMgr
->GetArrowColor(KEY_PAGEUP
,nPageNum
), pMgr
->GetArrowColor(KEY_PAGEDOWN
,nPageNum
));
6577 /*static*/ void SwPageFrame::PaintNotesSidebarArrows(const Point
&aMiddleFirst
, const Point
&aMiddleSecond
, SwViewShell
const * _pViewShell
, const Color
& rColorUp
, const Color
& rColorDown
)
6579 tools::Polygon
aTriangleUp(3);
6580 tools::Polygon
aTriangleDown(3);
6582 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(0,_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6583 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),1);
6584 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6586 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6587 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(+3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),1);
6588 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(0,_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6590 _pViewShell
->GetOut()->SetFillColor(rColorUp
);
6591 _pViewShell
->GetOut()->DrawPolygon(aTriangleUp
);
6592 _pViewShell
->GetOut()->SetFillColor(rColorDown
);
6593 _pViewShell
->GetOut()->DrawPolygon(aTriangleDown
);
6597 * Get bound rectangle of border and shadow for repaints
6601 /*static*/ void SwPageFrame::GetBorderAndShadowBoundRect( const SwRect
& _rPageRect
,
6602 const SwViewShell
* _pViewShell
,
6603 OutputDevice
const * pRenderContext
,
6604 SwRect
& _orBorderAndShadowBoundRect
,
6610 SwRect
aAlignedPageRect( _rPageRect
);
6611 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, pRenderContext
);
6612 SwRect
aPagePxRect(pRenderContext
->LogicToPixel( aAlignedPageRect
.SVRect() ));
6613 aPagePxRect
.AddBottom( snShadowPxWidth
+ 1 );
6614 aPagePxRect
.AddTop( - snShadowPxWidth
- 1 );
6618 // Always ask for full shadow since we want a bounding rect
6619 // including at least the page frame
6620 SwPageFrame::GetHorizontalShadowRect( _rPageRect
, _pViewShell
, pRenderContext
, aTmpRect
, false, false, bRightSidebar
);
6622 if(bLeftShadow
) aPagePxRect
.Left( aTmpRect
.Left() - snShadowPxWidth
- 1);
6623 if(bRightShadow
) aPagePxRect
.Right( aTmpRect
.Right() + snShadowPxWidth
+ 1);
6625 _orBorderAndShadowBoundRect
= SwRect(pRenderContext
->PixelToLogic( aPagePxRect
.SVRect() ));
6628 SwRect
SwPageFrame::GetBoundRect(OutputDevice
const * pOutputDevice
) const
6630 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6631 SwRect
aPageRect( getFrameArea() );
6635 return SwRect( Point(0, 0), Size(0, 0) );
6638 SwPageFrame::GetBorderAndShadowBoundRect( aPageRect
, pSh
, pOutputDevice
, aResult
,
6639 IsLeftShadowNeeded(), IsRightShadowNeeded(), SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT
);
6643 /*static*/ SwTwips
SwPageFrame::GetSidebarBorderWidth( const SwViewShell
* _pViewShell
)
6645 const SwPostItMgr
* pPostItMgr
= _pViewShell
? _pViewShell
->GetPostItMgr() : nullptr;
6646 const SwTwips nRet
= pPostItMgr
&& pPostItMgr
->HasNotes() && pPostItMgr
->ShowNotes() ? pPostItMgr
->GetSidebarWidth() + pPostItMgr
->GetSidebarBorderWidth() : 0;
6650 void SwFrame::PaintBaBo( const SwRect
& rRect
, const SwPageFrame
*pPage
,
6651 const bool bOnlyTextBackground
) const
6654 pPage
= FindPageFrame();
6656 OutputDevice
*pOut
= gProp
.pSGlobalShell
->GetOut();
6658 // #i16816# tagged pdf support
6659 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
6661 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
6662 pOut
->SetLineColor();
6664 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), this );
6665 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
6667 // take care of page margin area
6668 // Note: code move from <SwFrame::PaintSwFrameBackground(..)> to new method
6669 // <SwPageFrame::Paintmargin(..)>.
6670 if ( IsPageFrame() && !bOnlyTextBackground
)
6672 static_cast<const SwPageFrame
*>(this)->PaintMarginArea( rRect
, gProp
.pSGlobalShell
);
6677 PaintSwFrameBackground( rRect
, pPage
, rAttrs
, false, true/*bLowerBorder*/, bOnlyTextBackground
);
6680 // paint border before painting background
6681 // paint grid for page frame and paint border
6682 if (!bOnlyTextBackground
)
6684 SwRect
aRect( rRect
);
6688 static_cast<const SwPageFrame
*>(this)->PaintGrid( pOut
, aRect
);
6691 PaintSwFrameShadowAndBorder(aRect
, pPage
, rAttrs
);
6697 static bool lcl_compareFillAttributes(const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& pA
, const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& pB
)
6703 return pA
->getFillAttribute() == pB
->getFillAttribute();
6706 /// Do not paint background for fly frames without a background brush by
6707 /// calling <PaintBaBo> at the page or at the fly frame its anchored
6708 void SwFrame::PaintSwFrameBackground( const SwRect
&rRect
, const SwPageFrame
*pPage
,
6709 const SwBorderAttrs
& rAttrs
,
6710 const bool bLowerMode
,
6711 const bool bLowerBorder
,
6712 const bool bOnlyTextBackground
) const
6714 // #i1837# - no paint of table background, if corresponding option is *not* set.
6715 SwViewShell
*pSh
= gProp
.pSGlobalShell
;
6717 !pSh
->GetViewOptions()->IsTable() )
6722 // nothing to do for covered table cells:
6723 if( IsCellFrame() && IsCoveredCell() )
6726 // #i16816# tagged pdf support
6727 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh
->GetOut() );
6729 const SvxBrushItem
* pItem
;
6730 // temporary background brush for a fly frame without a background brush
6731 std::unique_ptr
<SvxBrushItem
> pTmpBackBrush
;
6732 std::optional
<Color
> pCol
;
6733 SwRect aOrigBackRect
;
6734 const bool bPageFrame
= IsPageFrame();
6735 bool bLowMode
= true;
6736 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
6738 bool bBack
= GetBackgroundBrush( aFillAttributes
, pItem
, pCol
, aOrigBackRect
, bLowerMode
, /*bConsiderTextBox=*/false );
6740 // show track changes of table row
6741 if( IsRowFrame() && !getRootFrame()->IsHideRedlines() )
6743 RedlineType eType
= static_cast<const SwRowFrame
*>(this)->GetTabLine()->GetRedlineType();
6744 if ( RedlineType::Delete
== eType
|| RedlineType::Insert
== eType
)
6746 pCol
= RedlineType::Delete
== eType
? COL_AUTHOR_TABLE_DEL
: COL_AUTHOR_TABLE_INS
;
6750 else if ( IsCellFrame() && !getRootFrame()->IsHideRedlines() )
6752 RedlineType eType
= static_cast<const SwCellFrame
*>(this)->GetTabBox()->GetRedlineType();
6753 if ( RedlineType::Delete
== eType
|| RedlineType::Insert
== eType
)
6755 pCol
= RedlineType::Delete
== eType
? COL_AUTHOR_TABLE_DEL
: COL_AUTHOR_TABLE_INS
;
6760 if ( bBack
&& IsCellFrame() && !getRootFrame()->IsHideRedlines() &&
6761 // skip cell background to show the row colored according to its tracked change
6762 RedlineType::None
!= static_cast<const SwRowFrame
*>(GetUpper())->GetTabLine()->GetRedlineType() )
6767 //- Output if a separate background is used.
6768 bool bNoFlyBackground
= !gProp
.bSFlyMetafile
&& !bBack
&& IsFlyFrame();
6769 if ( bNoFlyBackground
)
6771 // Fly frame has no background.
6772 // Try to find background brush at parents, if previous call of
6773 // <GetBackgroundBrush> disabled this option with the parameter <bLowerMode>
6776 bBack
= GetBackgroundBrush( aFillAttributes
, pItem
, pCol
, aOrigBackRect
, false, /*bConsiderTextBox=*/false );
6778 // If still no background found for the fly frame, initialize the
6779 // background brush <pItem> with global retouche color and set <bBack>
6780 // to true, that fly frame will paint its background using this color.
6783 // #i6467# - on print output, pdf output and in embedded mode not editing color COL_WHITE is used
6784 // instead of the global retouche color.
6785 if ( pSh
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
6786 pSh
->GetViewOptions()->IsPDFExport() ||
6787 ( pSh
->GetDoc()->GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED
&&
6788 !pSh
->GetDoc()->GetDocShell()->IsInPlaceActive()
6792 pTmpBackBrush
.reset(new SvxBrushItem( COL_WHITE
, RES_BACKGROUND
));
6795 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(COL_WHITE
);
6799 pTmpBackBrush
.reset(new SvxBrushItem( aGlobalRetoucheColor
, RES_BACKGROUND
));
6802 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(aGlobalRetoucheColor
);
6805 pItem
= pTmpBackBrush
.get();
6810 SwRect
aPaintRect( getFrameArea() );
6811 if( IsTextFrame() || IsSctFrame() )
6812 aPaintRect
= UnionFrame( true );
6814 // bOnlyTextBackground means background that's on top of background shapes,
6815 // this includes both text and cell frames.
6816 if ( (!bOnlyTextBackground
|| IsTextFrame() || IsCellFrame()) && aPaintRect
.Overlaps( rRect
) )
6818 if ( bBack
|| bPageFrame
|| !bLowerMode
)
6820 const bool bBrowse
= pSh
->GetViewOptions()->getBrowseMode();
6822 if ( (bPageFrame
&& bBrowse
) ||
6823 (IsTextFrame() && getFramePrintArea().SSize() == getFrameArea().SSize()) )
6825 aRect
= getFrameArea();
6826 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
6830 if (bPageFrame
&& GetAttrSet()->GetItem
<SfxBoolItem
>(RES_BACKGROUND_FULL_SIZE
)->GetValue())
6832 aRect
= getFrameArea();
6833 ::SwAlignRect(aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut());
6837 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, false, gProp
);
6840 if ( (IsTextFrame() || IsTabFrame()) && GetPrev() )
6842 if ( GetPrev()->GetAttrSet()->GetBackground() == GetAttrSet()->GetBackground() &&
6843 lcl_compareFillAttributes(GetPrev()->getSdrAllFillAttributesHelper(), getSdrAllFillAttributesHelper()))
6845 aRect
.Top( getFrameArea().Top() );
6849 aRect
.Intersection( rRect
);
6851 OutputDevice
*pOut
= pSh
->GetOut();
6853 if ( aRect
.HasArea() )
6855 std::unique_ptr
<SvxBrushItem
> pNewItem
;
6859 pNewItem
.reset(new SvxBrushItem( *pCol
, RES_BACKGROUND
));
6860 pItem
= pNewItem
.get();
6861 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(*pCol
);
6864 SwRegionRects
aRegion( aRect
);
6865 basegfx::B2DPolygon aB2DPolygon
{tools::Polygon(aRect
.SVRect()).getB2DPolygon()};
6866 basegfx::utils::B2DClipState aClipState
{basegfx::B2DPolyPolygon(aB2DPolygon
)};
6867 if (pPage
->GetSortedObjs() &&
6868 pSh
->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
))
6870 ::lcl_SubtractFlys( this, pPage
, aRect
, aRegion
, aClipState
, gProp
);
6873 // Determine, if background transparency
6874 // have to be considered for drawing.
6875 // Status Quo: background transparency have to be
6876 // considered for fly frames
6877 const bool bConsiderBackgroundTransparency
= IsFlyFrame();
6880 // #i125189# We are also done when the new DrawingLayer FillAttributes are used
6881 // or the FillStyle is set (different from drawing::FillStyle_NONE)
6882 if (aFillAttributes
)
6884 if(aFillAttributes
->isUsed())
6886 // check if really something is painted
6887 bDone
= DrawFillAttributes(aFillAttributes
, aOrigBackRect
, aRegion
, aClipState
, *pOut
);
6892 // if not, still a FillStyle could be set but the transparency is at 100%,
6893 // thus need to check the model data itself for FillStyle (do not rely on
6894 // SdrAllFillAttributesHelper since it already contains optimized information,
6895 // e.g. transparency leads to no fill)
6896 const drawing::FillStyle
eFillStyle(GetAttrSet()->Get(XATTR_FILLSTYLE
).GetValue());
6898 if(drawing::FillStyle_NONE
!= eFillStyle
)
6907 for (size_t i
= 0; i
< aRegion
.size(); ++i
)
6909 if (1 < aRegion
.size())
6911 ::SwAlignRect( aRegion
[i
], gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
6912 if( !aRegion
[i
].HasArea() )
6915 // add 6th parameter to indicate, if background transparency have to be considered
6916 // Set missing 5th parameter to the default value GRFNUM_NO
6917 // - see declaration in /core/inc/frmtool.hxx.
6924 bConsiderBackgroundTransparency
);
6930 bLowMode
= bLowerMode
;
6933 // delete temporary background brush.
6934 pTmpBackBrush
.reset();
6936 //Now process lower and his neighbour.
6937 //We end this as soon as a Frame leaves the chain and therefore is not a lower
6939 const SwFrame
*pFrame
= GetLower();
6944 SwRect
aRect( GetPaintArea() );
6945 aRect
.Intersection_( rRect
);
6946 SwRect
aBorderRect( aRect
);
6947 SwShortCut
aShortCut( *pFrame
, aBorderRect
);
6949 { if ( gProp
.pSProgress
)
6950 SfxProgress::Reschedule();
6952 aFrameRect
= pFrame
->GetPaintArea();
6953 if ( aFrameRect
.Overlaps( aBorderRect
) )
6955 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFrame
);
6956 const SwBorderAttrs
&rTmpAttrs
= *aAccess
.Get();
6957 if ( ( pFrame
->IsLayoutFrame() && bLowerBorder
) || aFrameRect
.Overlaps( aRect
) )
6959 pFrame
->PaintSwFrameBackground( aRect
, pPage
, rTmpAttrs
, bLowMode
,
6960 bLowerBorder
, bOnlyTextBackground
);
6965 pFrame
->PaintSwFrameShadowAndBorder( aBorderRect
, pPage
, rTmpAttrs
);
6968 pFrame
= pFrame
->GetNext();
6969 } while ( pFrame
&& pFrame
->GetUpper() == this &&
6970 !aShortCut
.Stop( aFrameRect
) );
6973 /// Refreshes all subsidiary lines of a page.
6974 void SwPageFrame::RefreshSubsidiary( const SwRect
&rRect
) const
6976 if ( !(isSubsidiaryLinesEnabled() || isTableBoundariesEnabled()
6977 || isSubsidiaryLinesForSectionsEnabled() || isSubsidiaryLinesFlysEnabled()) )
6980 if ( !rRect
.HasArea() )
6983 //During paint using the root, the array is controlled from there.
6984 //Otherwise we'll handle it for our self.
6985 bool bDelSubs
= false;
6986 if ( !gProp
.pSSubsLines
)
6988 gProp
.pSSubsLines
.reset(new SwSubsRects
);
6989 // create container for special subsidiary lines
6990 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
6994 RefreshLaySubsidiary( this, rRect
);
6998 // paint special subsidiary lines and delete its container
6999 gProp
.pSSpecSubsLines
->PaintSubsidiary( gProp
.pSGlobalShell
->GetOut(), nullptr, gProp
);
7000 gProp
.pSSpecSubsLines
.reset();
7002 gProp
.pSSubsLines
->PaintSubsidiary(gProp
.pSGlobalShell
->GetOut(), gProp
.pSLines
.get(), gProp
);
7003 gProp
.pSSubsLines
.reset();
7007 void SwLayoutFrame::RefreshLaySubsidiary( const SwPageFrame
*pPage
,
7008 const SwRect
&rRect
) const
7010 const bool bSubsOpt
= isSubsidiaryLinesEnabled() || isSubsidiaryLinesForSectionsEnabled();
7012 PaintSubsidiaryLines( pPage
, rRect
);
7014 const SwFrame
*pLow
= Lower();
7017 SwShortCut
aShortCut( *pLow
, rRect
);
7018 while( pLow
&& !aShortCut
.Stop( pLow
->getFrameArea() ) )
7020 if ( pLow
->getFrameArea().Overlaps( rRect
) && pLow
->getFrameArea().HasArea() )
7022 if ( pLow
->IsLayoutFrame() )
7023 static_cast<const SwLayoutFrame
*>(pLow
)->RefreshLaySubsidiary( pPage
, rRect
);
7024 else if ( pLow
->GetDrawObjs() )
7026 const SwSortedObjs
& rObjs
= *(pLow
->GetDrawObjs());
7027 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
7029 if ( pPage
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
7030 pAnchoredObj
->GetDrawObj()->GetLayer() ) )
7031 if (auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7033 if ( pFly
->IsFlyInContentFrame() && pFly
->getFrameArea().Overlaps( rRect
) )
7035 if ( !pFly
->Lower() || !pFly
->Lower()->IsNoTextFrame() ||
7036 !static_cast<const SwNoTextFrame
*>(pFly
->Lower())->HasAnimation())
7037 pFly
->RefreshLaySubsidiary( pPage
, rRect
);
7043 pLow
= pLow
->GetNext();
7048 * Subsidiary lines to paint the PrtAreas
7049 * Only the LayoutFrames which directly contain Content
7050 * Paints the desired line and pays attention to not overpaint any flys
7052 static void lcl_RefreshLine( const SwLayoutFrame
*pLay
,
7053 const SwPageFrame
*pPage
,
7056 const SubColFlags nSubColor
,
7057 SwLineRects
* pSubsLines
)
7059 //In which direction do we loop? Can only be horizontal or vertical.
7060 OSL_ENSURE( ((rP1
.X() == rP2
.X()) || (rP1
.Y() == rP2
.Y())),
7061 "Sloped subsidiary lines are not allowed." );
7063 const bool bHori
= rP1
.Y() == rP2
.Y();
7065 // use pointers to member function in order to unify flow
7066 typedef tools::Long (Point::*pmfPtGet
)() const;
7067 typedef void (Point::*pmfPtSet
)(tools::Long
);
7068 const pmfPtGet pDirPtX
= &Point::X
;
7069 const pmfPtGet pDirPtY
= &Point::Y
;
7070 const pmfPtGet pDirPt
= bHori
? pDirPtX
: pDirPtY
;
7071 const pmfPtSet pDirPtSetX
= &Point::setX
;
7072 const pmfPtSet pDirPtSetY
= &Point::setY
;
7073 const pmfPtSet pDirPtSet
= bHori
? pDirPtSetX
: pDirPtSetY
;
7078 while ( (aP1
.*pDirPt
)() < (aP2
.*pDirPt
)() )
7080 //If the starting point lies in a fly, it is directly set behind the
7082 //The end point moves to the start if the end point lies in a fly or we
7083 //have a fly between starting point and end point.
7084 // In this way, every position is output one by one.
7086 //If I'm a fly I'll only avoid those flys which are places 'above' me;
7087 //this means those who are behind me in the array.
7088 //Even if I'm inside a fly or inside a fly inside a fly a.s.o I won't
7089 //avoid any of those flys.
7090 SwOrderIter
aIter( pPage
);
7091 const SwFlyFrame
*pMyFly
= pLay
->FindFlyFrame();
7094 aIter
.Current( pMyFly
->GetVirtDrawObj() );
7095 while ( nullptr != (pMyFly
= pMyFly
->GetAnchorFrame()->FindFlyFrame()) )
7097 if ( aIter()->GetOrdNum() > pMyFly
->GetVirtDrawObj()->GetOrdNum() )
7098 aIter
.Current( pMyFly
->GetVirtDrawObj() );
7106 const SwVirtFlyDrawObj
*pObj
= static_cast<const SwVirtFlyDrawObj
*>(aIter());
7107 const SwFlyFrame
*pFly
= pObj
? pObj
->GetFlyFrame() : nullptr;
7109 //I certainly won't avoid myself, even if I'm placed _inside_ the
7110 //fly I won't avoid it.
7111 if ( !pFly
|| (pFly
== pLay
|| pFly
->IsAnLower( pLay
)) )
7117 // do *not* consider fly frames with a transparent background.
7118 // do *not* consider fly frame, which belongs to an invisible layer
7119 if ( pFly
->IsBackgroundTransparent() ||
7120 !pFly
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( pObj
->GetLayer() ) )
7126 //Is the Obj placed on the line
7127 const tools::Long nP1OthPt
= !bHori
? rP1
.X() : rP1
.Y();
7128 const tools::Rectangle
&rBound
= pObj
->GetCurrentBoundRect();
7129 const Point
aDrPt( rBound
.TopLeft() );
7130 const tools::Long nDrOthPt
= !bHori
? aDrPt
.X() : aDrPt
.Y();
7131 const Size
aDrSz( rBound
.GetSize() );
7132 const tools::Long nDrOthSz
= !bHori
? aDrSz
.Width() : aDrSz
.Height();
7134 if ( nP1OthPt
>= nDrOthPt
&& nP1OthPt
<= nDrOthPt
+ nDrOthSz
)
7136 const tools::Long nDrDirPt
= bHori
? aDrPt
.X() : aDrPt
.Y();
7137 const tools::Long nDrDirSz
= bHori
? aDrSz
.Width() : aDrSz
.Height();
7139 if ( (aP1
.*pDirPt
)() >= nDrDirPt
&& (aP1
.*pDirPt
)() <= nDrDirPt
+ nDrDirSz
)
7140 (aP1
.*pDirPtSet
)( nDrDirPt
+ nDrDirSz
);
7142 if ( (aP2
.*pDirPt
)() >= nDrDirPt
&& (aP1
.*pDirPt
)() < (nDrDirPt
- 1) )
7143 (aP2
.*pDirPtSet
)( nDrDirPt
- 1 );
7148 if ( (aP1
.*pDirPt
)() < (aP2
.*pDirPt
)() )
7150 SwRect
aRect( aP1
, aP2
);
7151 // use parameter <pSubsLines> instead of global variable <gProp.pSSubsLines>.
7152 pSubsLines
->AddLineRect( aRect
, nullptr, SvxBorderLineStyle::SOLID
,
7153 nullptr, nSubColor
, gProp
);
7156 (aP1
.*pDirPtSet
)( (aP1
.*pDirPt
)() + 1 );
7161 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreatePageAreaDelimiterPrimitives(
7162 const SwRect
& rRect
)
7164 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 4 );
7166 basegfx::BColor aLineColor
= SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
7167 double nLineLength
= 200.0; // in Twips
7169 Point aPoints
[] = { rRect
.TopLeft(), rRect
.TopRight(), rRect
.BottomRight(), rRect
.BottomLeft() };
7170 double const aXOffDirs
[] = { -1.0, 1.0, 1.0, -1.0 };
7171 double const aYOffDirs
[] = { -1.0, -1.0, 1.0, 1.0 };
7173 // Actually loop over the corners to create the two lines
7174 for ( int i
= 0; i
< 4; i
++ )
7176 basegfx::B2DVector
aHorizVector( aXOffDirs
[i
], 0.0 );
7177 basegfx::B2DVector
aVertVector( 0.0, aYOffDirs
[i
] );
7179 basegfx::B2DPoint
aBPoint( aPoints
[i
].getX(), aPoints
[i
].getY() );
7181 basegfx::B2DPolygon aPolygon
;
7182 aPolygon
.append( aBPoint
+ aHorizVector
* nLineLength
);
7183 aPolygon
.append( aBPoint
);
7184 aPolygon
.append( aBPoint
+ aVertVector
* nLineLength
);
7186 aSeq
[i
] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
7187 std::move(aPolygon
), aLineColor
);
7193 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateRectangleDelimiterPrimitives (
7194 const SwRect
& rRect
)
7196 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 1 );
7197 basegfx::BColor aLineColor
= SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
7199 basegfx::B2DPolygon aPolygon
;
7200 aPolygon
.append( basegfx::B2DPoint( rRect
.Left(), rRect
.Top() ) );
7201 aPolygon
.append( basegfx::B2DPoint( rRect
.Right(), rRect
.Top() ) );
7202 aPolygon
.append( basegfx::B2DPoint( rRect
.Right(), rRect
.Bottom() ) );
7203 aPolygon
.append( basegfx::B2DPoint( rRect
.Left(), rRect
.Bottom() ) );
7204 aPolygon
.setClosed( true );
7206 aSeq
[0] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
7207 std::move(aPolygon
), aLineColor
);
7212 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateColumnAreaDelimiterPrimitives(
7213 const SwRect
& rRect
)
7215 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 4 );
7217 basegfx::BColor aLineColor
= SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
7218 double nLineLength
= 100.0; // in Twips
7220 Point aPoints
[] = { rRect
.TopLeft(), rRect
.TopRight(), rRect
.BottomRight(), rRect
.BottomLeft() };
7221 double const aXOffDirs
[] = { 1.0, -1.0, -1.0, 1.0 };
7222 double const aYOffDirs
[] = { 1.0, 1.0, -1.0, -1.0 };
7224 // Actually loop over the corners to create the two lines
7225 for ( int i
= 0; i
< 4; i
++ )
7227 basegfx::B2DVector
aHorizVector( aXOffDirs
[i
], 0.0 );
7228 basegfx::B2DVector
aVertVector( 0.0, aYOffDirs
[i
] );
7230 basegfx::B2DPoint
aBPoint( aPoints
[i
].getX(), aPoints
[i
].getY() );
7232 basegfx::B2DPolygon aPolygon
;
7233 aPolygon
.append( aBPoint
+ aHorizVector
* nLineLength
);
7234 aPolygon
.append( aBPoint
);
7235 aPolygon
.append( aBPoint
+ aVertVector
* nLineLength
);
7237 aSeq
[i
] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
7238 std::move(aPolygon
), aLineColor
);
7244 void SwPageFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7245 const SwRect
& ) const
7247 if (!gProp
.pSGlobalShell
->GetViewOptions()->IsDocBoundaries())
7250 if ( gProp
.pSGlobalShell
->IsHeaderFooterEdit() )
7253 const SwFrame
* pLay
= Lower();
7254 const SwFrame
* pFootnoteCont
= nullptr;
7255 const SwFrame
* pPageBody
= nullptr;
7256 while ( pLay
&& !( pFootnoteCont
&& pPageBody
) )
7258 if ( pLay
->IsFootnoteContFrame( ) )
7259 pFootnoteCont
= pLay
;
7260 if ( pLay
->IsBodyFrame() )
7262 pLay
= pLay
->GetNext();
7268 SwRect
aArea( pPageBody
->getFrameArea() );
7269 if ( pFootnoteCont
)
7270 aArea
.AddBottom( pFootnoteCont
->getFrameArea().Bottom() - aArea
.Bottom() );
7272 if ( !gProp
.pSGlobalShell
->GetViewOptions()->IsViewMetaChars( ) )
7273 ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea
) );
7275 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea
) );
7278 void SwColumnFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7279 const SwRect
& ) const
7281 const SwFrame
* pLay
= Lower();
7282 const SwFrame
* pFootnoteCont
= nullptr;
7283 const SwFrame
* pColBody
= nullptr;
7284 while ( pLay
&& !( pFootnoteCont
&& pColBody
) )
7286 if ( pLay
->IsFootnoteContFrame( ) )
7287 pFootnoteCont
= pLay
;
7288 if ( pLay
->IsBodyFrame() )
7290 pLay
= pLay
->GetNext();
7293 assert(pColBody
&& "presumably this is impossible");
7295 SwRect
aArea( pColBody
->getFrameArea() );
7297 // #i3662# - enlarge top of column body frame's printing area
7298 // in sections to top of section frame.
7299 const bool bColInSection
= GetUpper()->IsSctFrame();
7300 if ( bColInSection
)
7303 aArea
.Right( GetUpper()->getFrameArea().Right() );
7305 aArea
.Top( GetUpper()->getFrameArea().Top() );
7308 if ( pFootnoteCont
)
7309 aArea
.AddBottom( pFootnoteCont
->getFrameArea().Bottom() - aArea
.Bottom() );
7311 ::SwAlignRect( aArea
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7313 if ( !gProp
.pSGlobalShell
->GetViewOptions()->IsViewMetaChars( ) )
7314 ProcessPrimitives( lcl_CreateColumnAreaDelimiterPrimitives( aArea
) );
7316 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea
) );
7319 void SwSectionFrame::PaintSubsidiaryLines( const SwPageFrame
* pPage
,
7320 const SwRect
& rRect
) const
7322 if (!gProp
.pSGlobalShell
->GetViewOptions()->IsSectionBoundaries())
7325 const bool bNoLowerColumn
= !Lower() || !Lower()->IsColumnFrame();
7326 if ( bNoLowerColumn
)
7328 SwLayoutFrame::PaintSubsidiaryLines( pPage
, rRect
);
7333 * The SwBodyFrame doesn't print any subsidiary line: it's bounds are painted
7334 * either by the parent page or the parent column frame.
7336 void SwBodyFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7337 const SwRect
& ) const
7341 void SwHeadFootFrame::PaintSubsidiaryLines( const SwPageFrame
*, const SwRect
& ) const
7343 if (!gProp
.pSGlobalShell
->GetViewOptions()->IsDocBoundaries())
7346 if ( gProp
.pSGlobalShell
->IsHeaderFooterEdit() )
7348 SwRect
aArea( getFramePrintArea() );
7349 aArea
.Pos() += getFrameArea().Pos();
7350 if ( !gProp
.pSGlobalShell
->GetViewOptions()->IsViewMetaChars( ) )
7351 ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea
) );
7353 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea
) );
7358 * This method is overridden in order to have no subsidiary lines
7359 * around the footnotes.
7361 void SwFootnoteFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7362 const SwRect
& ) const
7367 * This method is overridden in order to have no subsidiary lines
7368 * around the footnotes containers.
7370 void SwFootnoteContFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7371 const SwRect
& ) const
7375 void SwLayoutFrame::PaintSubsidiaryLines( const SwPageFrame
*pPage
,
7376 const SwRect
&rRect
) const
7378 bool bNewTableModel
= false;
7381 if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
7383 const SwTabFrame
* pTabFrame
= FindTabFrame();
7384 if ( pTabFrame
->IsCollapsingBorders() )
7387 bNewTableModel
= pTabFrame
->GetTable()->IsNewModel();
7388 // in the new table model, we have an early return for all cell-related
7389 // frames, except from non-covered table cells
7390 if ( bNewTableModel
)
7391 if ( IsTabFrame() ||
7393 ( IsCellFrame() && IsCoveredCell() ) )
7397 const bool bFlys
= pPage
->GetSortedObjs() != nullptr;
7399 const bool bCell
= IsCellFrame();
7400 // #i3662# - use frame area for cells for section use also frame area
7401 const bool bUseFrameArea
= bCell
|| IsSctFrame();
7402 SwRect
aOriginal( bUseFrameArea
? getFrameArea() : getFramePrintArea() );
7403 if ( !bUseFrameArea
)
7404 aOriginal
.Pos() += getFrameArea().Pos();
7406 ::SwAlignRect( aOriginal
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7408 if ( !aOriginal
.Overlaps( rRect
) )
7411 SwRect
aOut( aOriginal
);
7412 aOut
.Intersection_( rRect
);
7414 const SwTwips nRight
= aOut
.Right();
7415 const SwTwips nBottom
= aOut
.Bottom();
7417 const Point
aRT( nRight
, aOut
.Top() );
7418 const Point
aRB( nRight
, nBottom
);
7419 const Point
aLB( aOut
.Left(), nBottom
);
7421 SubColFlags nSubColor
= ( bCell
|| IsRowFrame() )
7425 : ( IsInFly() ? SubColFlags::Fly
: SubColFlags::Page
) );
7427 // collect body, header, footer, footnote and section
7428 // sub-lines in <pSpecSubsLine> array.
7429 const bool bSpecialSublines
= IsBodyFrame() || IsHeaderFrame() || IsFooterFrame() ||
7430 IsFootnoteFrame() || IsSctFrame();
7431 SwLineRects
*const pUsedSubsLines
= bSpecialSublines
7432 ? gProp
.pSSpecSubsLines
.get() : gProp
.pSSubsLines
.get();
7434 // NOTE: for cell frames only left and right (horizontal layout) respectively
7435 // top and bottom (vertical layout) lines painted.
7436 // NOTE2: this does not hold for the new table model!!! We paint the top border
7437 // of each non-covered table cell.
7438 const bool bVert
= IsVertical();
7441 // add control for drawing left and right lines
7442 if ( !bCell
|| bNewTableModel
|| !bVert
)
7444 if ( aOriginal
.Left() == aOut
.Left() )
7445 ::lcl_RefreshLine( this, pPage
, aOut
.Pos(), aLB
, nSubColor
, pUsedSubsLines
);
7446 // in vertical layout set page/column break at right
7447 if ( aOriginal
.Right() == nRight
)
7448 ::lcl_RefreshLine( this, pPage
, aRT
, aRB
, nSubColor
, pUsedSubsLines
);
7450 // adjust control for drawing top and bottom lines
7451 if ( !bCell
|| bNewTableModel
|| bVert
)
7453 if ( aOriginal
.Top() == aOut
.Top() )
7454 // in horizontal layout set page/column break at top
7455 ::lcl_RefreshLine( this, pPage
, aOut
.Pos(), aRT
, nSubColor
, pUsedSubsLines
);
7456 if ( aOriginal
.Bottom() == nBottom
)
7457 ::lcl_RefreshLine( this, pPage
, aLB
, aRB
, nSubColor
,
7463 // add control for drawing left and right lines
7464 if ( !bCell
|| bNewTableModel
|| !bVert
)
7466 if ( aOriginal
.Left() == aOut
.Left() )
7468 const SwRect
aRect( aOut
.Pos(), aLB
);
7469 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7470 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7472 // in vertical layout set page/column break at right
7473 if ( aOriginal
.Right() == nRight
)
7475 const SwRect
aRect( aRT
, aRB
);
7476 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7477 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7480 // adjust control for drawing top and bottom lines
7481 if ( !bCell
|| bNewTableModel
|| bVert
)
7483 if ( aOriginal
.Top() == aOut
.Top() )
7485 // in horizontal layout set page/column break at top
7486 const SwRect
aRect( aOut
.Pos(), aRT
);
7487 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7488 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7490 if ( aOriginal
.Bottom() == nBottom
)
7492 const SwRect
aRect( aLB
, aRB
);
7493 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7494 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7501 * Refreshes all extra data (line breaks a.s.o) of the page. Basically only those objects
7502 * are considered which horizontally overlap the Rect.
7504 void SwPageFrame::RefreshExtraData( const SwRect
&rRect
) const
7506 const SwLineNumberInfo
&rInfo
= GetFormat()->GetDoc()->GetLineNumberInfo();
7507 bool bLineInFly
= (rInfo
.IsPaintLineNumbers() && rInfo
.IsCountInFlys())
7508 || static_cast<sal_Int16
>(SW_MOD()->GetRedlineMarkPos()) != text::HoriOrientation::NONE
;
7510 SwRect
aRect( rRect
);
7511 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7512 if ( !aRect
.HasArea() )
7515 SwLayoutFrame::RefreshExtraData( aRect
);
7517 if ( bLineInFly
&& GetSortedObjs() )
7518 for (SwAnchoredObject
* pAnchoredObj
: *GetSortedObjs())
7520 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7522 if ( pFly
->getFrameArea().Top() <= aRect
.Bottom() &&
7523 pFly
->getFrameArea().Bottom() >= aRect
.Top() )
7524 pFly
->RefreshExtraData( aRect
);
7529 void SwLayoutFrame::RefreshExtraData( const SwRect
&rRect
) const
7532 const SwLineNumberInfo
&rInfo
= GetFormat()->GetDoc()->GetLineNumberInfo();
7533 bool bLineInBody
= rInfo
.IsPaintLineNumbers(),
7534 bLineInFly
= bLineInBody
&& rInfo
.IsCountInFlys(),
7535 bRedLine
= static_cast<sal_Int16
>(SW_MOD()->GetRedlineMarkPos())!=text::HoriOrientation::NONE
;
7537 const SwContentFrame
*pCnt
= ContainsContent();
7538 while ( pCnt
&& IsAnLower( pCnt
) )
7540 if ( pCnt
->IsTextFrame() && ( bRedLine
||
7541 ( !pCnt
->IsInTab() &&
7542 ((bLineInBody
&& pCnt
->IsInDocBody()) ||
7543 (bLineInFly
&& pCnt
->IsInFly())) ) ) &&
7544 pCnt
->getFrameArea().Top() <= rRect
.Bottom() &&
7545 pCnt
->getFrameArea().Bottom() >= rRect
.Top() )
7547 static_cast<const SwTextFrame
*>(pCnt
)->PaintExtraData( rRect
);
7549 if ( bLineInFly
&& pCnt
->GetDrawObjs() )
7550 for (SwAnchoredObject
* pAnchoredObj
: *pCnt
->GetDrawObjs())
7552 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7554 if ( pFly
->IsFlyInContentFrame() &&
7555 pFly
->getFrameArea().Top() <= rRect
.Bottom() &&
7556 pFly
->getFrameArea().Bottom() >= rRect
.Top() )
7557 pFly
->RefreshExtraData( rRect
);
7560 pCnt
= pCnt
->GetNextContentFrame();
7566 * Determine the color, that is respectively will be drawn as background
7567 * for the page frame.
7568 * Using existing method SwFrame::GetBackgroundBrush to determine the color
7569 * that is set at the page frame respectively is parent. If none is found
7570 * return the global retouche color
7574 Color
SwPageFrame::GetDrawBackgroundColor() const
7576 const SvxBrushItem
* pBrushItem
;
7577 std::optional
<Color
> xDummyColor
;
7579 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
7581 if ( GetBackgroundBrush( aFillAttributes
, pBrushItem
, xDummyColor
, aDummyRect
, true, /*bConsiderTextBox=*/false) )
7583 if(aFillAttributes
&& aFillAttributes
->isUsed())
7585 // let SdrAllFillAttributesHelper do the average color calculation
7586 return Color(aFillAttributes
->getAverageColor(aGlobalRetoucheColor
.getBColor()));
7591 SwViewShell
* sh1
= getRootFrame()->GetCurrShell();
7592 if (sh1
!= nullptr) {
7593 SfxObjectShell
* sh2
= sh1
->GetDoc()->GetPersist();
7594 if (sh2
!= nullptr && sh2
->HasName()) {
7595 referer
= sh2
->GetMedium()->GetName();
7598 const Graphic
* pGraphic
= pBrushItem
->GetGraphic(referer
);
7602 // #29105# when a graphic is set, it may be possible to calculate a single
7603 // color which looks good in all places of the graphic. Since it is
7604 // planned to have text edit on the overlay one day and the fallback
7605 // to aGlobalRetoucheColor returns something useful, just use that
7610 // not a graphic, use (hopefully) initialized color
7611 return pBrushItem
->GetColor();
7616 return aGlobalRetoucheColor
;
7619 /// create/return font used to paint the "empty page" string
7620 const vcl::Font
& SwPageFrame::GetEmptyPageFont()
7622 static vcl::Font aEmptyPgFont
= []()
7625 tmp
.SetFontSize( Size( 0, 80 * 20 )); // == 80 pt
7626 tmp
.SetWeight( WEIGHT_BOLD
);
7627 tmp
.SetStyleName(OUString());
7628 tmp
.SetFamilyName("Helvetica");
7629 tmp
.SetFamily( FAMILY_SWISS
);
7630 tmp
.SetTransparent( true );
7631 tmp
.SetColor( COL_GRAY
);
7635 return aEmptyPgFont
;
7639 * Retouch for a section
7641 * Retouch will only be done, if the Frame is the last one in his chain.
7642 * The whole area of the upper which is located below the Frame will be
7643 * cleared using PaintSwFrameBackground.
7645 void SwFrame::Retouch( const SwPageFrame
* pPage
, const SwRect
&rRect
) const
7647 if ( gProp
.bSFlyMetafile
)
7650 OSL_ENSURE( GetUpper(), "Retouche try without Upper." );
7651 OSL_ENSURE( getRootFrame()->GetCurrShell() && gProp
.pSGlobalShell
->GetWin(), "Retouche on a printer?" );
7653 SwRect
aRetouche( GetUpper()->GetPaintArea() );
7654 aRetouche
.Top( getFrameArea().Top() + getFrameArea().Height() );
7655 aRetouche
.Intersection( gProp
.pSGlobalShell
->VisArea() );
7657 if ( aRetouche
.HasArea() )
7659 //Omit the passed Rect. To do this, we unfortunately need a region to
7661 SwRegionRects
aRegion( aRetouche
);
7663 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
7665 // #i16816# tagged pdf support
7666 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh
->GetOut() );
7668 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
7670 const SwRect
&rRetouche
= aRegion
[i
];
7672 GetUpper()->PaintBaBo( rRetouche
, pPage
);
7674 //Hell and Heaven need to be refreshed too.
7675 //To avoid recursion my retouch flag needs to be reset first!
7677 if ( rRetouche
.HasArea() )
7679 const Color
aPageBackgrdColor(pPage
->GetDrawBackgroundColor());
7680 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
7682 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
7685 pSh
->Imp()->PaintLayer( rIDDMA
.GetHellId(), nullptr,
7686 *pPage
, rRetouche
, &aPageBackgrdColor
,
7687 pPage
->IsRightToLeft(),
7689 pSh
->Imp()->PaintLayer( rIDDMA
.GetHeavenId(), nullptr,
7690 *pPage
, rRetouche
, &aPageBackgrdColor
,
7691 pPage
->IsRightToLeft(),
7697 //Because we leave all paint areas, we need to refresh the
7699 pPage
->RefreshSubsidiary( rRetouche
);
7702 if ( SwViewShell::IsLstEndAction() )
7707 * Determine the background brush for the frame:
7708 * the background brush is taken from it-self or from its parent (anchor/upper).
7709 * Normally, the background brush is taken, which has no transparent color or
7710 * which has a background graphic. But there are some special cases:
7711 * (1) No background brush is taken from a page frame, if view option "IsPageBack"
7713 * (2) Background brush from an index section is taken under special conditions.
7714 * In this case parameter <rpCol> is set to the index shading color.
7715 * (3) New (OD 20.08.2002) - Background brush is taken, if on background drawing
7716 * of the frame transparency is considered and its color is not "no fill"/"auto fill"
7718 * Old description in German:
7719 * Returns the Backgroundbrush for the area of the Frame.
7720 * The Brush is defined by the Frame or by an upper, the first Brush is
7721 * used. If no Brush is defined for a Frame, false is returned.
7724 * output parameter - constant reference pointer the found background brush
7726 * @param rpFillStyle
7727 * output parameter - constant reference pointer the found background fill style
7729 * @param rpFillGradient
7730 * output parameter - constant reference pointer the found background fill gradient
7733 * output parameter - constant reference pointer to the color of the index shading
7734 * set under special conditions, if background brush is taken from an index section.
7737 * in-/output parameter - reference to the rectangle the background brush is
7738 * considered for - adjusted to the frame, from which the background brush is
7742 * input parameter - boolean indicating, if background brush should *not* be
7743 * taken from parent.
7745 * @param bConsiderTextBox
7746 * consider the TextBox of this fly frame (if there is any) when determining
7747 * the background color, useful for automatic font color.
7749 * @return true, if a background brush for the frame is found
7751 bool SwFrame::GetBackgroundBrush(
7752 drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& rFillAttributes
,
7753 const SvxBrushItem
* & rpBrush
,
7754 std::optional
<Color
>& rxCol
,
7757 bool bConsiderTextBox
) const
7759 const SwFrame
*pFrame
= this;
7760 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
7761 const SwViewOption
*pOpt
= pSh
->GetViewOptions();
7766 if ( pFrame
->IsPageFrame() && !pOpt
->IsPageBack() )
7769 if (pFrame
->supportsFullDrawingLayerFillAttributeSet())
7771 bool bHandledTextBox
= false;
7772 if (pFrame
->IsFlyFrame() && bConsiderTextBox
)
7774 const SwFlyFrame
* pFlyFrame
= static_cast<const SwFlyFrame
*>(pFrame
);
7775 SwFrameFormat
* pShape
7776 = SwTextBoxHelper::getOtherTextBoxFormat(pFlyFrame
->GetFormat(), RES_FLYFRMFMT
);
7779 SdrObject
* pObject
= pShape
->FindRealSdrObject();
7782 // Work with the fill attributes of the shape of the fly frame.
7784 std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(
7785 pObject
->GetMergedItemSet());
7786 bHandledTextBox
= true;
7791 if (!bHandledTextBox
)
7792 rFillAttributes
= pFrame
->getSdrAllFillAttributesHelper();
7794 const SvxBrushItem
&rBack
= pFrame
->GetAttrSet()->GetBackground();
7796 if( pFrame
->IsSctFrame() )
7798 const SwSection
* pSection
= static_cast<const SwSectionFrame
*>(pFrame
)->GetSection();
7799 // Note: If frame <pFrame> is a section of the index and
7800 // it its background color is "no fill"/"auto fill" and
7801 // it has no background graphic and
7802 // we are not in the page preview and
7803 // we are not in read-only mode and
7804 // option "index shadings" is set and
7805 // the output is not the printer
7806 // then set <rpCol> to the color of the index shading
7807 if( pSection
&& ( SectionType::ToxHeader
== pSection
->GetType() ||
7808 SectionType::ToxContent
== pSection
->GetType() ) &&
7809 (rBack
.GetColor() == COL_TRANSPARENT
) &&
7810 rBack
.GetGraphicPos() == GPOS_NONE
&&
7811 !pOpt
->IsPagePreview() &&
7812 !pOpt
->IsReadonly() &&
7813 // #114856# Form view
7814 !pOpt
->IsFormView() &&
7815 pOpt
->IsIndexShadings() &&
7816 !pOpt
->IsPDFExport() &&
7817 pSh
->GetOut()->GetOutDevType() != OUTDEV_PRINTER
)
7819 rxCol
= pOpt
->GetIndexShadingsColor();
7823 // determine, if background draw of frame <pFrame> considers transparency
7824 // Status Quo: background transparency have to be
7825 // considered for fly frames
7826 const bool bConsiderBackgroundTransparency
= pFrame
->IsFlyFrame();
7828 // #i125189# Do not base the decision for using the parent's fill style for this
7829 // frame when the new DrawingLayer FillAttributes are used on the SdrAllFillAttributesHelper
7830 // information. There the data is already optimized to no fill in the case that the
7831 // transparence is at 100% while no fill is the criteria for derivation
7832 bool bNewDrawingLayerFillStyleIsUsedAndNotNoFill(false);
7836 // the new DrawingLayer FillStyle is used
7837 if(rFillAttributes
->isUsed())
7839 // it's not drawing::FillStyle_NONE
7840 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
= true;
7844 // maybe optimized already when 100% transparency is used somewhere, need to test
7845 // XFillStyleItem directly from the model data
7846 const drawing::FillStyle
eFillStyle(pFrame
->GetAttrSet()->Get(XATTR_FILLSTYLE
).GetValue());
7848 if(drawing::FillStyle_NONE
!= eFillStyle
)
7850 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
= true;
7856 // If <bConsiderBackgroundTransparency> is set - see above -,
7857 // return brush of frame <pFrame>, if its color is *not* "no fill"/"auto fill"
7859 // #i125189# Done when the new DrawingLayer FillAttributes are used and
7860 // not drawing::FillStyle_NONE (see above)
7861 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
||
7863 // done when SvxBrushItem is used
7864 rBack
.GetColor().GetAlpha() == 255 || rBack
.GetGraphicPos() != GPOS_NONE
||
7866 // done when direct color is forced
7869 // done when consider BG transparency and color is not completely transparent
7870 (bConsiderBackgroundTransparency
&& (rBack
.GetColor() != COL_TRANSPARENT
))
7874 if ( pFrame
->IsPageFrame() && pSh
->GetViewOptions()->getBrowseMode() )
7876 rOrigRect
= pFrame
->getFrameArea();
7877 ::SwAlignRect(rOrigRect
, pSh
, pSh
->GetOut());
7881 if (pFrame
->IsPageFrame()
7882 && pFrame
->GetAttrSet()->GetItem
<SfxBoolItem
>(RES_BACKGROUND_FULL_SIZE
)->GetValue())
7884 rOrigRect
= pFrame
->getFrameArea();
7886 else if (pFrame
->getFrameArea().SSize() != pFrame
->getFramePrintArea().SSize())
7888 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFrame
);
7889 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
7890 ::lcl_CalcBorderRect( rOrigRect
, pFrame
, rAttrs
, false, gProp
);
7894 rOrigRect
= pFrame
->getFramePrintArea();
7895 rOrigRect
+= pFrame
->getFrameArea().Pos();
7904 // Do not try to get background brush from parent (anchor/upper)
7908 // get parent frame - anchor or upper - for next loop
7909 if ( pFrame
->IsFlyFrame() )
7911 pFrame
= static_cast<const SwFlyFrame
*>(pFrame
)->GetAnchorFrame();
7915 pFrame
= pFrame
->GetUpper();
7922 void SetOutDevAndWin( SwViewShell
*pSh
, OutputDevice
*pO
,
7923 vcl::Window
*pW
, sal_uInt16 nZoom
)
7927 pSh
->mpOpt
->SetZoom( nZoom
);
7930 Graphic
SwFrameFormat::MakeGraphic( ImageMap
*, const sal_uInt32
/*nMaximumQuadraticPixels*/, const std::optional
<Size
>& /*rTargetDPI*/ )
7935 Graphic
SwFlyFrameFormat::MakeGraphic( ImageMap
* pMap
, const sal_uInt32
/*nMaximumQuadraticPixels*/, const std::optional
<Size
>& /*rTargetDPI*/ )
7939 SwIterator
<SwFrame
,SwFormat
> aIter( *this );
7940 SwFrame
*pFirst
= aIter
.First();
7941 SwViewShell
*const pSh
=
7942 pFirst
? pFirst
->getRootFrame()->GetCurrShell() : nullptr;
7945 SwViewShell
*pOldGlobal
= gProp
.pSGlobalShell
;
7946 gProp
.pSGlobalShell
= pSh
;
7948 bool bNoteURL
= pMap
&&
7949 SfxItemState::SET
!= GetAttrSet().GetItemState( RES_URL
);
7952 OSL_ENSURE( !pNoteURL
, "MakeGraphic: pNoteURL already used? " );
7953 pNoteURL
= new SwNoteURL
;
7955 SwFlyFrame
*pFly
= static_cast<SwFlyFrame
*>(pFirst
);
7957 OutputDevice
*pOld
= pSh
->GetOut();
7958 ScopedVclPtrInstance
< VirtualDevice
> pDev( *pOld
);
7959 pDev
->EnableOutput( false );
7962 MapMode
aMap( pOld
->GetMapMode().GetMapUnit() );
7963 pDev
->SetMapMode( aMap
);
7964 aMet
.SetPrefMapMode( aMap
);
7966 ::SwCalcPixStatics( pSh
->GetOut() );
7967 aMet
.SetPrefSize( pFly
->getFrameArea().SSize() );
7969 aMet
.Record( pDev
.get() );
7970 pDev
->SetLineColor();
7971 pDev
->SetFillColor();
7972 pDev
->SetFont( pOld
->GetFont() );
7974 //Enlarge the rectangle if needed, so the border is painted too.
7975 SwRect
aOut( pFly
->getFrameArea() );
7976 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFly
);
7977 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
7978 if ( rAttrs
.CalcRightLine() )
7979 aOut
.AddWidth(2*gProp
.nSPixelSzW
);
7980 if ( rAttrs
.CalcBottomLine() )
7981 aOut
.AddHeight(2*gProp
.nSPixelSzH
);
7983 // #i92711# start Pre/PostPaint encapsulation before pOut is changed to the buffering VDev
7984 const vcl::Region
aRepaintRegion(aOut
.SVRect());
7985 pSh
->DLPrePaint2(aRepaintRegion
);
7987 vcl::Window
*pWin
= pSh
->GetWin();
7988 sal_uInt16 nZoom
= pSh
->GetViewOptions()->GetZoom();
7989 ::SetOutDevAndWin( pSh
, pDev
, nullptr, 100 );
7990 gProp
.bSFlyMetafile
= true;
7991 gProp
.pSFlyMetafileOut
= pWin
->GetOutDev();
7993 SwViewShellImp
*pImp
= pSh
->Imp();
7994 gProp
.pSFlyOnlyDraw
= pFly
;
7995 gProp
.pSLines
.reset(new SwLineRects
);
7997 // determine page, fly frame is on
7998 const SwPageFrame
* pFlyPage
= pFly
->FindPageFrame();
7999 const Color
aPageBackgrdColor(pFlyPage
->GetDrawBackgroundColor());
8000 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
8002 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
8004 pImp
->PaintLayer( rIDDMA
.GetHellId(), nullptr,
8005 *pFlyPage
, aOut
, &aPageBackgrdColor
,
8006 pFlyPage
->IsRightToLeft(),
8008 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8009 if ( pFly
->IsFlyInContentFrame() )
8010 pFly
->PaintSwFrame( *pDev
, aOut
);
8011 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8012 pImp
->PaintLayer( rIDDMA
.GetHeavenId(), nullptr,
8013 *pFlyPage
, aOut
, &aPageBackgrdColor
,
8014 pFlyPage
->IsRightToLeft(),
8016 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8017 gProp
.pSLines
.reset();
8018 gProp
.pSFlyOnlyDraw
= nullptr;
8020 gProp
.pSFlyMetafileOut
= nullptr;
8021 gProp
.bSFlyMetafile
= false;
8022 ::SetOutDevAndWin( pSh
, pOld
, pWin
, nZoom
);
8024 // #i92711# end Pre/PostPaint encapsulation when pOut is back and content is painted
8025 pSh
->DLPostPaint2(true);
8028 aMet
.Move( -pFly
->getFrameArea().Left(), -pFly
->getFrameArea().Top() );
8029 aRet
= Graphic( aMet
);
8033 OSL_ENSURE( pNoteURL
, "MakeGraphic: Good Bye, NoteURL." );
8037 gProp
.pSGlobalShell
= pOldGlobal
;
8042 Graphic
SwDrawFrameFormat::MakeGraphic( ImageMap
*, const sal_uInt32 nMaximumQuadraticPixels
, const std::optional
<Size
>& rTargetDPI
)
8045 SwDrawModel
* pMod
= getIDocumentDrawModelAccess().GetDrawModel();
8048 SdrObject
*pObj
= FindSdrObject();
8049 SdrView
aView( *pMod
);
8050 SdrPageView
*pPgView
= aView
.ShowSdrPage(aView
.GetModel().GetPage(0));
8051 aView
.MarkObj( pObj
, pPgView
);
8052 aRet
= aView
.GetMarkedObjBitmapEx(/*bNoVDevIfOneBmpMarked=*/false, nMaximumQuadraticPixels
, rTargetDPI
);
8053 aView
.HideSdrPage();
8058 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */