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/canvastools.hxx>
22 #include <tools/lazydelete.hxx>
23 #include <sfx2/docfile.hxx>
24 #include <sfx2/printer.hxx>
25 #include <sfx2/progress.hxx>
26 #include <sfx2/StylePreviewRenderer.hxx>
27 #include <editeng/brushitem.hxx>
28 #include <editeng/prntitem.hxx>
29 #include <editeng/boxitem.hxx>
30 #include <editeng/shaditem.hxx>
31 #include <svx/ctredlin.hxx>
32 #include <svx/framelink.hxx>
33 #include <svx/svdouno.hxx>
34 #include <drawdoc.hxx>
35 #include <tgrditem.hxx>
37 #include <fmtsrnd.hxx>
38 #include <fmtclds.hxx>
40 #include <strings.hrc>
41 #include <swmodule.hxx>
42 #include <rootfrm.hxx>
43 #include <pagefrm.hxx>
44 #include <section.hxx>
45 #include <sectfrm.hxx>
46 #include <viewimp.hxx>
47 #include <dflyobj.hxx>
50 #include <frmtool.hxx>
51 #include <viewopt.hxx>
53 #include <dcontact.hxx>
58 #include <cellfrm.hxx>
59 #include <notxtfrm.hxx>
61 #include <pagedesc.hxx>
62 #include <ptqueue.hxx>
63 #include <noteurl.hxx>
64 #include "virtoutp.hxx"
65 #include <lineinfo.hxx>
66 #include <dbg_lay.hxx>
68 #include <svx/svdogrp.hxx>
69 #include <sortedobjs.hxx>
70 #include <EnhancedPDFExportHelper.hxx>
71 #include <bodyfrm.hxx>
74 #include <sw_primitivetypes2d.hxx>
77 #include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
78 #include <svx/sdr/contact/viewobjectcontact.hxx>
79 #include <svx/sdr/contact/viewcontact.hxx>
80 #include <DocumentSettingManager.hxx>
81 #include <IDocumentDeviceAccess.hxx>
82 #include <IDocumentDrawModelAccess.hxx>
85 #include <PostItMgr.hxx>
86 #include <FrameControlsManager.hxx>
87 #include <vcl/settings.hxx>
89 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
91 #include <svtools/borderhelper.hxx>
93 #include <bitmaps.hlst>
94 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
95 #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
96 #include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
97 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
98 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
99 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
100 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
101 #include <drawinglayer/processor2d/processor2dtools.hxx>
102 #include <svx/unoapi.hxx>
103 #include <svx/svdpagv.hxx>
104 #include <svx/xfillit0.hxx>
105 #include <basegfx/matrix/b2dhommatrixtools.hxx>
106 #include <basegfx/color/bcolortools.hxx>
107 #include <basegfx/utils/b2dclipstate.hxx>
108 #include <sal/log.hxx>
114 #include <edtwin.hxx>
116 #include <paintfrm.hxx>
117 #include <textboxhelper.hxx>
118 #include <o3tl/typed_flags_set.hxx>
120 #include <vcl/BitmapTools.hxx>
121 #include <comphelper/configuration.hxx>
122 #include <comphelper/lok.hxx>
123 #include <svtools/optionsdrawinglayer.hxx>
124 #include <vcl/GraphicLoader.hxx>
125 #include <basegfx/polygon/b2dpolygontools.hxx>
127 #include <svl/style.hxx>
129 #include <unotools/configmgr.hxx>
130 #include <vcl/hatch.hxx>
132 using namespace ::editeng
;
133 using namespace ::com::sun::star
;
137 struct SwPaintProperties
;
139 //Class declaration; here because they are only used in this file
140 enum class SubColFlags
{
141 Page
= 0x01, //Helplines of the page
142 Tab
= 0x08, //Helplines inside tables
143 Fly
= 0x10, //Helplines inside fly frames
144 Sect
= 0x20, //Helplines inside sections
150 template<> struct typed_flags
<SubColFlags
> : is_typed_flags
<SubColFlags
, 0x39> {};
155 // Classes collecting the border lines and help lines
156 class SwLineRect
: public SwRect
159 SvxBorderLineStyle m_nStyle
;
160 const SwTabFrame
* m_pTabFrame
;
161 SubColFlags m_nSubColor
; //colorize subsidiary lines
162 bool m_bPainted
; //already painted?
163 sal_uInt8 m_nLock
; //To distinguish the line and the hell layer.
165 SwLineRect( const SwRect
&rRect
, const Color
*pCol
, const SvxBorderLineStyle nStyle
,
166 const SwTabFrame
*pT
, const SubColFlags nSCol
);
168 const Color
& GetColor() const { return m_aColor
; }
169 SvxBorderLineStyle
GetStyle() const { return m_nStyle
; }
170 const SwTabFrame
* GetTab() const { return m_pTabFrame
; }
171 void SetPainted() { m_bPainted
= true; }
172 void Lock(bool bLock
)
179 bool IsPainted() const { return m_bPainted
; }
180 bool IsLocked() const { return m_nLock
!= 0; }
181 SubColFlags
GetSubColor() const { return m_nSubColor
; }
183 bool MakeUnion(const SwRect
& rRect
, SwPaintProperties
const& properties
);
189 static void dummy_function()
191 pid_t pid
= getpid();
201 std::vector
<SwLineRect
> m_aLineRects
;
202 typedef std::vector
< SwLineRect
>::const_iterator const_iterator
;
203 typedef std::vector
< SwLineRect
>::iterator iterator
;
204 typedef std::vector
< SwLineRect
>::reverse_iterator reverse_iterator
;
205 typedef std::vector
< SwLineRect
>::size_type size_type
;
206 size_t m_nLastCount
; //avoid unnecessary cycles in PaintLines
211 // Work around what is either a compiler bug in Xcode 5.1.1,
212 // or some unknown problem in this file. If I ifdef out this
213 // call, I get a crash in SwSubsRects::PaintSubsidiary: the
214 // address of the rLi reference variable is claimed to be
219 void AddLineRect( const SwRect
& rRect
, const Color
*pColor
, const SvxBorderLineStyle nStyle
,
220 const SwTabFrame
*pTab
, const SubColFlags nSCol
, SwPaintProperties
const &properties
);
221 void ConnectEdges( OutputDevice
const *pOut
, SwPaintProperties
const &properties
);
222 void PaintLines ( OutputDevice
*pOut
, SwPaintProperties
const &properties
);
223 void LockLines( bool bLock
);
226 bool isFull() const { return m_aLineRects
.size() > 100; }
229 class SwSubsRects
: public SwLineRects
231 void RemoveSuperfluousSubsidiaryLines( const SwLineRects
&rRects
, SwPaintProperties
const &properties
);
233 void PaintSubsidiary( OutputDevice
*pOut
, const SwLineRects
*pRects
, SwPaintProperties
const &properties
);
238 drawinglayer::primitive2d::Primitive2DContainer m_Lines
;
240 void AddBorderLines(drawinglayer::primitive2d::Primitive2DContainer
&& rContainer
);
241 drawinglayer::primitive2d::Primitive2DContainer
GetBorderLines_Clear()
243 drawinglayer::primitive2d::Primitive2DContainer lines
;
251 // Default zoom factor
252 const double aEdgeScale
= 0.5;
254 //To optimize the expensive RetouchColor determination
255 Color aGlobalRetoucheColor
;
259 Color
* GetActiveRetoucheColor()
261 return &aGlobalRetoucheColor
;
268 * Container for static properties
270 struct SwPaintProperties
{
271 // Only repaint the Fly content as well as the background of the Fly content if
272 // a metafile is taken of the Fly.
274 VclPtr
<OutputDevice
> pSFlyMetafileOut
;
275 SwViewShell
*pSGlobalShell
;
277 // Retouch for transparent Flys is done by the background of the Flys.
278 // The Fly itself should certainly not be spared out. See PaintSwFrameBackground and
279 // lcl_SubtractFlys()
280 SwFlyFrame
*pSRetoucheFly
;
281 SwFlyFrame
*pSRetoucheFly2
;
282 SwFlyFrame
*pSFlyOnlyDraw
;
284 // The borders will be collected in pSLines during the Paint and later
285 // possibly merge them.
286 // The help lines will be collected and merged in gProp.pSSubsLines. These will
287 // be compared with pSLines before the work in order to avoid help lines
289 std::unique_ptr
<BorderLines
> pBLines
;
290 std::unique_ptr
<SwLineRects
> pSLines
;
291 std::unique_ptr
<SwSubsRects
> pSSubsLines
;
293 // global variable for sub-lines of body, header, footer, section and footnote frames.
294 std::unique_ptr
<SwSubsRects
> pSSpecSubsLines
;
295 SfxProgress
*pSProgress
;
297 // Sizes of a pixel and the corresponding halves. Will be reset when
298 // entering SwRootFrame::PaintSwFrame
299 tools::Long nSPixelSzW
;
300 tools::Long nSPixelSzH
;
301 tools::Long nSHalfPixelSzW
;
302 tools::Long nSHalfPixelSzH
;
303 tools::Long nSMinDistPixelW
;
304 tools::Long nSMinDistPixelH
;
306 Color aSGlobalRetoucheColor
;
308 // Current zoom factor
313 : bSFlyMetafile(false)
314 , pSFlyMetafileOut(nullptr)
315 , pSGlobalShell(nullptr)
316 , pSRetoucheFly(nullptr)
317 , pSRetoucheFly2(nullptr)
318 , pSFlyOnlyDraw(nullptr)
319 , pSProgress(nullptr)
335 static SwPaintProperties gProp
;
337 static bool isSubsidiaryLinesEnabled()
339 return !gProp
.pSGlobalShell
->GetViewOptions()->IsPagePreview() &&
340 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
341 !gProp
.pSGlobalShell
->GetViewOptions()->IsFormView() &&
342 gProp
.pSGlobalShell
->GetViewOptions()->IsShowBoundaries();
346 * Set borders alignment statics
347 * Adjustment for 'small' twip-to-pixel relations:
348 * For 'small' twip-to-pixel relations (less than 2:1)
349 * values of <gProp.nSHalfPixelSzW> and <gProp.nSHalfPixelSzH> are set to ZERO
351 void SwCalcPixStatics( vcl::RenderContext
const *pOut
)
353 // determine 'small' twip-to-pixel relation
354 bool bSmallTwipToPxRelW
= false;
355 bool bSmallTwipToPxRelH
= false;
357 Size
aCheckTwipToPxRelSz( pOut
->PixelToLogic( Size( 100, 100 )) );
358 if ( (aCheckTwipToPxRelSz
.Width()/100.0) < 2.0 )
360 bSmallTwipToPxRelW
= true;
362 if ( (aCheckTwipToPxRelSz
.Height()/100.0) < 2.0 )
364 bSmallTwipToPxRelH
= true;
368 Size
aSz( pOut
->PixelToLogic( Size( 1,1 )) );
370 gProp
.nSPixelSzW
= aSz
.Width();
371 if( !gProp
.nSPixelSzW
)
372 gProp
.nSPixelSzW
= 1;
373 gProp
.nSPixelSzH
= aSz
.Height();
374 if( !gProp
.nSPixelSzH
)
375 gProp
.nSPixelSzH
= 1;
377 // consider 'small' twip-to-pixel relations
378 if ( !bSmallTwipToPxRelW
)
380 gProp
.nSHalfPixelSzW
= gProp
.nSPixelSzW
/ 2 + 1;
384 gProp
.nSHalfPixelSzW
= 0;
386 // consider 'small' twip-to-pixel relations
387 if ( !bSmallTwipToPxRelH
)
389 gProp
.nSHalfPixelSzH
= gProp
.nSPixelSzH
/ 2 + 1;
393 gProp
.nSHalfPixelSzH
= 0;
396 gProp
.nSMinDistPixelW
= gProp
.nSPixelSzW
* 2 + 1;
397 gProp
.nSMinDistPixelH
= gProp
.nSPixelSzH
* 2 + 1;
399 const MapMode
&rMap
= pOut
->GetMapMode();
400 gProp
.aSScaleX
= double(rMap
.GetScaleX());
401 gProp
.aSScaleY
= double(rMap
.GetScaleY());
407 * To be able to save the statics so the paint is more or less reentrant
409 class SwSavePaintStatics
: public SwPaintProperties
412 SwSavePaintStatics();
413 ~SwSavePaintStatics();
418 SwSavePaintStatics::SwSavePaintStatics()
421 bSFlyMetafile
= gProp
.bSFlyMetafile
;
422 pSGlobalShell
= gProp
.pSGlobalShell
;
423 pSFlyMetafileOut
= gProp
.pSFlyMetafileOut
;
424 pSRetoucheFly
= gProp
.pSRetoucheFly
;
425 pSRetoucheFly2
= gProp
.pSRetoucheFly2
;
426 pSFlyOnlyDraw
= gProp
.pSFlyOnlyDraw
;
427 pBLines
= std::move(gProp
.pBLines
);
428 pSLines
= std::move(gProp
.pSLines
);
429 pSSubsLines
= std::move(gProp
.pSSubsLines
);
430 pSSpecSubsLines
= std::move(gProp
.pSSpecSubsLines
);
431 pSProgress
= gProp
.pSProgress
;
432 nSPixelSzW
= gProp
.nSPixelSzW
;
433 nSPixelSzH
= gProp
.nSPixelSzH
;
434 nSHalfPixelSzW
= gProp
.nSHalfPixelSzW
;
435 nSHalfPixelSzH
= gProp
.nSHalfPixelSzH
;
436 nSMinDistPixelW
= gProp
.nSMinDistPixelW
;
437 nSMinDistPixelH
= gProp
.nSMinDistPixelH
;
438 aSGlobalRetoucheColor
= aGlobalRetoucheColor
;
439 aSScaleX
= gProp
.aSScaleX
;
440 aSScaleY
= gProp
.aSScaleY
;
442 // Restoring globales to default
443 gProp
.bSFlyMetafile
= false;
444 gProp
.pSFlyMetafileOut
= nullptr;
445 gProp
.pSRetoucheFly
= nullptr;
446 gProp
.pSRetoucheFly2
= nullptr;
447 gProp
.nSPixelSzW
= gProp
.nSPixelSzH
=
448 gProp
.nSHalfPixelSzW
= gProp
.nSHalfPixelSzH
=
449 gProp
.nSMinDistPixelW
= gProp
.nSMinDistPixelH
= 0;
450 gProp
.aSScaleX
= gProp
.aSScaleY
= 1.0;
451 gProp
.pSProgress
= nullptr;
454 SwSavePaintStatics::~SwSavePaintStatics()
456 // Restoring globales to saved one
457 gProp
.pSGlobalShell
= pSGlobalShell
;
458 gProp
.bSFlyMetafile
= bSFlyMetafile
;
459 gProp
.pSFlyMetafileOut
= pSFlyMetafileOut
;
460 gProp
.pSRetoucheFly
= pSRetoucheFly
;
461 gProp
.pSRetoucheFly2
= pSRetoucheFly2
;
462 gProp
.pSFlyOnlyDraw
= pSFlyOnlyDraw
;
463 gProp
.pBLines
= std::move(pBLines
);
464 gProp
.pSLines
= std::move(pSLines
);
465 gProp
.pSSubsLines
= std::move(pSSubsLines
);
466 gProp
.pSSpecSubsLines
= std::move(pSSpecSubsLines
);
467 gProp
.pSProgress
= pSProgress
;
468 gProp
.nSPixelSzW
= nSPixelSzW
;
469 gProp
.nSPixelSzH
= nSPixelSzH
;
470 gProp
.nSHalfPixelSzW
= nSHalfPixelSzW
;
471 gProp
.nSHalfPixelSzH
= nSHalfPixelSzH
;
472 gProp
.nSMinDistPixelW
= nSMinDistPixelW
;
473 gProp
.nSMinDistPixelH
= nSMinDistPixelH
;
474 aGlobalRetoucheColor
= aSGlobalRetoucheColor
;
475 gProp
.aSScaleX
= aSScaleX
;
476 gProp
.aSScaleY
= aSScaleY
;
479 void BorderLines::AddBorderLines(drawinglayer::primitive2d::Primitive2DContainer
&& rContainer
)
481 if(!rContainer
.empty())
483 m_Lines
.append(std::move(rContainer
));
487 SwLineRect::SwLineRect(const SwRect
& rRect
, const Color
* pCol
, const SvxBorderLineStyle nStyl
,
488 const SwTabFrame
* pT
, const SubColFlags nSCol
)
496 if ( pCol
!= nullptr )
500 bool SwLineRect::MakeUnion( const SwRect
&rRect
, SwPaintProperties
const & properties
)
502 // It has already been tested outside, whether the rectangles have
503 // the same orientation (horizontal or vertical), color, etc.
504 if ( Height() > Width() ) //Vertical line
506 if ( Left() == rRect
.Left() && Width() == rRect
.Width() )
508 // Merge when there is no gap between the lines
509 const tools::Long nAdd
= properties
.nSPixelSzW
+ properties
.nSHalfPixelSzW
;
510 if ( Bottom() + nAdd
>= rRect
.Top() &&
511 Top() - nAdd
<= rRect
.Bottom() )
513 Bottom( std::max( Bottom(), rRect
.Bottom() ) );
514 Top ( std::min( Top(), rRect
.Top() ) );
521 if ( Top() == rRect
.Top() && Height() == rRect
.Height() )
523 // Merge when there is no gap between the lines
524 const tools::Long nAdd
= properties
.nSPixelSzW
+ properties
.nSHalfPixelSzW
;
525 if ( Right() + nAdd
>= rRect
.Left() &&
526 Left() - nAdd
<= rRect
.Right() )
528 Right( std::max( Right(), rRect
.Right() ) );
529 Left ( std::min( Left(), rRect
.Left() ) );
537 void SwLineRects::AddLineRect( const SwRect
&rRect
, const Color
*pCol
, const SvxBorderLineStyle nStyle
,
538 const SwTabFrame
*pTab
, const SubColFlags nSCol
, SwPaintProperties
const & properties
)
540 // Loop backwards because lines which can be combined, can usually be painted
541 // in the same context
542 for (reverse_iterator it
= m_aLineRects
.rbegin(); it
!= m_aLineRects
.rend(); ++it
)
544 SwLineRect
&rLRect
= *it
;
545 // Test for the orientation, color, table
546 if ( rLRect
.GetTab() == pTab
&&
547 !rLRect
.IsPainted() && rLRect
.GetSubColor() == nSCol
&&
548 (rLRect
.Height() > rLRect
.Width()) == (rRect
.Height() > rRect
.Width()) &&
549 (pCol
&& rLRect
.GetColor() == *pCol
) )
551 if ( rLRect
.MakeUnion( rRect
, properties
) )
555 m_aLineRects
.emplace_back(rRect
, pCol
, nStyle
, pTab
, nSCol
);
558 void SwLineRects::ConnectEdges( OutputDevice
const *pOut
, SwPaintProperties
const & properties
)
560 if ( pOut
->GetOutDevType() != OUTDEV_PRINTER
)
562 // I'm not doing anything for a too small zoom
563 if ( properties
.aSScaleX
< aEdgeScale
|| properties
.aSScaleY
< aEdgeScale
)
567 static const tools::Long nAdd
= 20;
569 std::vector
<SwLineRect
*> aCheck
;
571 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
573 SwLineRect
& rL1
= m_aLineRects
[i
];
574 if ( !rL1
.GetTab() || rL1
.IsPainted() || rL1
.IsLocked() )
579 const bool bVert
= rL1
.Height() > rL1
.Width();
580 tools::Long nL1a
, nL1b
, nL1c
, nL1d
;
584 nL1a
= rL1
.Top(); nL1b
= rL1
.Left();
585 nL1c
= rL1
.Right(); nL1d
= rL1
.Bottom();
589 nL1a
= rL1
.Left(); nL1b
= rL1
.Top();
590 nL1c
= rL1
.Bottom(); nL1d
= rL1
.Right();
593 // Collect all lines to possibly link with i1
594 for (iterator it2
= m_aLineRects
.begin(); it2
!= m_aLineRects
.end(); ++it2
)
596 SwLineRect
&rL2
= *it2
;
597 if ( rL2
.GetTab() != rL1
.GetTab() ||
600 (bVert
== (rL2
.Height() > rL2
.Width())) )
603 tools::Long nL2a
, nL2b
, nL2c
, nL2d
;
606 nL2a
= rL2
.Top(); nL2b
= rL2
.Left();
607 nL2c
= rL2
.Right(); nL2d
= rL2
.Bottom();
611 nL2a
= rL2
.Left(); nL2b
= rL2
.Top();
612 nL2c
= rL2
.Bottom(); nL2d
= rL2
.Right();
615 if ( (nL1a
- nAdd
< nL2d
&& nL1d
+ nAdd
> nL2a
) &&
616 ((nL1b
> nL2b
&& nL1c
< nL2c
) ||
617 (nL1c
>= nL2c
&& nL1b
- nAdd
< nL2c
) ||
618 (nL1b
<= nL2b
&& nL1c
+ nAdd
> nL2b
)) )
620 aCheck
.push_back( &rL2
);
623 if ( aCheck
.size() < 2 )
626 bool bRemove
= false;
628 // For each line test all following ones.
629 for ( size_t k
= 0; !bRemove
&& k
< aCheck
.size(); ++k
)
631 SwLineRect
&rR1
= *aCheck
[k
];
633 for ( size_t k2
= k
+1; !bRemove
&& k2
< aCheck
.size(); ++k2
)
635 SwLineRect
&rR2
= *aCheck
[k2
];
638 SwLineRect
*pLA
= nullptr;
639 SwLineRect
*pLB
= nullptr;
640 if ( rR1
.Top() < rR2
.Top() )
642 pLA
= &rR1
; pLB
= &rR2
;
644 else if ( rR1
.Top() > rR2
.Top() )
646 pLA
= &rR2
; pLB
= &rR1
;
648 // are k1 and k2 describing a double line?
649 if ( pLA
&& pLA
->Bottom() + 60 > pLB
->Top() )
651 if ( rL1
.Top() < pLA
->Top() )
653 if ( rL1
.Bottom() == pLA
->Bottom() )
654 continue; //Small mistake (where?)
657 aIns
.Bottom( pLA
->Bottom() );
658 if ( !rL1
.Contains( aIns
) )
660 m_aLineRects
.emplace_back(aIns
, &rL1
.GetColor(),
661 SvxBorderLineStyle::SOLID
, rL1
.GetTab(),
671 if ( rL1
.Bottom() > pLB
->Bottom() )
672 rL1
.Top( pLB
->Top() ); // extend i1 on the top
674 bRemove
= true; //stopping, remove i1
679 SwLineRect
*pLA
= nullptr;
680 SwLineRect
*pLB
= nullptr;
681 if ( rR1
.Left() < rR2
.Left() )
683 pLA
= &rR1
; pLB
= &rR2
;
685 else if ( rR1
.Left() > rR2
.Left() )
687 pLA
= &rR2
; pLB
= &rR1
;
689 // Is it double line?
690 if ( pLA
&& pLA
->Right() + 60 > pLB
->Left() )
692 if ( rL1
.Left() < pLA
->Left() )
694 if ( rL1
.Right() == pLA
->Right() )
695 continue; //small error
698 aIns
.Right( pLA
->Right() );
699 if ( !rL1
.Contains( aIns
) )
701 m_aLineRects
.emplace_back(aIns
, &rL1
.GetColor(),
702 SvxBorderLineStyle::SOLID
, rL1
.GetTab(),
712 if ( rL1
.Right() > pLB
->Right() )
713 rL1
.Left( pLB
->Left() );
722 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
728 void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects
&rRects
, SwPaintProperties
const & properties
)
730 // All help lines that are covered by any border will be removed or split
731 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
733 // get a copy instead of a reference, because an <insert> may destroy
734 // the object due to a necessary array resize.
735 const SwLineRect
aSubsLineRect(m_aLineRects
[i
]);
737 // add condition <aSubsLineRect.IsLocked()> in order to consider only
738 // border lines, which are *not* locked.
739 if ( aSubsLineRect
.IsPainted() ||
740 aSubsLineRect
.IsLocked() )
743 const bool bVerticalSubs
= aSubsLineRect
.Height() > aSubsLineRect
.Width();
744 SwRect
aSubsRect( aSubsLineRect
);
747 aSubsRect
.AddLeft ( - (properties
.nSPixelSzW
+properties
.nSHalfPixelSzW
) );
748 aSubsRect
.AddRight ( properties
.nSPixelSzW
+properties
.nSHalfPixelSzW
);
752 aSubsRect
.AddTop ( - (properties
.nSPixelSzH
+properties
.nSHalfPixelSzH
) );
753 aSubsRect
.AddBottom( properties
.nSPixelSzH
+properties
.nSHalfPixelSzH
);
755 for (const_iterator itK
= rRects
.m_aLineRects
.begin(); itK
!= rRects
.m_aLineRects
.end();
758 const SwLineRect
&rLine
= *itK
;
760 // do *not* consider painted or locked border lines.
761 // #i1837# - locked border lines have to be considered.
762 if ( rLine
.IsLocked () )
765 if ( !bVerticalSubs
== ( rLine
.Height() > rLine
.Width() ) ) //same direction?
768 if ( aSubsRect
.Overlaps( rLine
) )
770 if ( bVerticalSubs
) // Vertical?
772 if ( aSubsRect
.Left() <= rLine
.Right() &&
773 aSubsRect
.Right() >= rLine
.Left() )
775 tools::Long nTmp
= rLine
.Top()-(properties
.nSPixelSzH
+1);
776 if ( aSubsLineRect
.Top() < nTmp
)
778 SwRect
aNewSubsRect( aSubsLineRect
);
779 aNewSubsRect
.Bottom( nTmp
);
780 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
781 aSubsLineRect
.GetStyle(), nullptr,
782 aSubsLineRect
.GetSubColor());
784 nTmp
= rLine
.Bottom()+properties
.nSPixelSzH
+1;
785 if ( aSubsLineRect
.Bottom() > nTmp
)
787 SwRect
aNewSubsRect( aSubsLineRect
);
788 aNewSubsRect
.Top( nTmp
);
789 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
790 aSubsLineRect
.GetStyle(), nullptr,
791 aSubsLineRect
.GetSubColor());
793 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
800 if ( aSubsRect
.Top() <= rLine
.Bottom() &&
801 aSubsRect
.Bottom() >= rLine
.Top() )
803 tools::Long nTmp
= rLine
.Left()-(properties
.nSPixelSzW
+1);
804 if ( aSubsLineRect
.Left() < nTmp
)
806 SwRect
aNewSubsRect( aSubsLineRect
);
807 aNewSubsRect
.Right( nTmp
);
808 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
809 aSubsLineRect
.GetStyle(), nullptr,
810 aSubsLineRect
.GetSubColor());
812 nTmp
= rLine
.Right()+properties
.nSPixelSzW
+1;
813 if ( aSubsLineRect
.Right() > nTmp
)
815 SwRect
aNewSubsRect( aSubsLineRect
);
816 aNewSubsRect
.Left( nTmp
);
817 m_aLineRects
.emplace_back(aNewSubsRect
, nullptr,
818 aSubsLineRect
.GetStyle(), nullptr,
819 aSubsLineRect
.GetSubColor());
821 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
831 void SwLineRects::LockLines( bool bLock
)
833 for (SwLineRect
& rLRect
: m_aLineRects
)
837 static void lcl_DrawDashedRect( OutputDevice
* pOut
, SwLineRect
const & rLRect
)
839 tools::Long startX
= rLRect
.Left( ), endX
;
840 tools::Long startY
= rLRect
.Top( ), endY
;
842 // Discriminate vertically stretched rect from horizontally stretched
843 // and restrict minimum nHalfLWidth to 1
844 tools::Long nHalfLWidth
= std::max( std::min( rLRect
.Width( ), rLRect
.Height( ) ) / 2, tools::Long(1) );
846 if ( rLRect
.Height( ) > rLRect
.Width( ) )
848 startX
+= nHalfLWidth
;
850 endY
= startY
+ rLRect
.Height( );
854 startY
+= nHalfLWidth
;
856 endX
= startX
+ rLRect
.Width( );
859 svtools::DrawLine( *pOut
, Point( startX
, startY
), Point( endX
, endY
),
860 sal_uInt32( nHalfLWidth
* 2 ), rLRect
.GetStyle( ) );
863 void SwLineRects::PaintLines( OutputDevice
*pOut
, SwPaintProperties
const &properties
)
865 // Paint the borders. Sadly two passes are needed.
866 // Once for the inside and once for the outside edges of tables
867 if (m_aLineRects
.size() == m_nLastCount
)
870 // #i16816# tagged pdf support
871 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
873 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
874 pOut
->SetFillColor();
875 pOut
->SetLineColor();
876 ConnectEdges( pOut
, properties
);
877 const Color
*pLast
= nullptr;
879 bool bPaint2nd
= false;
880 size_t nMinCount
= m_aLineRects
.size();
882 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
884 SwLineRect
& rLRect
= m_aLineRects
[i
];
886 if ( rLRect
.IsPainted() )
889 if ( rLRect
.IsLocked() )
891 nMinCount
= std::min( nMinCount
, i
);
895 // Paint it now or in the second pass?
897 if ( rLRect
.GetTab() )
899 if ( rLRect
.Height() > rLRect
.Width() )
901 // Vertical edge, overlapping with the table edge?
902 SwTwips nLLeft
= rLRect
.Left() - 30,
903 nLRight
= rLRect
.Right() + 30,
904 nTLeft
= rLRect
.GetTab()->getFrameArea().Left() + rLRect
.GetTab()->getFramePrintArea().Left(),
905 nTRight
= rLRect
.GetTab()->getFrameArea().Left() + rLRect
.GetTab()->getFramePrintArea().Right();
906 if ( (nTLeft
>= nLLeft
&& nTLeft
<= nLRight
) ||
907 (nTRight
>= nLLeft
&& nTRight
<= nLRight
) )
912 // Horizontal edge, overlapping with the table edge?
913 SwTwips nLTop
= rLRect
.Top() - 30,
914 nLBottom
= rLRect
.Bottom() + 30,
915 nTTop
= rLRect
.GetTab()->getFrameArea().Top() + rLRect
.GetTab()->getFramePrintArea().Top(),
916 nTBottom
= rLRect
.GetTab()->getFrameArea().Top() + rLRect
.GetTab()->getFramePrintArea().Bottom();
917 if ( (nTTop
>= nLTop
&& nTTop
<= nLBottom
) ||
918 (nTBottom
>= nLTop
&& nTBottom
<= nLBottom
) )
924 if ( !pLast
|| *pLast
!= rLRect
.GetColor() )
926 pLast
= &rLRect
.GetColor();
928 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
929 if( properties
.pSGlobalShell
->GetWin() &&
930 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
931 pOut
->SetDrawMode( DrawModeFlags::Default
);
933 pOut
->SetLineColor( *pLast
);
934 pOut
->SetFillColor( *pLast
);
935 pOut
->SetDrawMode( nOldDrawMode
);
938 if( !rLRect
.IsEmpty() )
939 lcl_DrawDashedRect( pOut
, rLRect
);
947 for (size_t i
= 0; i
< m_aLineRects
.size(); ++i
)
949 SwLineRect
& rLRect
= m_aLineRects
[i
];
950 if ( rLRect
.IsPainted() )
953 if ( rLRect
.IsLocked() )
955 nMinCount
= std::min( nMinCount
, i
);
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() )
967 pOut
->SetDrawMode( DrawModeFlags::Default
);
970 pOut
->SetFillColor( *pLast
);
971 pOut
->SetDrawMode( nOldDrawMode
);
973 if( !rLRect
.IsEmpty() )
974 lcl_DrawDashedRect( pOut
, rLRect
);
978 m_nLastCount
= nMinCount
;
983 void SwSubsRects::PaintSubsidiary( OutputDevice
*pOut
,
984 const SwLineRects
*pRects
,
985 SwPaintProperties
const & properties
)
987 if (m_aLineRects
.empty())
990 // #i16816# tagged pdf support
991 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
993 // Remove all help line that are almost covered (tables)
994 for (sal_Int32 i
= 0; i
!= static_cast<sal_Int32
>(m_aLineRects
.size()); ++i
)
996 SwLineRect
& rLi
= m_aLineRects
[i
];
997 const bool bVerticalSubs
= rLi
.Height() > rLi
.Width();
999 for (size_type k
= i
+ 1; k
!= m_aLineRects
.size(); ++k
)
1001 SwLineRect
& rLk
= m_aLineRects
[k
];
1002 if ( rLi
.SSize() == rLk
.SSize() )
1004 if ( bVerticalSubs
== ( rLk
.Height() > rLk
.Width() ) )
1006 if ( bVerticalSubs
)
1008 tools::Long nLi
= rLi
.Right();
1009 tools::Long nLk
= rLk
.Right();
1010 if ( rLi
.Top() == rLk
.Top() &&
1011 ((nLi
< rLk
.Left() && nLi
+21 > rLk
.Left()) ||
1012 (nLk
< rLi
.Left() && nLk
+21 > rLi
.Left())))
1014 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
1015 // don't continue with inner loop any more:
1016 // the array may shrink!
1023 tools::Long nLi
= rLi
.Bottom();
1024 tools::Long nLk
= rLk
.Bottom();
1025 if ( rLi
.Left() == rLk
.Left() &&
1026 ((nLi
< rLk
.Top() && nLi
+21 > rLk
.Top()) ||
1027 (nLk
< rLi
.Top() && nLk
+21 > rLi
.Top())))
1029 m_aLineRects
.erase(m_aLineRects
.begin() + i
);
1030 // don't continue with inner loop any more:
1031 // the array may shrink!
1041 if (pRects
&& (!pRects
->m_aLineRects
.empty()))
1042 RemoveSuperfluousSubsidiaryLines( *pRects
, properties
);
1044 if (m_aLineRects
.empty())
1047 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
1048 pOut
->SetLineColor();
1050 // Reset draw mode in high contrast mode in order to get fill color
1051 // set at output device. Recover draw mode after draw of lines.
1052 // Necessary for the subsidiary lines painted by the fly frames.
1053 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
1054 if( gProp
.pSGlobalShell
->GetWin() &&
1055 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1057 pOut
->SetDrawMode( DrawModeFlags::Default
);
1060 for (SwLineRect
& rLRect
: m_aLineRects
)
1062 // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
1063 if ( !rLRect
.IsPainted() &&
1064 !rLRect
.IsLocked() )
1066 const Color
*pCol
= nullptr;
1067 SwViewShell
*pShell
= properties
.pSGlobalShell
;
1068 const SwViewOption
*pOpt
= pShell
->GetViewOptions();
1069 switch ( rLRect
.GetSubColor() )
1071 case SubColFlags::Page
: pCol
= &pOpt
->GetDocBoundariesColor(); break;
1072 case SubColFlags::Tab
: pCol
= &pOpt
->GetTableBoundariesColor(); break;
1073 case SubColFlags::Fly
:
1074 case SubColFlags::Sect
: pCol
= &pOpt
->GetSectionBoundColor(); break;
1077 if (pCol
&& pOut
->GetFillColor() != *pCol
)
1078 pOut
->SetFillColor( *pCol
);
1079 pOut
->DrawRect( rLRect
.SVRect() );
1081 rLRect
.SetPainted();
1085 pOut
->SetDrawMode( nOldDrawMode
);
1090 // Various functions that are use in this file.
1093 * Function <SwAlignRect(..)> is also used outside this file
1095 * Correction: adjust rectangle on pixel level in order to make sure,
1096 * that the border "leaves its original pixel", if it has to
1097 * No prior adjustments for odd relation between pixel and twip
1099 void SwAlignRect( SwRect
&rRect
, const SwViewShell
*pSh
, const vcl::RenderContext
* pRenderContext
)
1101 if( !rRect
.HasArea() )
1104 // Make sure that view shell (parameter <pSh>) exists, if the output device
1105 // is taken from this view shell --> no output device, no alignment
1106 // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
1107 if ( !gProp
.bSFlyMetafile
&& !pSh
)
1112 const vcl::RenderContext
*pOut
= gProp
.bSFlyMetafile
?
1113 gProp
.pSFlyMetafileOut
.get() : pRenderContext
;
1115 // Hold original rectangle in pixel
1116 const tools::Rectangle aOrgPxRect
= pOut
->LogicToPixel( rRect
.SVRect() );
1117 // Determine pixel-center rectangle in twip
1118 const SwRect
aPxCenterRect( pOut
->PixelToLogic( aOrgPxRect
) );
1120 // Perform adjustments on pixel level.
1121 SwRect
aAlignedPxRect( aOrgPxRect
);
1122 if ( rRect
.Top() > aPxCenterRect
.Top() )
1124 // 'leave pixel overlapping on top'
1125 aAlignedPxRect
.AddTop( 1 );
1128 if ( rRect
.Bottom() < aPxCenterRect
.Bottom() )
1130 // 'leave pixel overlapping on bottom'
1131 aAlignedPxRect
.AddBottom( - 1 );
1134 if ( rRect
.Left() > aPxCenterRect
.Left() )
1136 // 'leave pixel overlapping on left'
1137 aAlignedPxRect
.AddLeft( 1 );
1140 if ( rRect
.Right() < aPxCenterRect
.Right() )
1142 // 'leave pixel overlapping on right'
1143 aAlignedPxRect
.AddRight( - 1 );
1146 // Consider negative width/height check, if aligned SwRect has negative width/height.
1147 // If Yes, adjust it to width/height = 0 twip.
1148 // NOTE: A SwRect with negative width/height can occur, if the width/height
1149 // of the given SwRect in twip was less than a pixel in twip and that
1150 // the alignment calculates that the aligned SwRect should not contain
1151 // the pixels the width/height is on.
1152 if ( aAlignedPxRect
.Width() < 0 )
1154 aAlignedPxRect
.Width(0);
1156 if ( aAlignedPxRect
.Height() < 0 )
1158 aAlignedPxRect
.Height(0);
1160 // Consider zero width/height for converting a rectangle from
1161 // pixel to logic it needs a width/height. Thus, set width/height
1162 // to one, if it's zero and correct this on the twip level after the conversion.
1163 bool bZeroWidth
= false;
1164 if ( aAlignedPxRect
.Width() == 0 )
1166 aAlignedPxRect
.Width(1);
1169 bool bZeroHeight
= false;
1170 if ( aAlignedPxRect
.Height() == 0 )
1172 aAlignedPxRect
.Height(1);
1176 rRect
= SwRect(pOut
->PixelToLogic( aAlignedPxRect
.SVRect() ));
1178 // Consider zero width/height and adjust calculated aligned twip rectangle.
1179 // Reset width/height to zero; previous negative width/height haven't to be considered.
1191 * Method to pixel-align rectangle for drawing graphic object
1193 * Because we are drawing graphics from the left-top-corner in conjunction
1194 * with size coordinates, these coordinates have to be calculated at a pixel
1196 * Thus, we convert the rectangle to pixel and then convert to left-top-corner
1197 * and then get size of pixel rectangle back to logic.
1198 * This calculation is necessary, because there's a different between
1199 * the conversion from logic to pixel of a normal rectangle with its left-top-
1200 * and right-bottom-corner and the same conversion of the same rectangle
1201 * with left-top-corner and size.
1203 * NOTE: Call this method before each <GraphicObject.Draw(...)>
1205 void SwAlignGrfRect( SwRect
*pGrfRect
, const vcl::RenderContext
&rOut
)
1207 tools::Rectangle aPxRect
= rOut
.LogicToPixel( pGrfRect
->SVRect() );
1208 pGrfRect
->Pos( rOut
.PixelToLogic( aPxRect
.TopLeft() ) );
1209 pGrfRect
->SSize( rOut
.PixelToLogic( aPxRect
.GetSize() ) );
1212 static tools::Long
lcl_AlignWidth( const tools::Long nWidth
, SwPaintProperties
const & properties
)
1216 const tools::Long nW
= nWidth
% properties
.nSPixelSzW
;
1218 if ( !nW
|| nW
> properties
.nSHalfPixelSzW
)
1219 return std::max(tools::Long(1), nWidth
- properties
.nSHalfPixelSzW
);
1224 static tools::Long
lcl_AlignHeight( const tools::Long nHeight
, SwPaintProperties
const & properties
)
1228 const tools::Long nH
= nHeight
% properties
.nSPixelSzH
;
1230 if ( !nH
|| nH
> properties
.nSHalfPixelSzH
)
1231 return std::max(tools::Long(1), nHeight
- properties
.nSHalfPixelSzH
);
1237 * Calculate PrtArea plus surrounding plus shadow
1239 static void lcl_CalcBorderRect( SwRect
&rRect
, const SwFrame
*pFrame
,
1240 const SwBorderAttrs
&rAttrs
,
1242 SwPaintProperties
const & properties
)
1244 // Special handling for cell frames.
1245 // The printing area of a cell frame is completely enclosed in the frame area
1246 // and a cell frame has no shadow. Thus, for cell frames the calculated
1247 // area equals the frame area.
1248 // Notes: Borders of cell frames in R2L text direction will switch its side
1249 // - left border is painted on the right; right border on the left.
1250 // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
1251 if( pFrame
->IsSctFrame() )
1253 rRect
= pFrame
->getFramePrintArea();
1254 rRect
.Pos() += pFrame
->getFrameArea().Pos();
1256 else if ( pFrame
->IsCellFrame() )
1257 rRect
= pFrame
->getFrameArea();
1260 rRect
= pFrame
->getFramePrintArea();
1261 rRect
.Pos() += pFrame
->getFrameArea().Pos();
1263 SwRectFnSet
fnRect(pFrame
);
1265 const SvxBoxItem
&rBox
= rAttrs
.GetBox();
1266 const bool bTop
= 0 != fnRect
.GetTopMargin(*pFrame
);
1267 if ( bTop
|| rBox
.GetTop() )
1269 SwTwips nDiff
= rBox
.GetTop() ?
1270 rBox
.CalcLineSpace( SvxBoxItemLine::TOP
, /*bEvenIfNoLine=*/false, /*bAllowNegative=*/true ) :
1271 rBox
.GetDistance( SvxBoxItemLine::TOP
);
1273 fnRect
.SubTop(rRect
, nDiff
);
1276 const bool bBottom
= 0 != fnRect
.GetBottomMargin(*pFrame
);
1281 if ( pFrame
->IsTabFrame() &&
1282 static_cast<const SwTabFrame
*>(pFrame
)->IsCollapsingBorders() )
1284 // For collapsing borders, we have to add the height of
1285 // the height of the last line
1286 nDiff
= static_cast<const SwTabFrame
*>(pFrame
)->GetBottomLineSize();
1290 nDiff
= rBox
.GetBottom() ?
1291 rBox
.CalcLineSpace( SvxBoxItemLine::BOTTOM
) :
1292 rBox
.GetDistance( SvxBoxItemLine::BOTTOM
);
1295 fnRect
.AddBottom(rRect
, nDiff
);
1298 if ( rBox
.GetLeft() )
1299 fnRect
.SubLeft(rRect
, rBox
.CalcLineSpace(SvxBoxItemLine::LEFT
));
1301 fnRect
.SubLeft(rRect
, rBox
.GetDistance(SvxBoxItemLine::LEFT
));
1303 if ( rBox
.GetRight() )
1304 fnRect
.AddRight(rRect
, rBox
.CalcLineSpace(SvxBoxItemLine::RIGHT
));
1306 fnRect
.AddRight(rRect
, rBox
.GetDistance(SvxBoxItemLine::RIGHT
));
1308 if ( bShadow
&& rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
)
1310 const SvxShadowItem
&rShadow
= rAttrs
.GetShadow();
1312 fnRect
.SubTop(rRect
, rShadow
.CalcShadowSpace(SvxShadowItemSide::TOP
));
1313 fnRect
.SubLeft(rRect
, rShadow
.CalcShadowSpace(SvxShadowItemSide::LEFT
));
1315 fnRect
.AddBottom(rRect
, rShadow
.CalcShadowSpace(SvxShadowItemSide::BOTTOM
));
1316 fnRect
.AddRight(rRect
, rShadow
.CalcShadowSpace(SvxShadowItemSide::RIGHT
));
1320 ::SwAlignRect( rRect
, properties
.pSGlobalShell
, properties
.pSGlobalShell
? properties
.pSGlobalShell
->GetOut() : nullptr );
1324 * Extend left/right border/shadow rectangle to bottom of previous frame/to
1325 * top of next frame, if border/shadow is joined with previous/next frame
1327 static void lcl_ExtendLeftAndRight( SwRect
& _rRect
,
1328 const SwFrame
& _rFrame
,
1329 const SwBorderAttrs
& _rAttrs
,
1330 const SwRectFn
& _rRectFn
)
1332 if ( _rAttrs
.JoinedWithPrev( _rFrame
) )
1334 const SwFrame
* pPrevFrame
= _rFrame
.GetPrev();
1335 (_rRect
.*_rRectFn
->fnSetTop
)( (pPrevFrame
->*_rRectFn
->fnGetPrtBottom
)() );
1337 if ( _rAttrs
.JoinedWithNext( _rFrame
) )
1339 const SwFrame
* pNextFrame
= _rFrame
.GetNext();
1340 (_rRect
.*_rRectFn
->fnSetBottom
)( (pNextFrame
->*_rRectFn
->fnGetPrtTop
)() );
1344 /// Returns a range suitable for subtraction when lcl_SubtractFlys() is used.
1345 /// Otherwise DrawFillAttributes() expands the clip path itself.
1346 static basegfx::B2DRange
lcl_ShrinkFly(const SwRect
& rRect
)
1348 static MapMode
aMapMode(MapUnit::MapTwip
);
1349 static const Size aSingleUnit
= Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode
);
1351 double x1
= rRect
.Left() + aSingleUnit
.getWidth();
1352 double y1
= rRect
.Top() + aSingleUnit
.getHeight();
1353 double x2
= rRect
.Right() - aSingleUnit
.getWidth();
1354 double y2
= rRect
.Bottom() - aSingleUnit
.getHeight();
1356 return basegfx::B2DRange(x1
, y1
, x2
, y2
);
1359 static void lcl_SubtractFlys( const SwFrame
*pFrame
, const SwPageFrame
*pPage
,
1360 const SwRect
&rRect
, SwRegionRects
&rRegion
, basegfx::utils::B2DClipState
& rClipState
, SwPaintProperties
const & rProperties
)
1362 const SwSortedObjs
& rObjs
= *pPage
->GetSortedObjs();
1363 const SwFlyFrame
* pSelfFly
= pFrame
->IsInFly() ? pFrame
->FindFlyFrame() : gProp
.pSRetoucheFly2
;
1364 if (!gProp
.pSRetoucheFly
)
1365 gProp
.pSRetoucheFly
= gProp
.pSRetoucheFly2
;
1367 for (size_t j
= 0; (j
< rObjs
.size()) && !rRegion
.empty(); ++j
)
1369 const SwAnchoredObject
* pAnchoredObj
= rObjs
[j
];
1370 const SdrObject
* pSdrObj
= pAnchoredObj
->GetDrawObj();
1372 // Do not consider invisible objects
1373 if (!pPage
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj
->GetLayer()))
1376 const SwFlyFrame
*pFly
= pAnchoredObj
->DynCastFlyFrame();
1380 if (pSelfFly
== pFly
|| gProp
.pSRetoucheFly
== pFly
|| !rRect
.Overlaps(pFly
->getFrameArea()))
1383 if (!pFly
->GetFormat()->GetPrint().GetValue() &&
1384 (OUTDEV_PRINTER
== gProp
.pSGlobalShell
->GetOut()->GetOutDevType() ||
1385 gProp
.pSGlobalShell
->IsPreview()))
1388 const bool bLowerOfSelf
= pSelfFly
&& pFly
->IsLowerOf( pSelfFly
);
1390 //For character bound Flys only examine those Flys in which it is not
1392 //Why only for character bound ones you may ask? It never makes sense to
1393 //subtract frames in which it is anchored itself right?
1394 if (pSelfFly
&& pSelfFly
->IsLowerOf(pFly
))
1397 //Any why does it not apply for the RetoucheFly too?
1398 if (gProp
.pSRetoucheFly
&& gProp
.pSRetoucheFly
->IsLowerOf(pFly
))
1401 #if OSL_DEBUG_LEVEL > 0
1402 //Flys who are anchored inside their own one, must have a bigger OrdNum
1403 //or be character bound.
1404 if (pSelfFly
&& bLowerOfSelf
)
1406 OSL_ENSURE( pFly
->IsFlyInContentFrame() ||
1407 pSdrObj
->GetOrdNumDirect() > pSelfFly
->GetVirtDrawObj()->GetOrdNumDirect(),
1408 "Fly with wrong z-Order" );
1412 bool bStopOnHell
= true;
1415 const SdrObject
*pTmp
= pSelfFly
->GetVirtDrawObj();
1416 if (pSdrObj
->GetLayer() == pTmp
->GetLayer())
1418 if (pSdrObj
->GetOrdNumDirect() < pTmp
->GetOrdNumDirect())
1419 //In the same layer we only observe those that are above.
1424 if (!bLowerOfSelf
&& !pFly
->GetFormat()->GetOpaque().GetValue())
1425 //From other layers we are only interested in non
1426 //transparent ones or those that are internal
1428 bStopOnHell
= false;
1431 if (gProp
.pSRetoucheFly
)
1433 const SdrObject
*pTmp
= gProp
.pSRetoucheFly
->GetVirtDrawObj();
1434 if ( pSdrObj
->GetLayer() == pTmp
->GetLayer() )
1436 if ( pSdrObj
->GetOrdNumDirect() < pTmp
->GetOrdNumDirect() )
1437 //In the same layer we only observe those that are above.
1442 if (!pFly
->IsLowerOf( gProp
.pSRetoucheFly
) && !pFly
->GetFormat()->GetOpaque().GetValue())
1443 //From other layers we are only interested in non
1444 //transparent ones or those that are internal
1446 bStopOnHell
= false;
1450 //If the content of the Fly is transparent, we subtract it only if it's
1451 //contained in the hell layer.
1452 const IDocumentDrawModelAccess
& rIDDMA
= pFly
->GetFormat()->getIDocumentDrawModelAccess();
1453 bool bHell
= pSdrObj
->GetLayer() == rIDDMA
.GetHellId();
1454 if (bStopOnHell
&& bHell
)
1457 /// Change internal order of condition
1458 /// first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()"
1459 /// have not to be performed, if frame is in "Hell"
1460 const SwFrame
* pLower
= pFly
->Lower();
1461 if (!bHell
&& pLower
&& pLower
->IsNoTextFrame() &&
1462 (static_cast<SwNoTextFrame
const*>(pLower
)->IsTransparent() ||
1463 static_cast<SwNoTextFrame
const*>(pLower
)->HasAnimation() ||
1464 pFly
->GetFormat()->GetSurround().IsContour()
1469 // Own if-statements for transparent background/shadow of fly frames
1470 // in order to handle special conditions.
1471 if (pFly
->IsBackgroundTransparent())
1473 // Background <pFly> is transparent drawn. Thus normally, its region
1474 // have not to be subtracted from given region.
1475 // But, if method is called for a fly frame and
1476 // <pFly> is a direct lower of this fly frame and
1477 // <pFly> inherites its transparent background brush from its parent,
1478 // then <pFly> frame area have to be subtracted from given region.
1479 // NOTE: Because in Status Quo transparent backgrounds can only be
1480 // assigned to fly frames, the handle of this special case
1481 // avoids drawing of transparent areas more than once, if
1482 // a fly frame inherites a transparent background from its
1483 // parent fly frame.
1484 if (pFrame
->IsFlyFrame() &&
1485 (pFly
->GetAnchorFrame()->FindFlyFrame() == pFrame
) &&
1486 pFly
->GetFormat()->IsBackgroundBrushInherited()
1490 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(pFly
) );
1491 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
1492 ::lcl_CalcBorderRect( aRect
, pFly
, rAttrs
, true, rProperties
);
1494 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1503 if (bHell
&& pFly
->GetAnchorFrame()->IsInFly())
1505 //So the border won't get dismantled by the background of the other
1508 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(pFly
) );
1509 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
1510 ::lcl_CalcBorderRect( aRect
, pFly
, rAttrs
, true, rProperties
);
1512 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1516 SwRect
aRect( pFly
->getFramePrintArea() );
1517 aRect
+= pFly
->getFrameArea().Pos();
1519 rClipState
.subtractRange(lcl_ShrinkFly(aRect
));
1522 if (gProp
.pSRetoucheFly
== gProp
.pSRetoucheFly2
)
1523 gProp
.pSRetoucheFly
= nullptr;
1526 static void lcl_implDrawGraphicBackground(const SvxBrushItem
& _rBackgrdBrush
,
1527 vcl::RenderContext
& _rOut
,
1528 const SwRect
& _rAlignedPaintRect
,
1529 const GraphicObject
& _rGraphicObj
,
1530 SwPaintProperties
const & properties
)
1532 /// determine color of background
1533 /// If color of background brush is not "no fill"/"auto fill" or
1534 /// <SwPaintProperties.bSFlyMetafile> is set, use color of background brush, otherwise
1535 /// use global retouche color.
1536 const Color
aColor( ( (_rBackgrdBrush
.GetColor() != COL_TRANSPARENT
) || properties
.bSFlyMetafile
)
1537 ? _rBackgrdBrush
.GetColor()
1538 : aGlobalRetoucheColor
);
1540 /// determine, if background color have to be drawn transparent
1541 /// and calculate transparency percent value
1542 sal_Int8 nTransparencyPercent
= 0;
1543 bool bDrawTransparent
= false;
1544 if ( aColor
.IsTransparent() )
1545 /// background color is transparent --> draw transparent.
1547 bDrawTransparent
= true;
1548 nTransparencyPercent
= ((255 - aColor
.GetAlpha())*100 + 0x7F)/0xFF;
1550 else if ( (_rGraphicObj
.GetAttr().IsTransparent()) &&
1551 (_rBackgrdBrush
.GetColor() == COL_TRANSPARENT
) )
1552 /// graphic is drawn transparent and background color is
1553 /// "no fill"/"auto fill" --> draw transparent
1555 bDrawTransparent
= true;
1556 nTransparencyPercent
= 100 - (_rGraphicObj
.GetAttr().GetAlpha() * 100 + 127) / 255;
1559 if ( bDrawTransparent
)
1561 /// draw background transparent
1562 if( _rOut
.GetFillColor() != aColor
.GetRGBColor() )
1563 _rOut
.SetFillColor( aColor
.GetRGBColor() );
1564 tools::PolyPolygon
aPoly( _rAlignedPaintRect
.SVRect() );
1565 _rOut
.DrawTransparent( aPoly
, nTransparencyPercent
);
1569 /// draw background opaque
1570 if ( _rOut
.GetFillColor() != aColor
)
1571 _rOut
.SetFillColor( aColor
);
1572 _rOut
.DrawRect( _rAlignedPaintRect
.SVRect() );
1577 * This is a local help method to draw a background for a graphic
1579 * Under certain circumstances we have to draw a background for a graphic.
1580 * This method takes care of the conditions and draws the background with the
1581 * corresponding color.
1582 * Method introduced for bug fix #103876# in order to optimize drawing tiled
1583 * background graphics. Previously, this code was integrated in method
1584 * <lcl_DrawGraphic>.
1585 * Method implemented as an inline, checking the conditions and calling method
1586 * method <lcl_implDrawGraphicBackground(..)> for the intrinsic drawing.
1588 * @param _rBackgrdBrush
1589 * background brush contain the color the background has to be drawn.
1592 * output device the background has to be drawn in.
1594 * @param _rAlignedPaintRect
1595 * paint rectangle in the output device, which has to be drawn with the background.
1596 * rectangle have to be aligned by method ::SwAlignRect
1598 * @param _rGraphicObj
1599 * graphic object, for which the background has to be drawn. Used for checking
1600 * the transparency of its bitmap, its type and if the graphic is drawn transparent
1602 * @param _bNumberingGraphic
1603 * boolean indicating that graphic is used as a numbering.
1605 * @param _bBackgrdAlreadyDrawn
1606 * boolean (optional; default: false) indicating, if the background is already drawn.
1608 static void lcl_DrawGraphicBackground( const SvxBrushItem
& _rBackgrdBrush
,
1609 OutputDevice
& _rOut
,
1610 const SwRect
& _rAlignedPaintRect
,
1611 const GraphicObject
& _rGraphicObj
,
1612 bool _bNumberingGraphic
,
1613 SwPaintProperties
const & properties
,
1614 bool _bBackgrdAlreadyDrawn
= false)
1616 // draw background with background color, if
1617 // (1) graphic is not used as a numbering AND
1618 // (2) background is not already drawn AND
1619 // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
1620 if ( !_bNumberingGraphic
&&
1621 !_bBackgrdAlreadyDrawn
&&
1622 ( _rGraphicObj
.IsTransparent() || _rGraphicObj
.GetType() == GraphicType::NONE
)
1625 lcl_implDrawGraphicBackground( _rBackgrdBrush
, _rOut
, _rAlignedPaintRect
, _rGraphicObj
, properties
);
1630 * NNOTE: the transparency of the background graphic is saved in
1631 * SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency()
1632 * and is considered in the drawing of the graphic
1634 * Thus, to provide transparent background graphic for text frames nothing
1637 * Use align rectangle for drawing graphic Pixel-align coordinates for
1639 * Outsource code for drawing background of the graphic
1640 * with a background color in method <lcl_DrawGraphicBackground>
1642 * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
1644 static void lcl_DrawGraphic( const SvxBrushItem
& rBrush
, vcl::RenderContext
&rOutDev
,
1645 const SwViewShell
&rSh
, const SwRect
&rGrf
, const SwRect
&rOut
,
1647 SwPaintProperties
const & properties
,
1648 bool bBackgrdAlreadyDrawn
)
1649 // add parameter <bBackgrdAlreadyDrawn> to indicate
1650 // that the background is already drawn.
1652 // Calculate align rectangle from parameter <rGrf> and use aligned
1653 // rectangle <aAlignedGrfRect> in the following code
1654 SwRect aAlignedGrfRect
= rGrf
;
1655 ::SwAlignRect( aAlignedGrfRect
, &rSh
, &rOutDev
);
1657 // Change type from <bool> to <bool>.
1658 const bool bNotInside
= !rOut
.Contains( aAlignedGrfRect
);
1661 rOutDev
.Push( vcl::PushFlags::CLIPREGION
);
1662 rOutDev
.IntersectClipRegion( rOut
.SVRect() );
1665 GraphicObject
*pGrf
= const_cast<GraphicObject
*>(rBrush
.GetGraphicObject());
1667 OUString aOriginURL
= pGrf
->GetGraphic().getOriginURL();
1668 if (pGrf
->GetGraphic().GetType() == GraphicType::Default
&& !aOriginURL
.isEmpty())
1670 Graphic aGraphic
= vcl::graphic::loadFromURL(aOriginURL
);
1671 pGrf
->SetGraphic(aGraphic
);
1674 // Outsource drawing of background with a background color
1675 ::lcl_DrawGraphicBackground( rBrush
, rOutDev
, aAlignedGrfRect
, *pGrf
, bGrfNum
, properties
, bBackgrdAlreadyDrawn
);
1677 // Because for drawing a graphic left-top-corner and size coordinates are
1678 // used, these coordinates have to be determined on pixel level.
1679 ::SwAlignGrfRect( &aAlignedGrfRect
, rOutDev
);
1681 const basegfx::B2DHomMatrix
aGraphicTransform(
1682 basegfx::utils::createScaleTranslateB2DHomMatrix(
1683 aAlignedGrfRect
.Width(), aAlignedGrfRect
.Height(),
1684 aAlignedGrfRect
.Left(), aAlignedGrfRect
.Top()));
1686 paintGraphicUsingPrimitivesHelper(
1699 bool DrawFillAttributes(
1700 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& rFillAttributes
,
1701 const SwRect
& rOriginalLayoutRect
,
1702 const SwRegionRects
& rPaintRegion
,
1703 const basegfx::utils::B2DClipState
& rClipState
,
1704 vcl::RenderContext
& rOut
)
1706 if(rFillAttributes
&& rFillAttributes
->isUsed())
1708 basegfx::B2DRange
aPaintRange(
1709 rPaintRegion
.GetOrigin().Left(),
1710 rPaintRegion
.GetOrigin().Top(),
1711 rPaintRegion
.GetOrigin().Right(),
1712 rPaintRegion
.GetOrigin().Bottom());
1714 if (!aPaintRange
.isEmpty() &&
1715 !rPaintRegion
.empty() &&
1716 !basegfx::fTools::equalZero(aPaintRange
.getWidth()) &&
1717 !basegfx::fTools::equalZero(aPaintRange
.getHeight()))
1719 // need to expand for correct AAed and non-AAed visualization as primitive.
1720 // This must probably be removed again when we will be able to get all Writer visualization
1721 // as primitives and Writer prepares all it's stuff in high precision coordinates (also
1722 // needs to avoid moving boundaries around to better show overlapping stuff...)
1723 if (comphelper::IsFuzzing() || SvtOptionsDrawinglayer::IsAntiAliasing())
1725 // if AAed in principle expand by 0.5 in all directions. Since painting edges of
1726 // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
1727 // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
1728 // artifacts. Checked experimentally - a little bit more in Y is needed, probably
1729 // due to still existing integer alignment and crunching in writer.
1730 static const double fExpandX
= 0.55;
1731 static const double fExpandY
= 0.70;
1732 const basegfx::B2DVector
aSingleUnit(rOut
.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX
, fExpandY
));
1734 aPaintRange
.expand(aPaintRange
.getMinimum() - aSingleUnit
);
1735 aPaintRange
.expand(aPaintRange
.getMaximum() + aSingleUnit
);
1739 // if not AAed expand by one unit to bottom right due to the missing unit
1740 // from SwRect/Rectangle integer handling
1741 const basegfx::B2DVector
aSingleUnit(rOut
.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
1743 aPaintRange
.expand(aPaintRange
.getMaximum() + aSingleUnit
);
1746 const basegfx::B2DRange
aDefineRange(
1747 rOriginalLayoutRect
.Left(),
1748 rOriginalLayoutRect
.Top(),
1749 rOriginalLayoutRect
.Right(),
1750 rOriginalLayoutRect
.Bottom());
1752 const drawinglayer::primitive2d::Primitive2DContainer
& rSequence
= rFillAttributes
->getPrimitive2DSequence(
1756 if(rSequence
.size())
1758 drawinglayer::primitive2d::Primitive2DContainer
const*
1759 pPrimitives(&rSequence
);
1760 drawinglayer::primitive2d::Primitive2DContainer primitives
;
1761 // tdf#86578 the awful lcl_SubtractFlys hack
1762 if (rPaintRegion
.size() > 1 || rPaintRegion
[0] != rPaintRegion
.GetOrigin())
1764 basegfx::B2DPolyPolygon
const& maskRegion(rClipState
.getClipPoly());
1765 primitives
.resize(1);
1766 primitives
[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
1767 maskRegion
, drawinglayer::primitive2d::Primitive2DContainer(rSequence
));
1768 pPrimitives
= &primitives
;
1770 assert(pPrimitives
&& pPrimitives
->size());
1772 drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
1773 aViewInformation2D
.setViewTransformation(rOut
.GetViewTransformation());
1774 aViewInformation2D
.setViewport(aPaintRange
);
1776 std::unique_ptr
<drawinglayer::processor2d::BaseProcessor2D
> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1778 aViewInformation2D
) );
1779 pProcessor
->process(*pPrimitives
);
1789 const SvxBrushItem
*pBrush
,
1790 vcl::RenderContext
&rOutDev
,
1793 const sal_uInt8 nGrfNum
,
1794 const bool bConsiderBackgroundTransparency
)
1795 // Add 6th parameter to indicate that method should
1796 // consider background transparency, saved in the color of the brush item
1798 SwViewShell
&rSh
= *gProp
.pSGlobalShell
;
1799 bool bReplaceGrfNum
= GRFNUM_REPLACE
== nGrfNum
;
1800 bool bGrfNum
= GRFNUM_NO
!= nGrfNum
;
1802 SvxGraphicPosition ePos
= GPOS_NONE
;
1803 if( pBrush
&& !bReplaceGrfNum
)
1805 if( rSh
.GetViewOptions()->IsGraphic() )
1808 SfxObjectShell
* sh
= rSh
.GetDoc()->GetPersist();
1809 if (sh
!= nullptr && sh
->HasName()) {
1810 referer
= sh
->GetMedium()->GetName();
1812 const Graphic
* pGrf
= pBrush
->GetGraphic(referer
);
1813 if( pGrf
&& GraphicType::NONE
!= pGrf
->GetType() )
1815 ePos
= pBrush
->GetGraphicPos();
1816 if( pGrf
->IsSupportedGraphic() )
1817 // don't the use the specific output device! Bug 94802
1818 aGrfSize
= ::GetGraphicSizeTwip( *pGrf
, nullptr );
1822 bReplaceGrfNum
= bGrfNum
;
1826 aGrf
.SSize( aGrfSize
);
1828 bool bRetouche
= true;
1832 aGrf
.Pos() = rOrg
.Pos();
1836 aGrf
.Pos().setY( rOrg
.Top() );
1837 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1841 aGrf
.Pos().setY( rOrg
.Top() );
1842 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1846 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1847 aGrf
.Pos().setX( rOrg
.Left() );
1851 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1852 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1856 aGrf
.Pos().setY( rOrg
.Top() + rOrg
.Height()/2 - aGrfSize
.Height()/2 );
1857 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1861 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1862 aGrf
.Pos().setX( rOrg
.Left() );
1866 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1867 aGrf
.Pos().setX( rOrg
.Left() + rOrg
.Width()/2 - aGrfSize
.Width()/2 );
1871 aGrf
.Pos().setY( rOrg
.Bottom() - aGrfSize
.Height() );
1872 aGrf
.Pos().setX( rOrg
.Right() - aGrfSize
.Width() );
1877 // Despite the fact that the background graphic has to fill the complete
1878 // area, we already checked, whether the graphic will completely fill out
1879 // the region the <rOut> that is to be painted. Thus, nothing has to be
1881 // E.g. this is the case for a Fly Frame without a background
1882 // brush positioned on the border of the page which inherited the background
1883 // brush from the page.
1884 bRetouche
= !rOut
.Contains( aGrf
);
1889 // draw background of tiled graphic before drawing tiled graphic in loop
1890 // determine graphic object
1891 GraphicObject
* pGraphicObj
= const_cast< GraphicObject
* >(pBrush
->GetGraphicObject());
1892 // calculate aligned paint rectangle
1893 SwRect aAlignedPaintRect
= rOut
;
1894 ::SwAlignRect( aAlignedPaintRect
, &rSh
, &rOutDev
);
1895 // draw background color for aligned paint rectangle
1896 lcl_DrawGraphicBackground( *pBrush
, rOutDev
, aAlignedPaintRect
, *pGraphicObj
, bGrfNum
, gProp
);
1898 // set left-top-corner of background graphic to left-top-corner of the
1899 // area, from which the background brush is determined.
1900 aGrf
.Pos() = rOrg
.Pos();
1901 // setup clipping at output device
1902 rOutDev
.Push( vcl::PushFlags::CLIPREGION
);
1903 rOutDev
.IntersectClipRegion( rOut
.SVRect() );
1904 // use new method <GraphicObject::DrawTiled(::)>
1906 // calculate paint offset
1907 Point
aPaintOffset( aAlignedPaintRect
.Pos() - aGrf
.Pos() );
1908 // draw background graphic tiled for aligned paint rectangle
1910 // For PDF export, every draw operation for bitmaps takes a
1911 // noticeable amount of place (~50 characters). Thus, optimize
1912 // between tile bitmap size and number of drawing operations here.
1915 // n_chars = k1 * ---------- + k2 * A_bitmap
1918 // minimum n_chars is obtained for (derive for A_bitmap,
1919 // set to 0, take positive solution):
1921 // A_bitmap = Sqrt( ---- A_out )
1924 // where k1 is the number of chars per draw operation, and
1925 // k2 is the number of chars per bitmap pixel.
1926 // This is approximately 50 and 7 for current PDF writer, respectively.
1928 const double k1( 50 );
1929 const double k2( 7 );
1930 const Size
aSize( aAlignedPaintRect
.SSize() );
1931 const double Abitmap( k1
/k2
* static_cast<double>(aSize
.Width())*aSize
.Height() );
1933 pGraphicObj
->DrawTiled( rOutDev
,
1934 aAlignedPaintRect
.SVRect(),
1936 Size( aPaintOffset
.X(), aPaintOffset
.Y() ),
1937 std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap
)) + .5 ) ) );
1939 // reset clipping at output device
1941 // set <bDraw> and <bRetouche> to false, indicating that background
1942 // graphic and background are already drawn.
1943 bDraw
= bRetouche
= false;
1951 default: OSL_ENSURE( false, "new Graphic position?" );
1954 /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of
1955 /// graphic is already drawn or not.
1956 bool bGrfBackgrdAlreadyDrawn
= false;
1959 rOutDev
.Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
1960 rOutDev
.SetLineColor();
1962 // check, if an existing background graphic (not filling the complete
1963 // background) is transparent drawn and the background color is
1964 // "no fill" respectively "auto fill", if background transparency
1965 // has to be considered.
1966 // If YES, memorize transparency of background graphic.
1967 // check also, if background graphic bitmap is transparent.
1968 bool bTransparentGrfWithNoFillBackgrd
= false;
1969 sal_Int32 nGrfTransparency
= 0;
1970 bool bGrfIsTransparent
= false;
1971 if ( (ePos
!= GPOS_NONE
) &&
1972 (ePos
!= GPOS_TILED
) && (ePos
!= GPOS_AREA
)
1975 GraphicObject
*pGrf
= const_cast<GraphicObject
*>(pBrush
->GetGraphicObject());
1976 if ( bConsiderBackgroundTransparency
)
1978 GraphicAttr aGrfAttr
= pGrf
->GetAttr();
1979 if ( (aGrfAttr
.IsTransparent()) &&
1980 (pBrush
->GetColor() == COL_TRANSPARENT
)
1983 bTransparentGrfWithNoFillBackgrd
= true;
1984 nGrfTransparency
= 255 - aGrfAttr
.GetAlpha();
1987 if ( pGrf
->IsTransparent() )
1989 bGrfIsTransparent
= true;
1993 // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
1994 // instead of checking, if transparency is not set.
1995 const Color
aColor( pBrush
&&
1996 ( (pBrush
->GetColor() != COL_TRANSPARENT
) ||
1997 gProp
.bSFlyMetafile
)
1998 ? pBrush
->GetColor()
1999 : aGlobalRetoucheColor
);
2001 // determine, if background region have to be
2002 // drawn transparent.
2003 // background region has to be drawn transparent, if
2004 // background transparency have to be considered
2006 // ( background color is transparent OR
2007 // background graphic is transparent and background color is "no fill"
2013 } eDrawStyle
= Default
;
2015 if (bConsiderBackgroundTransparency
&&
2016 ( ( aColor
.IsTransparent()) ||
2017 bTransparentGrfWithNoFillBackgrd
) )
2019 eDrawStyle
= Transparent
;
2022 // #i75614# reset draw mode in high contrast mode in order to get fill color set
2023 const DrawModeFlags nOldDrawMode
= rOutDev
.GetDrawMode();
2024 if ( gProp
.pSGlobalShell
->GetWin() &&
2025 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2027 rOutDev
.SetDrawMode( DrawModeFlags::Default
);
2030 // If background region has to be drawn transparent, set only the RGB values of the background color as
2031 // the fill color for the output device.
2036 if( rOutDev
.GetFillColor() != aColor
.GetRGBColor() )
2037 rOutDev
.SetFillColor( aColor
.GetRGBColor() );
2042 if( rOutDev
.GetFillColor() != aColor
)
2043 rOutDev
.SetFillColor( aColor
);
2049 // restore draw mode
2050 rOutDev
.SetDrawMode( nOldDrawMode
);
2056 // background region have to be drawn transparent.
2057 // Thus, create a poly-polygon from the region and draw it with
2058 // the corresponding transparency percent.
2059 tools::PolyPolygon
aDrawPoly( rOut
.SVRect() );
2060 if ( aGrf
.HasArea() )
2062 if ( !bGrfIsTransparent
)
2064 // subtract area of background graphic from draw area
2065 // Consider only that part of the graphic area that is overlapping with draw area.
2066 SwRect aTmpGrf
= aGrf
;
2067 aTmpGrf
.Intersection( rOut
);
2068 if ( aTmpGrf
.HasArea() )
2070 tools::Polygon
aGrfPoly( aTmpGrf
.SVRect() );
2071 aDrawPoly
.Insert( aGrfPoly
);
2075 bGrfBackgrdAlreadyDrawn
= true;
2077 // calculate transparency percent:
2078 // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
2079 // If there is a background graphic with a background color "no fill"/"auto fill",
2080 // the transparency value is taken from the background graphic,
2081 // otherwise take the transparency value from the color.
2082 sal_Int8 nTransparencyPercent
= static_cast<sal_Int8
>(
2083 (( bTransparentGrfWithNoFillBackgrd
? nGrfTransparency
: (255 - aColor
.GetAlpha())
2084 )*100 + 0x7F)/0xFF);
2085 // draw poly-polygon transparent
2086 rOutDev
.DrawTransparent( aDrawPoly
, nTransparencyPercent
);
2093 SwRegionRects
aRegion( rOut
, 4 );
2094 if ( !bGrfIsTransparent
)
2097 bGrfBackgrdAlreadyDrawn
= true;
2098 // loop rectangles of background region, which has to be drawn
2099 for( size_t i
= 0; i
< aRegion
.size(); ++i
)
2101 rOutDev
.DrawRect( aRegion
[i
].SVRect() );
2108 if( bDraw
&& aGrf
.Overlaps( rOut
) )
2109 lcl_DrawGraphic( *pBrush
, rOutDev
, rSh
, aGrf
, rOut
, bGrfNum
, gProp
,
2110 bGrfBackgrdAlreadyDrawn
);
2112 if( bReplaceGrfNum
)
2114 const BitmapEx
& rBmp
= rSh
.GetReplacementBitmap(false);
2115 vcl::Font
aTmp( rOutDev
.GetFont() );
2116 Graphic::DrawEx(rOutDev
, OUString(), aTmp
, rBmp
, rOrg
.Pos(), rOrg
.SSize());
2121 * Local helper for SwRootFrame::PaintSwFrame(..) - Adjust given rectangle to pixel size
2123 * By OD at 27.09.2002 for #103636#
2124 * In order to avoid paint errors caused by multiple alignments (e.g. ::SwAlignRect(..))
2125 * and other changes to the to be painted rectangle, this method is called for the
2126 * rectangle to be painted in order to adjust it to the pixel it is overlapping
2128 static void lcl_AdjustRectToPixelSize( SwRect
& io_aSwRect
, const vcl::RenderContext
&aOut
)
2130 // local constant object of class <Size> to determine number of Twips
2131 // representing a pixel.
2132 const Size
aTwipToPxSize( aOut
.PixelToLogic( Size( 1,1 )) );
2134 // local object of class <Rectangle> in Twip coordinates
2135 // calculated from given rectangle aligned to pixel centers.
2136 const tools::Rectangle aPxCenterRect
= aOut
.PixelToLogic(
2137 aOut
.LogicToPixel( io_aSwRect
.SVRect() ) );
2139 // local constant object of class <Rectangle> representing given rectangle
2141 const tools::Rectangle aOrgPxRect
= aOut
.LogicToPixel( io_aSwRect
.SVRect() );
2143 // calculate adjusted rectangle from pixel centered rectangle.
2144 // Due to rounding differences <aPxCenterRect> doesn't exactly represents
2145 // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
2146 // Afterwards, adjust calculated Twip-positions of the all borders.
2147 tools::Rectangle aSizedRect
= aPxCenterRect
;
2148 aSizedRect
.AdjustLeft( -(aTwipToPxSize
.Width()/2 + 1) );
2149 aSizedRect
.AdjustRight( aTwipToPxSize
.Width()/2 + 1 );
2150 aSizedRect
.AdjustTop( -(aTwipToPxSize
.Height()/2 + 1) );
2151 aSizedRect
.AdjustBottom(aTwipToPxSize
.Height()/2 + 1);
2154 while ( aOut
.LogicToPixel(aSizedRect
).Left() < aOrgPxRect
.Left() )
2156 aSizedRect
.AdjustLeft( 1 );
2159 while ( aOut
.LogicToPixel(aSizedRect
).Right() > aOrgPxRect
.Right() )
2161 aSizedRect
.AdjustRight( -1 );
2164 while ( aOut
.LogicToPixel(aSizedRect
).Top() < aOrgPxRect
.Top() )
2166 aSizedRect
.AdjustTop( 1 );
2169 while ( aOut
.LogicToPixel(aSizedRect
).Bottom() > aOrgPxRect
.Bottom() )
2171 aSizedRect
.AdjustBottom( -1 );
2174 io_aSwRect
= SwRect( aSizedRect
);
2176 #if OSL_DEBUG_LEVEL > 0
2177 tools::Rectangle aTestOrgPxRect
= aOut
.LogicToPixel( io_aSwRect
.SVRect() );
2178 tools::Rectangle aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2179 OSL_ENSURE( aTestOrgPxRect
== aTestNewPxRect
,
2180 "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
2182 aSizedRect
.AdjustLeft( -1 );
2183 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2184 OSL_ENSURE( aTestOrgPxRect
.Left() >= (aTestNewPxRect
.Left()+1),
2185 "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
2186 aSizedRect
.AdjustLeft( 1 );
2188 aSizedRect
.AdjustRight( 1 );
2189 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2190 OSL_ENSURE( aTestOrgPxRect
.Right() <= (aTestNewPxRect
.Right()-1),
2191 "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
2192 aSizedRect
.AdjustRight( -1 );
2194 aSizedRect
.AdjustTop( -1 );
2195 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2196 OSL_ENSURE( aTestOrgPxRect
.Top() >= (aTestNewPxRect
.Top()+1),
2197 "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
2198 aSizedRect
.AdjustTop( 1 );
2200 aSizedRect
.AdjustBottom( 1 );
2201 aTestNewPxRect
= aOut
.LogicToPixel( aSizedRect
);
2202 OSL_ENSURE( aTestOrgPxRect
.Bottom() <= (aTestNewPxRect
.Bottom()-1),
2203 "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
2204 aSizedRect
.AdjustBottom( -1 );
2208 // FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
2217 SwTwips mnLimitedEndPos
;
2220 svx::frame::Style maAttribute
;
2222 enum OverlapType
{ NO_OVERLAP
, OVERLAP1
, OVERLAP2
, OVERLAP3
};
2224 enum class VerticalType
{ LEFT
, RIGHT
};
2227 SwLineEntry( SwTwips nKey
,
2231 const svx::frame::Style
& rAttribute
);
2233 OverlapType
Overlaps( const SwLineEntry
& rComp
) const;
2236 * Assuming that this entry is for a Word-style covering cell and the border matching eType is
2237 * set, limit the end position of this border in case covered cells have no borders set.
2239 void LimitVerticalEndPos(const SwFrame
& rFrame
, VerticalType eType
);
2244 SwLineEntry::SwLineEntry( SwTwips nKey
,
2248 const svx::frame::Style
& rAttribute
)
2250 mnStartPos( nStartPos
),
2251 mnEndPos( nEndPos
),
2254 maAttribute( rAttribute
)
2269 4. ------------- rOld
2278 7. ------------- rOld
2288 SwLineEntry::OverlapType
SwLineEntry::Overlaps( const SwLineEntry
& rNew
) const
2290 SwLineEntry::OverlapType eRet
= OVERLAP3
;
2292 if ( mnStartPos
>= rNew
.mnEndPos
|| mnEndPos
<= rNew
.mnStartPos
)
2296 else if ( mnEndPos
< rNew
.mnEndPos
)
2300 else if (mnStartPos
<= rNew
.mnStartPos
)
2307 void SwLineEntry::LimitVerticalEndPos(const SwFrame
& rFrame
, VerticalType eType
)
2309 if (!rFrame
.IsCellFrame())
2314 const auto& rCellFrame
= static_cast<const SwCellFrame
&>(rFrame
);
2315 std::vector
<const SwCellFrame
*> aCoveredCells
= rCellFrame
.GetCoveredCells();
2316 // Iterate in reverse order, so we can stop at the first cell that has a border. This can
2317 // determine what is the minimal end position that is safe to use as a limit.
2318 for (auto it
= aCoveredCells
.rbegin(); it
!= aCoveredCells
.rend(); ++it
)
2320 const SwCellFrame
* pCoveredCell
= *it
;
2321 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pCoveredCell
);
2322 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2323 const SvxBoxItem
& rBox
= rAttrs
.GetBox();
2324 if (eType
== VerticalType::LEFT
&& rBox
.GetLeft())
2329 if (eType
== VerticalType::RIGHT
&& rBox
.GetRight())
2334 mnLimitedEndPos
= pCoveredCell
->getFrameArea().Top();
2340 struct lt_SwLineEntry
2342 bool operator()( const SwLineEntry
& e1
, const SwLineEntry
& e2
) const
2344 return e1
.mnStartPos
< e2
.mnStartPos
;
2350 typedef std::set
< SwLineEntry
, lt_SwLineEntry
> SwLineEntrySet
;
2351 typedef std::map
< SwTwips
, SwLineEntrySet
> SwLineEntryMap
;
2355 class SwTabFramePainter
2357 SwLineEntryMap maVertLines
;
2358 SwLineEntryMap maHoriLines
;
2359 const SwTabFrame
& mrTabFrame
;
2361 void Insert( SwLineEntry
&, bool bHori
);
2362 void Insert(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
, const SwRect
&rPaintArea
);
2364 /// Inserts top border at the top of a follow table.
2365 void InsertFollowTopBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2366 bool bWordTableCell
, SwTwips nTop
, SwTwips nLeft
, SwTwips nRight
,
2368 void InsertMasterBottomBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2369 bool bWordTableCell
, SwTwips nBottom
, SwTwips nLeft
, SwTwips nRight
,
2370 bool bBottomIsOuter
);
2372 void HandleFrame(const SwLayoutFrame
& rFrame
, const SwRect
& rPaintArea
);
2373 void FindStylesForLine( Point
&,
2377 bool bOuter
) const;
2380 explicit SwTabFramePainter( const SwTabFrame
& rTabFrame
);
2382 void PaintLines( OutputDevice
& rDev
, const SwRect
& rRect
) const;
2387 SwTabFramePainter::SwTabFramePainter( const SwTabFrame
& rTabFrame
)
2388 : mrTabFrame( rTabFrame
)
2390 SwRect aPaintArea
= rTabFrame
.GetUpper()->GetPaintArea();
2391 HandleFrame(rTabFrame
, aPaintArea
);
2394 void SwTabFramePainter::HandleFrame(const SwLayoutFrame
& rLayoutFrame
, const SwRect
& rPaintArea
)
2396 // Add border lines of cell frames. Skip covered cells. Skip cells
2397 // in special row span row, which do not have a negative row span:
2398 if ( rLayoutFrame
.IsCellFrame() && !rLayoutFrame
.IsCoveredCell() )
2400 const SwCellFrame
* pThisCell
= static_cast<const SwCellFrame
*>(&rLayoutFrame
);
2401 const SwRowFrame
* pRowFrame
= static_cast<const SwRowFrame
*>(pThisCell
->GetUpper());
2402 const tools::Long nRowSpan
= pThisCell
->GetTabBox()->getRowSpan();
2403 if ( !pRowFrame
->IsRowSpanLine() || nRowSpan
> 1 || nRowSpan
< -1 )
2405 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), &rLayoutFrame
);
2406 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2407 const SvxBoxItem
& rBox
= rAttrs
.GetBox();
2408 Insert(rLayoutFrame
, rBox
, rPaintArea
);
2412 // Recurse into lower layout frames, but do not recurse into lower tabframes.
2413 const SwFrame
* pLower
= rLayoutFrame
.Lower();
2416 if (pLower
->IsLayoutFrame() && !pLower
->IsTabFrame())
2418 const SwLayoutFrame
* pLowerLayFrame
= static_cast<const SwLayoutFrame
*>(pLower
);
2419 HandleFrame(*pLowerLayFrame
, rPaintArea
);
2421 pLower
= pLower
->GetNext();
2425 void SwTabFramePainter::PaintLines(OutputDevice
& rDev
, const SwRect
& rRect
) const
2427 // #i16816# tagged pdf support
2428 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev
);
2430 SwLineEntryMap::const_iterator aIter
= maHoriLines
.begin();
2433 // color for subsidiary lines:
2434 const Color
& rCol( gProp
.pSGlobalShell
->GetViewOptions()->GetTableBoundariesColor() );
2436 // high contrast mode:
2437 // overrides the color of non-subsidiary lines.
2438 const Color
* pHCColor
= nullptr;
2439 DrawModeFlags nOldDrawMode
= rDev
.GetDrawMode();
2440 if( gProp
.pSGlobalShell
->GetWin() &&
2441 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2443 pHCColor
= &gProp
.pSGlobalShell
->GetViewOptions()->GetFontColor();
2444 rDev
.SetDrawMode( DrawModeFlags::Default
);
2447 const SwFrame
* pUpper
= mrTabFrame
.GetUpper();
2448 SwRect
aUpper( pUpper
->getFramePrintArea() );
2449 aUpper
.Pos() += pUpper
->getFrameArea().Pos();
2450 SwRect
aUpperAligned( aUpper
);
2451 ::SwAlignRect( aUpperAligned
, gProp
.pSGlobalShell
, &rDev
);
2453 // prepare SdrFrameBorderDataVector
2454 drawinglayer::primitive2d::SdrFrameBorderDataVector aData
;
2458 if ( bHori
&& aIter
== maHoriLines
.end() )
2460 aIter
= maVertLines
.begin();
2464 if ( !bHori
&& aIter
== maVertLines
.end() )
2467 const SwLineEntrySet
& rEntrySet
= (*aIter
).second
;
2468 for (const SwLineEntry
& rEntry
: rEntrySet
)
2470 const svx::frame::Style
& rEntryStyle( rEntry
.maAttribute
);
2475 aStart
.setX( rEntry
.mnStartPos
);
2476 aStart
.setY( rEntry
.mnKey
);
2477 aEnd
.setX( rEntry
.mnEndPos
);
2478 aEnd
.setY( rEntry
.mnKey
);
2482 aStart
.setX( rEntry
.mnKey
);
2483 aStart
.setY( rEntry
.mnStartPos
);
2484 aEnd
.setX( rEntry
.mnKey
);
2485 aEnd
.setY( rEntry
.mnEndPos
);
2488 svx::frame::Style aStyles
[ 7 ];
2489 aStyles
[ 0 ] = rEntryStyle
;
2490 FindStylesForLine(aStart
, aEnd
, aStyles
, bHori
, rEntry
.mbOuter
);
2492 if (!bHori
&& rEntry
.mnLimitedEndPos
)
2494 aEnd
.setY(rEntry
.mnLimitedEndPos
);
2497 SwRect
aRepaintRect( aStart
, aEnd
);
2499 // the repaint rectangle has to be moved a bit for the centered lines:
2500 SwTwips nRepaintRectSize
= !rEntryStyle
.GetWidth() ? 1 : rEntryStyle
.GetWidth();
2503 aRepaintRect
.Height( 2 * nRepaintRectSize
);
2504 aRepaintRect
.Pos().AdjustY( -nRepaintRectSize
);
2506 // To decide on visibility it is also necessary to expand the RepaintRect
2507 // to left/right according existing BorderLine overlap matchings, else there
2508 // will be repaint errors when scrolling in e.t TripleLine BorderLines.
2509 // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB
2510 if(aStyles
[1].IsUsed() || aStyles
[3].IsUsed() || aStyles
[4].IsUsed() || aStyles
[6].IsUsed())
2512 const double fLineWidthMaxLeft(std::max(aStyles
[1].GetWidth(), aStyles
[3].GetWidth()));
2513 const double fLineWidthMaxRight(std::max(aStyles
[4].GetWidth(), aStyles
[6].GetWidth()));
2514 aRepaintRect
.Width(aRepaintRect
.Width() + (fLineWidthMaxLeft
+ fLineWidthMaxRight
));
2515 aRepaintRect
.Pos().AdjustX( -fLineWidthMaxLeft
);
2520 aRepaintRect
.Width( 2 * nRepaintRectSize
);
2521 aRepaintRect
.Pos().AdjustX( -nRepaintRectSize
);
2523 // Accordingly to horizontal case, but for top/bottom
2524 // aStyles[3] == aTFromR, aStyles[1] == aTFromL, aStyles[6] == aBFromR, aStyles[4] == aBFromL
2525 if(aStyles
[3].IsUsed() || aStyles
[1].IsUsed() || aStyles
[6].IsUsed() || aStyles
[4].IsUsed())
2527 const double fLineWidthMaxTop(std::max(aStyles
[3].GetWidth(), aStyles
[1].GetWidth()));
2528 const double fLineWidthMaxBottom(std::max(aStyles
[6].GetWidth(), aStyles
[4].GetWidth()));
2529 aRepaintRect
.Height(aRepaintRect
.Height() + (fLineWidthMaxTop
+ fLineWidthMaxBottom
));
2530 aRepaintRect
.Pos().AdjustY( -fLineWidthMaxTop
);
2534 if (!rRect
.Overlaps(aRepaintRect
))
2540 const Color
* pTmpColor
= nullptr;
2541 if (0 == aStyles
[ 0 ].GetWidth())
2543 if (isSubsidiaryLinesEnabled() &&
2544 gProp
.pSGlobalShell
->GetViewOptions()->IsTableBoundaries() &&
2545 gProp
.pSGlobalShell
->GetWin())
2546 aStyles
[ 0 ].Set( rCol
, rCol
, rCol
, false, 1, 0, 0 );
2548 aStyles
[0].SetType(SvxBorderLineStyle::NONE
);
2551 pTmpColor
= pHCColor
;
2553 // The (twip) positions will be adjusted to meet these requirements:
2554 // 1. The y coordinates are located in the middle of the pixel grid
2555 // 2. The x coordinated are located at the beginning of the pixel grid
2556 // This is done, because the horizontal lines are painted "at
2557 // beginning", whereas the vertical lines are painted "centered".
2558 // By making the line sizes a multiple of one pixel size, we can
2559 // assure that all lines having the same twip size have the same
2560 // pixel size, independent of their position on the screen.
2561 Point aPaintStart
= rDev
.PixelToLogic( rDev
.LogicToPixel(aStart
) );
2562 Point aPaintEnd
= rDev
.PixelToLogic( rDev
.LogicToPixel(aEnd
) );
2564 if (gProp
.pSGlobalShell
->GetWin())
2566 // The table borders do not use SwAlignRect, but all the other frames do.
2567 // Therefore we tweak the outer borders a bit to achieve that the outer
2568 // borders match the subsidiary lines of the upper:
2569 if (aStart
.X() == aUpper
.Left())
2570 aPaintStart
.setX( aUpperAligned
.Left() );
2571 else if (aStart
.X() == aUpper
.Right_())
2572 aPaintStart
.setX( aUpperAligned
.Right_() );
2573 if (aStart
.Y() == aUpper
.Top())
2574 aPaintStart
.setY( aUpperAligned
.Top() );
2575 else if (aStart
.Y() == aUpper
.Bottom_())
2576 aPaintStart
.setY( aUpperAligned
.Bottom_() );
2578 if (aEnd
.X() == aUpper
.Left())
2579 aPaintEnd
.setX( aUpperAligned
.Left() );
2580 else if (aEnd
.X() == aUpper
.Right_())
2581 aPaintEnd
.setX( aUpperAligned
.Right_() );
2582 if (aEnd
.Y() == aUpper
.Top())
2583 aPaintEnd
.setY( aUpperAligned
.Top() );
2584 else if (aEnd
.Y() == aUpper
.Bottom_())
2585 aPaintEnd
.setY( aUpperAligned
.Bottom_() );
2588 if(aStyles
[0].IsUsed())
2592 const basegfx::B2DPoint
aOrigin(aPaintStart
.X(), aPaintStart
.Y());
2593 const basegfx::B2DVector
aX(basegfx::B2DPoint(aPaintEnd
.X(), aPaintEnd
.Y()) - aOrigin
);
2597 const basegfx::B2DVector
aY(basegfx::getNormalizedPerpendicular(aX
));
2603 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
2605 rInstance
.addSdrConnectStyleData(true, aStyles
[1], -aY
, true); // aLFromT
2606 rInstance
.addSdrConnectStyleData(true, aStyles
[2], -aX
, true); // aLFromL
2607 rInstance
.addSdrConnectStyleData(true, aStyles
[3], aY
, false); // aLFromB
2609 rInstance
.addSdrConnectStyleData(false, aStyles
[4], -aY
, true); // aRFromT
2610 rInstance
.addSdrConnectStyleData(false, aStyles
[5], aX
, false); // aRFromR
2611 rInstance
.addSdrConnectStyleData(false, aStyles
[6], aY
, false); // aRFromB
2616 const basegfx::B2DPoint
aOrigin(aPaintStart
.X(), aPaintStart
.Y());
2617 const basegfx::B2DVector
aX(basegfx::B2DPoint(aPaintEnd
.X(), aPaintEnd
.Y()) - aOrigin
);
2621 const basegfx::B2DVector
aY(basegfx::getNormalizedPerpendicular(aX
));
2627 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
2629 rInstance
.addSdrConnectStyleData(true, aStyles
[3], -aY
, false); // aTFromR
2630 rInstance
.addSdrConnectStyleData(true, aStyles
[2], -aX
, true); // aTFromT
2631 rInstance
.addSdrConnectStyleData(true, aStyles
[1], aY
, true); // aTFromL
2633 rInstance
.addSdrConnectStyleData(false, aStyles
[6], -aY
, false); // aBFromR
2634 rInstance
.addSdrConnectStyleData(false, aStyles
[5], aX
, false); // aBFromB
2635 rInstance
.addSdrConnectStyleData(false, aStyles
[4], aY
, true); // aBFromL
2643 // create instance of SdrFrameBorderPrimitive2D if
2644 // SdrFrameBorderDataVector is used
2647 drawinglayer::primitive2d::Primitive2DContainer aSequence
;
2649 new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
2651 true)); // force visualization to minimal one discrete unit (pixel)
2653 mrTabFrame
.ProcessPrimitives(aSequence
);
2656 // restore output device:
2657 rDev
.SetDrawMode( nOldDrawMode
);
2661 * Finds the lines that join the line defined by (StartPoint, EndPoint) in either
2662 * StartPoint or Endpoint. The styles of these lines are required for DR's magic
2663 * line painting functions
2665 void SwTabFramePainter::FindStylesForLine( Point
& rStartPoint
,
2667 svx::frame::Style
* pStyles
,
2668 bool bHori
, bool bOuter
) const
2670 // For example, aLFromB means: this vertical line intersects my horizontal line at its left end,
2672 // pStyles[ 1 ] = bHori ? aLFromT : TFromL
2673 // pStyles[ 2 ] = bHori ? aLFromL : TFromT,
2674 // pStyles[ 3 ] = bHori ? aLFromB : TFromR,
2675 // pStyles[ 4 ] = bHori ? aRFromT : BFromL,
2676 // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
2677 // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
2679 bool bWordTableCell
= false;
2680 SwViewShell
* pShell
= mrTabFrame
.getRootFrame()->GetCurrShell();
2683 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
2684 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
2687 SwLineEntryMap::const_iterator aMapIter
= maVertLines
.find( rStartPoint
.X() );
2688 assert(aMapIter
!= maVertLines
.end() && "FindStylesForLine: Error");
2689 const SwLineEntrySet
& rVertSet
= (*aMapIter
).second
;
2691 for ( const SwLineEntry
& rEntry
: rVertSet
)
2695 if ( rStartPoint
.Y() == rEntry
.mnStartPos
)
2696 pStyles
[ 3 ] = rEntry
.maAttribute
;
2697 else if ( rStartPoint
.Y() == rEntry
.mnEndPos
)
2698 pStyles
[ 1 ] = rEntry
.maAttribute
;
2700 if (bWordTableCell
&& rStartPoint
.X() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2702 rStartPoint
.AdjustX(rEntry
.maAttribute
.GetWidth());
2707 if ( rStartPoint
.Y() == rEntry
.mnEndPos
)
2708 pStyles
[ 2 ] = rEntry
.maAttribute
;
2709 else if ( rEndPoint
.Y() == rEntry
.mnStartPos
)
2710 pStyles
[ 5 ] = rEntry
.maAttribute
;
2714 aMapIter
= maHoriLines
.find( rStartPoint
.Y() );
2715 assert(aMapIter
!= maHoriLines
.end() && "FindStylesForLine: Error");
2716 const SwLineEntrySet
& rHoriSet
= aMapIter
->second
;
2718 for ( const SwLineEntry
& rEntry
: rHoriSet
)
2722 if ( rStartPoint
.X() == rEntry
.mnEndPos
)
2723 pStyles
[ 2 ] = rEntry
.maAttribute
;
2724 else if ( rEndPoint
.X() == rEntry
.mnStartPos
)
2725 pStyles
[ 5 ] = rEntry
.maAttribute
;
2729 if ( rStartPoint
.X() == rEntry
.mnEndPos
)
2730 pStyles
[ 1 ] = rEntry
.maAttribute
;
2731 else if ( rStartPoint
.X() == rEntry
.mnStartPos
)
2732 pStyles
[ 3 ] = rEntry
.maAttribute
;
2734 if (bWordTableCell
&& rStartPoint
.Y() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2736 rStartPoint
.AdjustY(rEntry
.maAttribute
.GetWidth());
2743 aMapIter
= maVertLines
.find( rEndPoint
.X() );
2744 assert(aMapIter
!= maVertLines
.end() && "FindStylesForLine: Error");
2745 const SwLineEntrySet
& rVertSet2
= (*aMapIter
).second
;
2747 for ( const SwLineEntry
& rEntry
: rVertSet2
)
2749 if ( rEndPoint
.Y() == rEntry
.mnStartPos
)
2750 pStyles
[ 6 ] = rEntry
.maAttribute
;
2751 else if ( rEndPoint
.Y() == rEntry
.mnEndPos
)
2752 pStyles
[ 4 ] = rEntry
.maAttribute
;
2754 if (bWordTableCell
&& rEndPoint
.X() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2756 rEndPoint
.AdjustX(-rEntry
.maAttribute
.GetWidth());
2762 aMapIter
= maHoriLines
.find( rEndPoint
.Y() );
2763 assert(aMapIter
!= maHoriLines
.end() && "FindStylesForLine: Error");
2764 const SwLineEntrySet
& rHoriSet2
= (*aMapIter
).second
;
2766 for ( const SwLineEntry
& rEntry
: rHoriSet2
)
2768 if ( rEndPoint
.X() == rEntry
.mnEndPos
)
2769 pStyles
[ 4 ] = rEntry
.maAttribute
;
2770 else if ( rEndPoint
.X() == rEntry
.mnStartPos
)
2771 pStyles
[ 6 ] = rEntry
.maAttribute
;
2773 if (bWordTableCell
&& rEndPoint
.Y() == rEntry
.mnKey
&& !bOuter
&& rEntry
.mbOuter
)
2775 rEndPoint
.AdjustY(-rEntry
.maAttribute
.GetWidth());
2782 * Special case: #i9860#
2783 * first line in follow table without repeated headlines
2784 * Special case: tdf#150308
2785 * first visible line of a table with preceding hidden deleted rows
2787 static bool lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
2788 SwTabFrame
const& rTabFrame
, SwFrame
const& rFrame
, SvxBoxItem
const& rBoxItem
)
2790 SwRowFrame
const*const pThisRowFrame
=
2791 dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2792 return (pThisRowFrame
2793 && (pThisRowFrame
->GetUpper() == &rTabFrame
)
2794 && ( rTabFrame
.IsFollow()
2795 // tdf#150308 first table row isn't equal to the table row of the first
2796 // row frame of the first table frame: there are invisible deleted rows
2797 // in Hide Changes mode before the first visible table row
2798 || rTabFrame
.GetTable()->GetTabLines().front() != pThisRowFrame
->GetTabLine() )
2799 && !rTabFrame
.GetTable()->GetRowsToRepeat()
2800 && ( !pThisRowFrame
->GetPrev()
2801 || static_cast<const SwRowFrame
*>(pThisRowFrame
->GetPrev())
2803 && !rBoxItem
.GetTop()
2804 && rBoxItem
.GetBottom());
2809 * last visible cell of a table row followed with a hidden deleted cell,
2810 * and the right border of the visible cell was painted by its left border
2812 static bool lcl_IsLastVisibleCellBeforeHiddenCellAtTheEndOfRow(
2813 SwFrame
const& rFrame
, SvxBoxItem
const& rBoxItem
)
2815 SwRowFrame
const*const pThisRowFrame
=
2816 dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2817 const SwCellFrame
* pThisCell
= static_cast<const SwCellFrame
*>(&rFrame
);
2819 return pThisRowFrame
2820 // last visible cell
2821 && !rFrame
.GetNext()
2822 // it has only left border
2823 && !rBoxItem
.GetRight()
2824 && rBoxItem
.GetLeft()
2825 // last visible table cell isn't equal to the last cell:
2826 // there are invisible deleted cells in Hide Changes mode
2827 && pThisRowFrame
->GetTabLine()->GetTabBoxes().back() != pThisCell
->GetTabBox();
2830 void SwTabFramePainter::InsertFollowTopBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2831 bool bWordTableCell
, SwTwips nTop
, SwTwips nLeft
,
2832 SwTwips nRight
, bool bTopIsOuter
)
2834 // Figure out which cell to copy.
2836 const SwFrame
* pCell
= &rFrame
;
2839 if (!pCell
->GetPrev())
2845 pCell
= pCell
->GetPrev();
2848 auto pThisRow
= dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2849 if (!pThisRow
|| pThisRow
->GetUpper() != &mrTabFrame
)
2854 if (!mrTabFrame
.IsFollow() || mrTabFrame
.GetTable()->GetRowsToRepeat())
2859 if (pThisRow
->GetPrev() || rBoxItem
.GetTop() || rBoxItem
.GetBottom())
2864 // This is then a first row in a follow table, without repeated headlines.
2865 auto pLastRow
= dynamic_cast<const SwRowFrame
*>(mrTabFrame
.GetLastLower());
2866 if (!pLastRow
|| pLastRow
== pThisRow
)
2871 const SwFrame
* pLastCell
= pLastRow
->GetLower();
2877 for (int i
= 0; i
< nCol
; ++i
)
2879 if (!pLastCell
->GetNext())
2881 // Reference row has merged cells, work with the last possible one.
2885 pLastCell
= pLastCell
->GetNext();
2888 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pLastCell
);
2889 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2890 const SvxBoxItem
& rLastBoxItem
= rAttrs
.GetBox();
2891 if (!rLastBoxItem
.GetBottom())
2896 // The matching (same column) row in the last row has a bottom border for us.
2897 svx::frame::Style
aFollowB(rLastBoxItem
.GetBottom(), 1.0);
2898 aFollowB
.SetWordTableCell(bWordTableCell
);
2899 SwLineEntry
aFollowTop(nTop
, nLeft
, nRight
, bTopIsOuter
, aFollowB
);
2900 aFollowB
.SetRefMode(svx::frame::RefMode::Begin
);
2901 Insert(aFollowTop
, true);
2904 void SwTabFramePainter::InsertMasterBottomBorder(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
,
2905 bool bWordTableCell
, SwTwips nBottom
, SwTwips nLeft
,
2906 SwTwips nRight
, bool bBottomIsOuter
)
2908 // Figure out which cell to copy.
2910 const SwFrame
* pCell
= &rFrame
;
2913 if (!pCell
->GetPrev())
2919 pCell
= pCell
->GetPrev();
2922 auto pThisRow
= dynamic_cast<const SwRowFrame
*>(rFrame
.GetUpper());
2923 if (!pThisRow
|| pThisRow
->GetUpper() != &mrTabFrame
)
2928 if (mrTabFrame
.IsFollow() || !mrTabFrame
.GetFollow())
2933 // This is a master table that is split.
2934 if (pThisRow
->GetNext() || rBoxItem
.GetTop() || rBoxItem
.GetBottom())
2939 // This is then a last row in a master table.
2940 auto pFirstRow
= dynamic_cast<const SwRowFrame
*>(mrTabFrame
.GetLower());
2941 if (!pFirstRow
|| pFirstRow
== pThisRow
)
2946 const SwFrame
* pFirstCell
= pFirstRow
->GetLower();
2952 for (int i
= 0; i
< nCol
; ++i
)
2954 if (!pFirstCell
->GetNext())
2956 // Reference row has merged cells, work with the last possible one.
2960 pFirstCell
= pFirstCell
->GetNext();
2963 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pFirstCell
);
2964 const SwBorderAttrs
& rAttrs
= *aAccess
.Get();
2965 const SvxBoxItem
& rFirstBoxItem
= rAttrs
.GetBox();
2966 if (!rFirstBoxItem
.GetTop())
2971 // The matching (same column) row in the first row has a top border for us.
2972 svx::frame::Style
aMasterT(rFirstBoxItem
.GetTop(), 1.0);
2973 aMasterT
.SetWordTableCell(bWordTableCell
);
2974 SwLineEntry
aMasterBottom(nBottom
, nLeft
, nRight
, bBottomIsOuter
, aMasterT
);
2975 aMasterT
.SetRefMode(svx::frame::RefMode::Begin
);
2976 Insert(aMasterBottom
, true);
2979 void SwTabFramePainter::Insert(const SwFrame
& rFrame
, const SvxBoxItem
& rBoxItem
, const SwRect
& rPaintArea
)
2981 // build 4 line entries for the 4 borders:
2982 SwRect aBorderRect
= rFrame
.getFrameArea();
2984 aBorderRect
.Intersection(rPaintArea
);
2986 bool const bBottomAsTop(lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
2987 mrTabFrame
, rFrame
, rBoxItem
));
2988 bool const bLeftAsRight(lcl_IsLastVisibleCellBeforeHiddenCellAtTheEndOfRow(
2991 bool const bVert
= mrTabFrame
.IsVertical();
2992 bool const bR2L
= mrTabFrame
.IsRightToLeft();
2994 bool bWordTableCell
= false;
2995 SwViewShell
* pShell
= rFrame
.getRootFrame()->GetCurrShell();
2998 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
2999 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
3002 // no scaling needed, it's all in the primitives and the target device
3003 svx::frame::Style
aL(rBoxItem
.GetLeft(), 1.0);
3004 aL
.SetWordTableCell(bWordTableCell
);
3005 svx::frame::Style
aR(rBoxItem
.GetRight(), 1.0);
3006 aR
.SetWordTableCell(bWordTableCell
);
3007 svx::frame::Style
aT(rBoxItem
.GetTop(), 1.0);
3008 aT
.SetWordTableCell(bWordTableCell
);
3009 svx::frame::Style
aB(rBoxItem
.GetBottom(), 1.0);
3010 aB
.SetWordTableCell(bWordTableCell
);
3012 // First cell in a row.
3013 bool bLeftIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetLower() == &rFrame
;
3014 // Last cell in a row.
3015 bool bRightIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetNext() == nullptr;
3016 // First row in a table.
3017 bool bTopIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetUpper()->GetLower() == rFrame
.GetUpper();
3018 // Last row in a table.
3019 bool bBottomIsOuter
= rFrame
.IsCellFrame() && rFrame
.GetUpper()->GetNext() == nullptr;
3022 if (!bWordTableCell
|| !bBottomIsOuter
)
3024 // Outer horizontal lines are never mirrored in Word.
3028 const SwTwips nLeft
= aBorderRect
.Left_();
3029 const SwTwips nRight
= aBorderRect
.Right_();
3030 const SwTwips nTop
= aBorderRect
.Top_();
3031 const SwTwips nBottom
= aBorderRect
.Bottom_();
3033 aL
.SetRefMode( svx::frame::RefMode::Centered
);
3034 aR
.SetRefMode( svx::frame::RefMode::Centered
);
3035 aT
.SetRefMode( !bVert
? svx::frame::RefMode::Begin
: svx::frame::RefMode::End
);
3036 aB
.SetRefMode( !bVert
? svx::frame::RefMode::Begin
: svx::frame::RefMode::End
);
3038 if (bWordTableCell
&& bLeftIsOuter
)
3040 // Outer vertical lines are always mirrored in Word.
3044 SwLineEntry
aLeft (nLeft
, nTop
, nBottom
, bLeftIsOuter
,
3045 bVert
? aB
: (bR2L
? aR
: aL
));
3046 if (bWordTableCell
&& rBoxItem
.GetLeft())
3048 aLeft
.LimitVerticalEndPos(rFrame
, SwLineEntry::VerticalType::LEFT
);
3051 SwLineEntry
aRight (nRight
, nTop
, nBottom
, bRightIsOuter
,
3052 bVert
? (bBottomAsTop
? aB
: aT
) : ((bR2L
|| bLeftAsRight
) ? aL
: aR
));
3053 if (bWordTableCell
&& rBoxItem
.GetRight())
3055 aRight
.LimitVerticalEndPos(rFrame
, SwLineEntry::VerticalType::RIGHT
);
3058 SwLineEntry
aTop (nTop
, nLeft
, nRight
, bTopIsOuter
,
3059 bVert
? aL
: (bBottomAsTop
? aB
: aT
));
3061 SwLineEntry
aBottom(nBottom
, nLeft
, nRight
, bBottomIsOuter
,
3064 Insert( aLeft
, false );
3065 Insert( aRight
, false );
3066 Insert( aTop
, true );
3067 Insert( aBottom
, true );
3069 InsertMasterBottomBorder(rFrame
, rBoxItem
, bWordTableCell
, nBottom
, nLeft
, nRight
,
3071 InsertFollowTopBorder(rFrame
, rBoxItem
, bWordTableCell
, nTop
, nLeft
, nRight
, bTopIsOuter
);
3074 void SwTabFramePainter::Insert( SwLineEntry
& rNew
, bool bHori
)
3076 // get all lines from structure, that have key entry of pLE
3077 SwLineEntryMap
* pLine2
= bHori
? &maHoriLines
: &maVertLines
;
3078 const SwTwips nKey
= rNew
.mnKey
;
3079 SwLineEntryMap::iterator aMapIter
= pLine2
->find( nKey
);
3081 SwLineEntrySet
* pLineSet
= aMapIter
!= pLine2
->end() ? &((*aMapIter
).second
) : nullptr;
3084 (*pLine2
)[nKey
] = SwLineEntrySet();
3085 pLineSet
= &(*pLine2
)[ nKey
];
3087 SwLineEntrySet::iterator aIter
= pLineSet
->begin();
3089 bool bWordTableCell
= false;
3090 SwViewShell
* pShell
= mrTabFrame
.getRootFrame()->GetCurrShell();
3093 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
3094 bWordTableCell
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
3096 bool bR2L
= mrTabFrame
.IsRightToLeft();
3097 while ( aIter
!= pLineSet
->end() && rNew
.mnStartPos
< rNew
.mnEndPos
)
3099 const SwLineEntry
& rOld
= *aIter
;
3101 // The bWordTableCell code only works for LTR at the moment, avoid it for RTL.
3102 if (rOld
.mnLimitedEndPos
|| (bWordTableCell
&& (rOld
.mbOuter
!= rNew
.mbOuter
) && !bR2L
))
3104 // Don't merge with this line entry as it ends sooner than mnEndPos.
3109 const SwLineEntry::OverlapType nOverlapType
= rOld
.Overlaps( rNew
);
3111 const svx::frame::Style
& rOldAttr
= rOld
.maAttribute
;
3112 const svx::frame::Style
& rNewAttr
= rNew
.maAttribute
;
3113 const svx::frame::Style
& rCmpAttr
= std::max(rNewAttr
, rOldAttr
);
3115 if ( SwLineEntry::OVERLAP1
== nOverlapType
)
3117 OSL_ENSURE( rNew
.mnStartPos
>= rOld
.mnStartPos
, "Overlap type 3? How this?" );
3120 const SwLineEntry
aLeft(nKey
, rOld
.mnStartPos
, rNew
.mnStartPos
, rOld
.mbOuter
, rOldAttr
);
3122 // new middle segment
3123 const SwLineEntry
aMiddle(nKey
, rNew
.mnStartPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3125 // new right segment
3126 rNew
.mnStartPos
= rOld
.mnEndPos
;
3128 // update current lines set
3129 pLineSet
->erase( aIter
);
3130 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3131 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3133 aIter
= pLineSet
->begin();
3135 continue; // start over
3137 else if ( SwLineEntry::OVERLAP2
== nOverlapType
)
3140 const SwLineEntry
aLeft(nKey
, rOld
.mnStartPos
, rNew
.mnStartPos
, rOld
.mbOuter
, rOldAttr
);
3142 // new middle segment
3143 const SwLineEntry
aMiddle(nKey
, rNew
.mnStartPos
, rNew
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3145 // new right segment
3146 const SwLineEntry
aRight(nKey
, rNew
.mnEndPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rOldAttr
);
3148 // update current lines set
3149 pLineSet
->erase( aIter
);
3150 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3151 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3152 if ( aRight
.mnStartPos
< aRight
.mnEndPos
) pLineSet
->insert( aRight
);
3154 rNew
.mnStartPos
= rNew
.mnEndPos
; // rNew should not be inserted!
3156 break; // we are finished
3158 else if ( SwLineEntry::OVERLAP3
== nOverlapType
)
3161 const SwLineEntry
aLeft(nKey
, rNew
.mnStartPos
, rOld
.mnStartPos
, rOld
.mbOuter
, rNewAttr
);
3163 // new middle segment
3164 const SwLineEntry
aMiddle(nKey
, rOld
.mnStartPos
, rNew
.mnEndPos
, rOld
.mbOuter
, rCmpAttr
);
3166 // new right segment
3167 const SwLineEntry
aRight(nKey
, rNew
.mnEndPos
, rOld
.mnEndPos
, rOld
.mbOuter
, rOldAttr
);
3169 // update current lines set
3170 pLineSet
->erase( aIter
);
3171 if ( aLeft
.mnStartPos
< aLeft
.mnEndPos
) pLineSet
->insert( aLeft
);
3172 if ( aMiddle
.mnStartPos
< aMiddle
.mnEndPos
) pLineSet
->insert( aMiddle
);
3173 if ( aRight
.mnStartPos
< aRight
.mnEndPos
) pLineSet
->insert( aRight
);
3175 rNew
.mnStartPos
= rNew
.mnEndPos
; // rNew should not be inserted!
3177 break; // we are finished
3183 if ( rNew
.mnStartPos
< rNew
.mnEndPos
) // insert rest
3184 pLineSet
->insert( rNew
);
3189 * Paint once for every visible page which is touched by Rect
3191 * 1. Paint borders and backgrounds
3192 * 2. Paint the draw layer (frames and drawing objects) that is
3193 * below the document (hell)
3194 * 3. Paint the document content (text)
3195 * 4. Paint the draw layer that is above the document
3197 void SwRootFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, PaintFrameMode
) const
3199 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." );
3201 PROTOCOL( this, PROT::FileInit
, DbgAction::NONE
, nullptr)
3203 bool bResetRootPaint
= false;
3204 SwViewShell
*pSh
= mpCurrShell
;
3206 if ( pSh
->GetWin() )
3208 if ( pSh
->GetOut() == pSh
->GetWin()->GetOutDev() && !pSh
->GetWin()->IsVisible() )
3212 if (SwRootFrame::s_isInPaint
)
3214 SwPaintQueue::Add( pSh
, rRect
);
3219 SwRootFrame::s_isInPaint
= bResetRootPaint
= true;
3221 const IDocumentSettingAccess
& rIDSA
= pSh
->GetDoc()->getIDocumentSettingAccess();
3222 bool isPaintHellOverHF
= rIDSA
.get(DocumentSettingId::PAINT_HELL_OVER_HEADER_FOOTER
) && pSh
->Imp()->HasDrawView();
3223 std::unique_ptr
<SwSavePaintStatics
> pStatics
;
3224 if ( gProp
.pSGlobalShell
)
3225 pStatics
.reset(new SwSavePaintStatics());
3226 gProp
.pSGlobalShell
= pSh
;
3228 if( !pSh
->GetWin() )
3229 gProp
.pSProgress
= SfxProgress::GetActiveProgress( static_cast<SfxObjectShell
*>(pSh
->GetDoc()->GetDocShell()) );
3231 ::SwCalcPixStatics( pSh
->GetOut() );
3232 aGlobalRetoucheColor
= pSh
->Imp()->GetRetoucheColor();
3234 // Copy rRect; for one, rRect could become dangling during the below action, and for another it
3235 // needs to be copied to aRect anyway as that is modified further down below:
3236 SwRect
aRect( rRect
);
3238 //Trigger an action to clear things up if needed.
3239 //Using this trick we can ensure that all values are valid in all paints -
3240 //no problems, no special case(s).
3242 // Extend check on certain states of the 'current' <SwViewShell> instance to
3243 // all existing <SwViewShell> instances.
3244 bool bPerformLayoutAction( true );
3246 for(SwViewShell
& rTmpViewShell
: pSh
->GetRingContainer())
3248 if ( rTmpViewShell
.IsInEndAction() ||
3249 rTmpViewShell
.IsPaintInProgress() ||
3250 ( rTmpViewShell
.Imp()->IsAction() &&
3251 rTmpViewShell
.Imp()->GetLayAction().IsActionInProgress() ) )
3253 bPerformLayoutAction
= false;
3256 if(!bPerformLayoutAction
)
3260 if ( bPerformLayoutAction
)
3262 const_cast<SwRootFrame
*>(this)->ResetTurbo();
3263 SwLayAction
aAction( const_cast<SwRootFrame
*>(this), pSh
->Imp() );
3264 aAction
.SetPaint( false );
3265 aAction
.SetComplete( false );
3266 aAction
.SetReschedule( gProp
.pSProgress
!= nullptr );
3267 aAction
.Action(&rRenderContext
);
3269 if ( !pSh
->ActionPend() )
3270 pSh
->Imp()->DeletePaintRegion();
3273 aRect
.Intersection( pSh
->VisArea() );
3275 const bool bExtraData
= ::IsExtraData( GetFormat()->GetDoc() );
3277 gProp
.pSLines
.reset(new SwLineRects
); // Container for borders.
3279 // #104289#. During painting, something (OLE) can
3280 // load the linguistic, which in turn can cause a reformat
3281 // of the document. Dangerous! We better set this flag to
3282 // avoid the reformat.
3283 const bool bOldAction
= IsCallbackActionEnabled();
3284 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( false );
3286 const SwPageFrame
*pPage
= pSh
->Imp()->GetFirstVisPage(&rRenderContext
);
3288 // #126222. The positions of headers and footers of the previous
3289 // pages have to be updated, else these headers and footers could
3290 // get visible at a wrong position.
3291 const SwPageFrame
*pPageDeco
= static_cast<const SwPageFrame
*>(pPage
->GetPrev());
3294 pPageDeco
->PaintDecorators();
3295 OSL_ENSURE(!pPageDeco
->GetPrev() || pPageDeco
->GetPrev()->IsPageFrame(),
3296 "Neighbour of page is not a page.");
3297 pPageDeco
= static_cast<const SwPageFrame
*>(pPageDeco
->GetPrev());
3300 const bool bBookMode
= gProp
.pSGlobalShell
->GetViewOptions()->IsViewLayoutBookMode();
3301 if ( bBookMode
&& pPage
->GetPrev() && static_cast<const SwPageFrame
*>(pPage
->GetPrev())->IsEmptyPage() )
3302 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetPrev());
3305 const bool bGridPainting(pSh
->GetWin() && pSh
->Imp()->HasDrawView() && pSh
->Imp()->GetDrawView()->IsGridVisible());
3307 // Hide all page break controls before showing them again
3308 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
3311 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
3312 SwFrameControlsManager
& rMngr
= rEditWin
.GetFrameControlsManager();
3313 const SwPageFrame
* pHiddenPage
= pPage
;
3314 while ( pHiddenPage
->GetPrev() != nullptr )
3316 pHiddenPage
= static_cast< const SwPageFrame
* >( pHiddenPage
->GetPrev() );
3317 SwFrameControlPtr pControl
= rMngr
.GetControl( FrameControlType::PageBreak
, pHiddenPage
);
3319 pControl
->ShowAll( false );
3324 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
3328 const bool bPaintRightShadow
= pPage
->IsRightShadowNeeded();
3329 const bool bPaintLeftShadow
= pPage
->IsLeftShadowNeeded();
3330 const bool bRightSidebar
= pPage
->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT
;
3332 if ( !pPage
->IsEmptyPage() )
3335 SwPageFrame::GetBorderAndShadowBoundRect( pPage
->getFrameArea(), pSh
, &rRenderContext
, aPaintRect
,
3336 bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3338 if ( aRect
.Overlaps( aPaintRect
) )
3340 if ( pSh
->GetWin() )
3342 gProp
.pSSubsLines
.reset(new SwSubsRects
);
3343 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
3345 gProp
.pBLines
.reset(new BorderLines
);
3347 aPaintRect
.Intersection_( aRect
);
3350 pSh
->GetWin() && pSh
->IsInEndAction() )
3352 // enlarge paint rectangle to complete page width, subtract
3353 // current paint area and invalidate the resulting region.
3354 SwRectFnSet
aRectFnSet(pPage
);
3355 SwRect
aPageRectTemp( aPaintRect
);
3356 aRectFnSet
.SetLeftAndWidth( aPageRectTemp
,
3357 aRectFnSet
.GetLeft(pPage
->getFrameArea()),
3358 aRectFnSet
.GetWidth(pPage
->getFrameArea()) );
3359 aPageRectTemp
.Intersection_( pSh
->VisArea() );
3360 vcl::Region
aPageRectRegion( aPageRectTemp
.SVRect() );
3361 aPageRectRegion
.Exclude( aPaintRect
.SVRect() );
3362 pSh
->GetWin()->Invalidate( aPageRectRegion
, InvalidateFlags::Children
);
3366 // enlarge paint rectangle for objects overlapping the same pixel
3367 // in all cases and before the DrawingLayer overlay is initialized.
3368 lcl_AdjustRectToPixelSize( aPaintRect
, *(pSh
->GetOut()) );
3371 // moved paint pre-process for DrawingLayer overlay here since the above
3372 // code dependent from bExtraData may expand the PaintRect
3374 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3375 // really be used but handled by SwViewShell::ImplEndAction already
3376 const vcl::Region
aDLRegion(aPaintRect
.SVRect());
3377 pSh
->DLPrePaint2(aDLRegion
);
3380 if(OUTDEV_WINDOW
== gProp
.pSGlobalShell
->GetOut()->GetOutDevType())
3382 // changed method SwLayVout::Enter(..)
3383 // 2nd parameter is no longer <const> and will be set to the
3384 // rectangle the virtual output device is calculated from <aPaintRect>,
3385 // if the virtual output is used.
3386 s_pVout
->Enter(pSh
, aPaintRect
, !s_isNoVirDev
);
3388 // Adjust paint rectangle to pixel size
3389 // Thus, all objects overlapping on pixel level with the unadjusted
3390 // paint rectangle will be considered in the paint.
3391 lcl_AdjustRectToPixelSize( aPaintRect
, *(pSh
->GetOut()) );
3394 // maybe this can be put in the above scope. Since we are not sure, just leave it ATM
3395 s_pVout
->SetOrgRect( aPaintRect
);
3397 // determine background color of page for <PaintLayer> method
3398 // calls, paint <hell> or <heaven>
3399 const Color
aPageBackgrdColor(pPage
->GetDrawBackgroundColor());
3401 pPage
->PaintBaBo( aPaintRect
, pPage
);
3403 if ( pSh
->Imp()->HasDrawView() )
3405 gProp
.pSLines
->LockLines( true );
3406 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
3407 pSh
->Imp()->PaintLayer( rIDDMA
.GetHellId(),
3408 /*pPrintData*/nullptr,
3409 *pPage
, pPage
->getFrameArea(),
3411 pPage
->IsRightToLeft(),
3413 gProp
.pSLines
->PaintLines( pSh
->GetOut(), gProp
);
3414 gProp
.pSLines
->LockLines( false );
3417 if (isPaintHellOverHF
)
3419 if ( pSh
->GetDoc()->GetDocumentSettingManager().get( DocumentSettingId::BACKGROUND_PARA_OVER_DRAWINGS
) )
3420 pPage
->PaintBaBo( aPaintRect
, pPage
, /*bOnlyTextBackground=*/true, PAINT_HEADER_FOOTER
);
3421 pPage
->PaintSwFrame(rRenderContext
, aPaintRect
, PAINT_HEADER_FOOTER
);
3422 gProp
.pSLines
->LockLines( true );
3423 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
3424 pSh
->Imp()->PaintLayer( rIDDMA
.GetHeaderFooterHellId(),
3425 /*pPrintData*/nullptr,
3426 *pPage
, pPage
->getFrameArea(),
3428 pPage
->IsRightToLeft(),
3430 gProp
.pSLines
->PaintLines( pSh
->GetOut(), gProp
);
3431 gProp
.pSLines
->LockLines( false );
3434 if ( pSh
->GetDoc()->GetDocumentSettingManager().get( DocumentSettingId::BACKGROUND_PARA_OVER_DRAWINGS
) )
3435 pPage
->PaintBaBo( aPaintRect
, pPage
, /*bOnlyTextBackground=*/true, isPaintHellOverHF
? PAINT_NON_HEADER_FOOTER
: PAINT_ALL
);
3438 // collect sub-lines
3439 pPage
->RefreshSubsidiary( aPaintRect
);
3440 // paint special sub-lines
3441 gProp
.pSSpecSubsLines
->PaintSubsidiary( pSh
->GetOut(), nullptr, gProp
);
3443 pPage
->PaintSwFrame( rRenderContext
, aPaintRect
, isPaintHellOverHF
? PAINT_NON_HEADER_FOOTER
: PAINT_ALL
);
3445 // no paint of page border and shadow, if writer is in place mode.
3446 SwDocShell
* pShell
= pSh
->GetDoc()->GetDocShell();
3447 if( pSh
->GetWin() && pShell
&& !pShell
->IsInPlaceActive() )
3449 SwPageFrame::PaintBorderAndShadow( pPage
->getFrameArea(), pSh
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3450 SwPageFrame::PaintNotesSidebar( pPage
->getFrameArea(), pSh
, pPage
->GetPhyPageNum(), bRightSidebar
);
3453 gProp
.pSLines
->PaintLines( pSh
->GetOut(), gProp
);
3454 if ( pSh
->GetWin() )
3456 gProp
.pSSubsLines
->PaintSubsidiary( pSh
->GetOut(), gProp
.pSLines
.get(), gProp
);
3457 gProp
.pSSubsLines
.reset();
3458 gProp
.pSSpecSubsLines
.reset();
3460 // fdo#42750: delay painting these until after subsidiary lines
3461 // fdo#45562: delay painting these until after hell layer
3462 // fdo#47717: but do it before heaven layer
3464 SwTaggedPDFHelper
tag(nullptr, nullptr, nullptr, rRenderContext
);
3465 ProcessPrimitives(gProp
.pBLines
->GetBorderLines_Clear());
3468 if ( pSh
->Imp()->HasDrawView() )
3470 pSh
->Imp()->PaintLayer( pSh
->GetDoc()->getIDocumentDrawModelAccess().GetHeavenId(),
3471 /*pPrintData*/nullptr,
3472 *pPage
, pPage
->getFrameArea(),
3474 pPage
->IsRightToLeft(),
3479 pPage
->RefreshExtraData( aPaintRect
);
3481 gProp
.pBLines
.reset();
3485 // needed to move grid painting inside Begin/EndDrawLayer bounds and to change
3486 // output rect for it accordingly
3489 SdrPaintView
* pPaintView
= pSh
->Imp()->GetDrawView();
3490 SdrPageView
* pPageView
= pPaintView
->GetSdrPageView();
3491 pPageView
->DrawPageViewGrid(*pSh
->GetOut(), aPaintRect
.SVRect(), pSh
->GetViewOptions()->GetTextGridColor() );
3495 // moved paint post-process for DrawingLayer overlay here, see above
3497 pSh
->DLPostPaint2(true);
3501 pPage
->PaintDecorators( );
3502 pPage
->PaintBreak();
3504 else if ( bBookMode
&& pSh
->GetWin() && !pSh
->GetDoc()->GetDocShell()->IsInPlaceActive() )
3508 SwRect
aEmptyPageRect( pPage
->getFrameArea() );
3510 // code from vprint.cxx
3511 const SwPageFrame
& rFormatPage
= pPage
->GetFormatPage();
3512 aEmptyPageRect
.SSize( rFormatPage
.getFrameArea().SSize() );
3514 SwPageFrame::GetBorderAndShadowBoundRect( aEmptyPageRect
, pSh
, &rRenderContext
, aPaintRect
,
3515 bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3516 aPaintRect
.Intersection_( aRect
);
3518 if ( aRect
.Overlaps( aEmptyPageRect
) )
3520 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3521 // really be used but handled by SwViewShell::ImplEndAction already
3523 const vcl::Region
aDLRegion(aPaintRect
.SVRect());
3524 pSh
->DLPrePaint2(aDLRegion
);
3527 if( pSh
->GetOut()->GetFillColor() != aGlobalRetoucheColor
)
3528 pSh
->GetOut()->SetFillColor( aGlobalRetoucheColor
);
3530 pSh
->GetOut()->SetLineColor();
3531 // Use aligned page rectangle
3533 SwRect
aTmpPageRect( aEmptyPageRect
);
3534 ::SwAlignRect( aTmpPageRect
, pSh
, &rRenderContext
);
3535 aEmptyPageRect
= aTmpPageRect
;
3538 pSh
->GetOut()->DrawRect( aEmptyPageRect
.SVRect() );
3540 // paint empty page text
3541 const vcl::Font
& rEmptyPageFont
= SwPageFrame::GetEmptyPageFont();
3542 const vcl::Font
aOldFont( pSh
->GetOut()->GetFont() );
3544 pSh
->GetOut()->SetFont( rEmptyPageFont
);
3545 pSh
->GetOut()->DrawText( aEmptyPageRect
.SVRect(), SwResId( STR_EMPTYPAGE
),
3546 DrawTextFlags::VCenter
|
3547 DrawTextFlags::Center
|
3548 DrawTextFlags::Clip
);
3550 pSh
->GetOut()->SetFont( aOldFont
);
3551 // paint shadow and border for empty page
3552 SwPageFrame::PaintBorderAndShadow( aEmptyPageRect
, pSh
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
3553 SwPageFrame::PaintNotesSidebar( aEmptyPageRect
, pSh
, pPage
->GetPhyPageNum(), bRightSidebar
);
3556 pSh
->DLPostPaint2(true);
3561 OSL_ENSURE( !pPage
->GetNext() || pPage
->GetNext()->IsPageFrame(),
3562 "Neighbour of page is not a page." );
3563 pPage
= static_cast<const SwPageFrame
*>(pPage
->GetNext());
3566 gProp
.pSLines
.reset();
3568 if ( bResetRootPaint
)
3569 SwRootFrame::s_isInPaint
= false;
3574 gProp
.pSProgress
= nullptr;
3575 gProp
.pSGlobalShell
= nullptr;
3578 const_cast<SwRootFrame
*>(this)->SetCallbackActionEnabled( bOldAction
);
3581 static void lcl_EmergencyFormatFootnoteCont( SwFootnoteContFrame
*pCont
)
3583 vcl::RenderContext
* pRenderContext
= pCont
->getRootFrame()->GetCurrShell()->GetOut();
3585 //It's possible that the Cont will get destroyed.
3586 SwContentFrame
*pCnt
= pCont
->ContainsContent();
3587 while ( pCnt
&& pCnt
->IsInFootnote() )
3589 pCnt
->Calc(pRenderContext
);
3590 pCnt
= pCnt
->GetNextContentFrame();
3598 SwRectDist m_fnCheck
;
3599 tools::Long m_nLimit
;
3602 SwShortCut( const SwFrame
& rFrame
, const SwRect
& rRect
);
3603 bool Stop(const SwRect
& rRect
) const { return (rRect
.*m_fnCheck
)(m_nLimit
) > 0; }
3608 SwShortCut::SwShortCut( const SwFrame
& rFrame
, const SwRect
& rRect
)
3610 bool bVert
= rFrame
.IsVertical();
3611 bool bR2L
= rFrame
.IsRightToLeft();
3612 if( rFrame
.IsNeighbourFrame() && bVert
== bR2L
)
3616 m_fnCheck
= &SwRect::GetBottomDistance
;
3617 m_nLimit
= rRect
.Top();
3621 m_fnCheck
= &SwRect::GetLeftDistance
;
3622 m_nLimit
= rRect
.Left() + rRect
.Width();
3625 else if( bVert
== rFrame
.IsNeighbourFrame() )
3627 m_fnCheck
= &SwRect::GetTopDistance
;
3628 m_nLimit
= rRect
.Top() + rRect
.Height();
3632 if ( rFrame
.IsVertLR() )
3634 m_fnCheck
= &SwRect::GetLeftDistance
;
3635 m_nLimit
= rRect
.Right();
3639 m_fnCheck
= &SwRect::GetRightDistance
;
3640 m_nLimit
= rRect
.Left();
3645 void SwLayoutFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, PaintFrameMode ePaintFrameMode
) const
3647 if (!getFramePrintArea().HasArea() && !IsRowFrame())
3648 { // tdf#163032 row frame may contain rowspan>1 cell that must be painted
3649 return; // do not paint hidden frame
3652 // #i16816# tagged pdf support
3653 Frame_Info
aFrameInfo(*this, false);
3654 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr,
3655 PAINT_HEADER_FOOTER
== ePaintFrameMode
? nullptr : &aFrameInfo
,
3656 nullptr, rRenderContext
);
3657 ::std::optional
<SwTaggedPDFHelper
> oTaggedLink
;
3660 // tdf#154939 Link nested inside Figure
3661 auto const pItem(GetFormat()->GetAttrSet().GetItemIfSet(RES_URL
));
3662 if (pItem
&& !pItem
->GetURL().isEmpty())
3664 Frame_Info
linkInfo(*this, true);
3665 oTaggedLink
.emplace(nullptr, &linkInfo
, nullptr, rRenderContext
);
3669 const SwFrame
*pFrame
= Lower();
3673 pFrame
= SkipFrame(pFrame
, ePaintFrameMode
);
3677 SwFrameDeleteGuard
g(const_cast<SwLayoutFrame
*>(this)); // lock because Calc() and recursion
3678 SwShortCut
aShortCut( *pFrame
, rRect
);
3679 bool bCnt
= pFrame
->IsContentFrame();
3681 pFrame
->Calc(&rRenderContext
);
3683 if ( pFrame
->IsFootnoteContFrame() )
3685 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pFrame
)) );
3689 const SwPageFrame
*pPage
= nullptr;
3690 bool bWin
= gProp
.pSGlobalShell
->GetWin() != nullptr;
3691 if (comphelper::LibreOfficeKit::isTiledPainting())
3692 // Tiled rendering is similar to printing in this case: painting transparently multiple
3693 // times will result in darker colors: avoid that.
3696 while ( IsAnLower( pFrame
) )
3699 SwRect
aPaintRect( pFrame
->GetPaintArea() );
3700 if( aShortCut
.Stop( aPaintRect
) )
3702 if ( bCnt
&& gProp
.pSProgress
)
3703 SfxProgress::Reschedule();
3705 //We need to retouch if a frame explicitly requests it.
3706 //First do the retouch, because this could flatten the borders.
3707 if ( pFrame
->IsRetouche() )
3709 if ( pFrame
->IsRetoucheFrame() && bWin
&& !pFrame
->GetNext() )
3712 pPage
= FindPageFrame();
3713 pFrame
->Retouch( pPage
, rRect
);
3715 pFrame
->ResetRetouche();
3718 if ( rRect
.Overlaps( aPaintRect
) )
3720 if ( bCnt
&& pFrame
->IsCompletePaint() &&
3721 !(comphelper::LibreOfficeKit::isActive() && comphelper::LibreOfficeKit::isTiledPainting()) &&
3722 !rRect
.Contains( aPaintRect
) && Application::AnyInput( VclInputFlags::KEYBOARD
) )
3724 //fix(8104): It may happen, that the processing wasn't complete
3725 //but some parts of the paragraph were still repainted.
3726 //This could lead to the situation, that other parts of the
3727 //paragraph won't be repainted at all. The only solution seems
3728 //to be an invalidation of the window.
3729 //To not make it too severe the rectangle is limited by
3730 //painting the desired part and only invalidating the
3731 //remaining paragraph parts.
3732 if ( aPaintRect
.Left() == rRect
.Left() &&
3733 aPaintRect
.Right() == rRect
.Right() )
3735 aPaintRect
.Bottom( rRect
.Top() - 1 );
3736 if ( aPaintRect
.Height() > 0 )
3737 gProp
.pSGlobalShell
->InvalidateWindows(aPaintRect
);
3738 aPaintRect
.Top( rRect
.Bottom() + 1 );
3739 aPaintRect
.Bottom( pFrame
->getFrameArea().Bottom() );
3740 if ( aPaintRect
.Height() > 0 )
3741 gProp
.pSGlobalShell
->InvalidateWindows(aPaintRect
);
3742 aPaintRect
.Top( pFrame
->getFrameArea().Top() );
3743 aPaintRect
.Bottom( pFrame
->getFrameArea().Bottom() );
3747 gProp
.pSGlobalShell
->InvalidateWindows( aPaintRect
);
3748 pFrame
= pFrame
->GetNext();
3751 bCnt
= pFrame
->IsContentFrame();
3753 pFrame
->Calc(&rRenderContext
);
3758 pFrame
->ResetCompletePaint();
3759 aPaintRect
.Intersection_( rRect
);
3761 pFrame
->PaintSwFrame( rRenderContext
, aPaintRect
);
3763 if ( Lower() && Lower()->IsColumnFrame() )
3765 //Paint the column separator line if needed. The page is
3766 //responsible for the page frame - not the upper.
3767 const SwFrameFormat
*pFormat
= GetUpper() && GetUpper()->IsPageFrame()
3768 ? GetUpper()->GetFormat()
3770 const SwFormatCol
&rCol
= pFormat
->GetCol();
3771 if ( rCol
.GetLineAdj() != COLADJ_NONE
)
3774 pPage
= pFrame
->FindPageFrame();
3776 PaintColLines( aPaintRect
, rCol
, pPage
);
3780 if ( !bCnt
&& pFrame
->GetNext() && pFrame
->GetNext()->IsFootnoteContFrame() )
3781 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame
*>(static_cast<const SwFootnoteContFrame
*>(pFrame
->GetNext())) );
3783 pFrame
= pFrame
->GetNext();
3784 pFrame
= SkipFrame(pFrame
, ePaintFrameMode
);
3788 bCnt
= pFrame
->IsContentFrame();
3790 pFrame
->Calc(&rRenderContext
);
3795 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateDashedIndicatorPrimitive(
3796 const basegfx::B2DPoint
& rStart
, const basegfx::B2DPoint
& rEnd
,
3797 basegfx::BColor aColor
)
3799 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 1 );
3801 std::vector
< double > aStrokePattern
;
3802 basegfx::B2DPolygon aLinePolygon
;
3803 aLinePolygon
.append(rStart
);
3804 aLinePolygon
.append(rEnd
);
3806 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
3807 if ( rSettings
.GetHighContrastMode( ) )
3809 // Only a solid line in high contrast mode
3810 aColor
= rSettings
.GetDialogTextColor().getBColor();
3814 // Get a color for the contrast
3815 basegfx::BColor aHslLine
= basegfx::utils::rgb2hsl( aColor
);
3816 double nLuminance
= aHslLine
.getZ() * 2.5;
3817 if ( nLuminance
== 0 )
3819 else if ( nLuminance
>= 1.0 )
3820 nLuminance
= aHslLine
.getZ() * 0.4;
3821 aHslLine
.setZ( nLuminance
);
3822 const basegfx::BColor aOtherColor
= basegfx::utils::hsl2rgb( aHslLine
);
3824 // Compute the plain line
3826 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
3827 aLinePolygon
, aOtherColor
);
3829 // Dashed line in twips
3830 aStrokePattern
.push_back( 40 );
3831 aStrokePattern
.push_back( 40 );
3836 // Compute the dashed line primitive
3837 aSeq
[ aSeq
.size( ) - 1 ] =
3838 new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D (
3839 basegfx::B2DPolyPolygon( aLinePolygon
),
3840 drawinglayer::attribute::LineAttribute( aColor
),
3841 drawinglayer::attribute::StrokeAttribute( std::move(aStrokePattern
) ) );
3847 void SwPageFrame::PaintBreak( ) const
3849 if ( gProp
.pSGlobalShell
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
3850 gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() ||
3851 gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() ||
3852 gProp
.pSGlobalShell
->IsPreview() )
3855 const SwFrame
* pBodyFrame
= Lower();
3856 while ( pBodyFrame
&& !pBodyFrame
->IsBodyFrame() )
3857 pBodyFrame
= pBodyFrame
->GetNext();
3861 const SwLayoutFrame
* pLayBody
= static_cast< const SwLayoutFrame
* >( pBodyFrame
);
3862 const SwFlowFrame
*pFlowFrame
= pLayBody
->ContainsContent();
3864 // Test if the first node is a table
3865 const SwFrame
* pFirstFrame
= pLayBody
->Lower();
3866 if ( pFirstFrame
&& pFirstFrame
->IsTabFrame() )
3867 pFlowFrame
= static_cast< const SwTabFrame
* >( pFirstFrame
);
3869 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
3872 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
3873 SwFrameControlsManager
& rMngr
= rEditWin
.GetFrameControlsManager();
3875 if ( pFlowFrame
&& pFlowFrame
->IsPageBreak( true ) )
3876 rMngr
.SetPageBreakControl( this );
3878 rMngr
.RemoveControlsByType( FrameControlType::PageBreak
, this );
3881 SwLayoutFrame::PaintBreak( );
3884 void SwColumnFrame::PaintBreak( ) const
3886 if ( gProp
.pSGlobalShell
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
3887 gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() ||
3888 gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() ||
3889 gProp
.pSGlobalShell
->IsPreview() )
3892 const SwFrame
* pBodyFrame
= Lower();
3893 while ( pBodyFrame
&& !pBodyFrame
->IsBodyFrame() )
3894 pBodyFrame
= pBodyFrame
->GetNext();
3899 const SwContentFrame
*pCnt
= static_cast< const SwLayoutFrame
* >( pBodyFrame
)->ContainsContent();
3900 if ( !(pCnt
&& pCnt
->IsColBreak( true )) )
3903 // Paint the break only if:
3904 // * Not in header footer edition, to avoid conflicts with the
3905 // header/footer marker
3906 // * Non-printing characters are shown, as this is more consistent
3907 // with other formatting marks
3908 if ( !(!gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) &&
3909 !gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) &&
3910 gProp
.pSGlobalShell
->GetViewOptions()->IsLineBreak()) )
3913 SwRect
aRect( pCnt
->getFramePrintArea() );
3914 aRect
.Pos() += pCnt
->getFrameArea().Pos();
3917 basegfx::B2DPoint
aStart( double( aRect
.Left() ), aRect
.Top() );
3918 basegfx::B2DPoint
aEnd( double( aRect
.Right() ), aRect
.Top() );
3919 double nWidth
= aRect
.Width();
3920 if ( IsVertical( ) )
3922 aStart
= basegfx::B2DPoint( double( aRect
.Right() ), double( aRect
.Top() ) );
3923 aEnd
= basegfx::B2DPoint( double( aRect
.Right() ), double( aRect
.Bottom() ) );
3924 nWidth
= aRect
.Height();
3927 basegfx::BColor aLineColor
= gProp
.pSGlobalShell
->GetViewOptions()->GetPageBreakColor().getBColor();
3929 drawinglayer::primitive2d::Primitive2DContainer aSeq
=
3930 lcl_CreateDashedIndicatorPrimitive( aStart
, aEnd
, aLineColor
);
3932 // Add the text above
3933 OUString aBreakText
= SwResId(STR_COLUMN_BREAK
);
3935 basegfx::B2DVector aFontSize
;
3936 OutputDevice
* pOut
= gProp
.pSGlobalShell
->GetOut();
3937 vcl::Font aFont
= pOut
->GetSettings().GetStyleSettings().GetToolFont();
3938 aFont
.SetFontHeight( 8 * 20 );
3939 pOut
->SetFont( aFont
);
3940 drawinglayer::attribute::FontAttribute aFontAttr
= drawinglayer::primitive2d::getFontAttributeFromVclFont(
3941 aFontSize
, aFont
, IsRightToLeft(), false );
3943 tools::Rectangle aTextRect
;
3944 pOut
->GetTextBoundRect( aTextRect
, aBreakText
);
3945 tools::Long nTextOff
= ( nWidth
- aTextRect
.GetWidth() ) / 2;
3947 basegfx::B2DHomMatrix
aTextMatrix( basegfx::utils::createScaleTranslateB2DHomMatrix(
3948 aFontSize
.getX(), aFontSize
.getY(),
3949 aRect
.Left() + nTextOff
, aRect
.Top() ) );
3952 aTextMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix (
3953 aFontSize
.getX(), aFontSize
.getY(), 0.0, M_PI_2
,
3954 aRect
.Right(), aRect
.Top() + nTextOff
);
3958 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
3960 aBreakText
, 0, aBreakText
.getLength(),
3961 std::vector
< double >(),
3963 std::move(aFontAttr
),
3967 ProcessPrimitives( aSeq
);
3970 void SwLayoutFrame::PaintBreak( ) const
3972 const SwFrame
* pFrame
= Lower();
3975 if ( pFrame
->IsLayoutFrame() )
3976 static_cast< const SwLayoutFrame
*>( pFrame
)->PaintBreak( );
3977 pFrame
= pFrame
->GetNext();
3981 void SwPageFrame::PaintDecorators( ) const
3983 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
3987 SwEditWin
& rEditWin
= pWrtSh
->GetView().GetEditWin();
3989 const SwLayoutFrame
* pBody
= FindBodyCont();
3993 SwRect
aBodyRect( pBody
->getFrameArea() );
3995 if ( !(gProp
.pSGlobalShell
->GetOut()->GetOutDevType() != OUTDEV_PRINTER
&&
3996 !gProp
.pSGlobalShell
->GetViewOptions()->IsPDFExport() &&
3997 !gProp
.pSGlobalShell
->IsPreview() &&
3998 !gProp
.pSGlobalShell
->GetViewOptions()->IsReadonly() &&
3999 !gProp
.pSGlobalShell
->GetViewOptions()->getBrowseMode() &&
4000 ( gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) ||
4001 gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) )) )
4004 bool bRtl
= AllSettings::GetLayoutRTL();
4005 const SwRect
& rVisArea
= gProp
.pSGlobalShell
->VisArea();
4006 tools::Long nXOff
= std::min( aBodyRect
.Right(), rVisArea
.Right() );
4008 nXOff
= std::max( aBodyRect
.Left(), rVisArea
.Left() );
4011 if ( gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Header
) )
4013 const SwFrame
* pHeaderFrame
= Lower();
4014 if ( pHeaderFrame
&& !pHeaderFrame
->IsHeaderFrame() )
4015 pHeaderFrame
= nullptr;
4017 tools::Long nHeaderYOff
= aBodyRect
.Top();
4018 Point nOutputOff
= rEditWin
.LogicToPixel( Point( nXOff
, nHeaderYOff
) );
4019 rEditWin
.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Header
, nOutputOff
);
4023 if ( !gProp
.pSGlobalShell
->IsShowHeaderFooterSeparator( FrameControlType::Footer
) )
4026 const SwFrame
* pFootnoteContFrame
= Lower();
4027 while ( pFootnoteContFrame
)
4029 if ( pFootnoteContFrame
->IsFootnoteContFrame() )
4030 aBodyRect
.AddBottom( pFootnoteContFrame
->getFrameArea().Bottom() - aBodyRect
.Bottom() );
4031 pFootnoteContFrame
= pFootnoteContFrame
->GetNext();
4034 tools::Long nFooterYOff
= aBodyRect
.Bottom();
4035 Point nOutputOff
= rEditWin
.LogicToPixel( Point( nXOff
, nFooterYOff
) );
4036 rEditWin
.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Footer
, nOutputOff
);
4040 * For feature #99657#
4043 * determines, if background of fly frame has to be drawn transparent
4044 * declaration found in /core/inc/flyfrm.cxx
4046 * OD 08.10.2002 #103898# - If the background of the fly frame itself is not
4047 * transparent and the background is inherited from its parent/grandparent,
4048 * the background brush, used for drawing, has to be investigated for transparency.
4050 * @return true, if background is transparent drawn
4052 bool SwFlyFrame::IsBackgroundTransparent() const
4054 bool bBackgroundTransparent
= GetFormat()->IsBackgroundTransparent();
4055 if ( !bBackgroundTransparent
&&
4056 GetFormat()->IsBackgroundBrushInherited() )
4058 const SvxBrushItem
* pBackgroundBrush
= nullptr;
4059 std::optional
<Color
> xSectionTOXColor
;
4061 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
4063 if ( GetBackgroundBrush( aFillAttributes
, pBackgroundBrush
, xSectionTOXColor
, aDummyRect
, false, /*bConsiderTextBox=*/false) )
4065 if ( xSectionTOXColor
&&
4066 (xSectionTOXColor
->IsTransparent()) &&
4067 (xSectionTOXColor
!= COL_TRANSPARENT
) )
4069 bBackgroundTransparent
= true;
4071 else if(aFillAttributes
&& aFillAttributes
->isUsed())
4073 bBackgroundTransparent
= aFillAttributes
->isTransparent();
4075 else if ( pBackgroundBrush
)
4077 if ( (pBackgroundBrush
->GetColor().IsTransparent()) &&
4078 (pBackgroundBrush
->GetColor() != COL_TRANSPARENT
) )
4080 bBackgroundTransparent
= true;
4084 const GraphicObject
*pTmpGrf
=
4085 pBackgroundBrush
->GetGraphicObject();
4087 (pTmpGrf
->GetAttr().IsTransparent())
4090 bBackgroundTransparent
= true;
4097 return bBackgroundTransparent
;
4100 static void lcl_PaintReplacement( const SwRect
&rRect
, const SwViewShell
&rSh
)
4102 const BitmapEx
& rBmp
= const_cast<SwViewShell
&>(rSh
).GetReplacementBitmap(false);
4103 vcl::Font
aFont(rSh
.GetOut()->GetFont() );
4104 Graphic::DrawEx(*rSh
.GetOut(), OUString(), aFont
, rBmp
, rRect
.Pos(), rRect
.SSize());
4107 bool SwFlyFrame::IsPaint(SdrObject
*pObj
, const SwViewShell
& rSh
)
4109 SdrObjUserCall
*pUserCall
= GetUserCall(pObj
);
4111 if ( nullptr == pUserCall
)
4114 if ( (!rSh
.GetViewOptions()->IsDraw()
4115 && (dynamic_cast<SdrUnoObj
*>(pObj
) || dynamic_cast<SdrAttrObj
*>(pObj
) || dynamic_cast<SwFlyDrawObj
*>(pObj
)))
4116 || (!rSh
.GetViewOptions()->IsGraphic() && dynamic_cast<SwVirtFlyDrawObj
*>(pObj
)) )
4118 SwRect rBoundRect
= GetBoundRectOfAnchoredObj( pObj
);
4119 lcl_PaintReplacement(rBoundRect
, rSh
);
4124 //Attribute dependent, don't paint for printer or Preview
4125 bool bPaint
= gProp
.pSFlyOnlyDraw
||
4126 static_cast<SwContact
*>(pUserCall
)->GetFormat()->GetPrint().GetValue();
4128 bPaint
= rSh
.GetWin() && !rSh
.IsPreview();
4132 //The paint may be prevented by the superior Flys.
4133 SwFrame
*pAnch
= nullptr;
4134 if ( dynamic_cast< const SwFlyDrawObj
*>( pObj
) != nullptr ) // i#117962#
4138 if ( auto pFlyDraw
= dynamic_cast<SwVirtFlyDrawObj
*>( pObj
) )
4140 SwFlyFrame
*pFly
= pFlyDraw
->GetFlyFrame();
4141 if ( gProp
.pSFlyOnlyDraw
&& gProp
.pSFlyOnlyDraw
== pFly
)
4144 //Try to avoid displaying the intermediate stage, Flys which don't
4145 //overlap with the page on which they are anchored won't be
4147 //HACK: exception: printing of frames in tables, those can overlap
4148 //a page once in a while when dealing with oversized tables (HTML).
4149 SwPageFrame
*pPage
= pFly
->FindPageFrame();
4150 if ( pPage
&& pPage
->getFrameArea().Overlaps( pFly
->getFrameArea() ) )
4152 pAnch
= pFly
->AnchorFrame();
4158 // Consider 'virtual' drawing objects
4159 SwDrawContact
* pDrawContact
= dynamic_cast<SwDrawContact
*>(pUserCall
);
4160 pAnch
= pDrawContact
? pDrawContact
->GetAnchorFrame(pObj
) : nullptr;
4163 if ( !pAnch
->isFrameAreaPositionValid() )
4165 else if ( rSh
.GetOut() == rSh
.getIDocumentDeviceAccess().getPrinter( false ))
4167 //HACK: we have to omit some of the objects for printing,
4168 //otherwise they would be printed twice.
4169 //The objects should get printed if the TableHack is active
4170 //right now. Afterwards they must not be printed if the
4171 //page over which they float position wise gets printed.
4172 const SwPageFrame
*pPage
= pAnch
->FindPageFrame();
4173 if ( !pPage
->getFrameArea().Overlaps( SwRect(pObj
->GetCurrentBoundRect()) ) )
4179 if ( dynamic_cast< const SdrObjGroup
*>( pObj
) == nullptr )
4181 OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" );
4187 if ( pAnch
->IsInFly() )
4188 bPaint
= SwFlyFrame::IsPaint(pAnch
->FindFlyFrame()->GetVirtDrawObj(), rSh
);
4189 else if ( gProp
.pSFlyOnlyDraw
)
4198 void SwCellFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, PaintFrameMode
) const
4200 if ( GetLayoutRowSpan() >= 1 )
4201 SwLayoutFrame::PaintSwFrame( rRenderContext
, rRect
);
4206 struct BorderLinesGuard
4208 explicit BorderLinesGuard() : m_pBorderLines(std::move(gProp
.pBLines
))
4210 gProp
.pBLines
.reset(new BorderLines
);
4214 gProp
.pBLines
= std::move(m_pBorderLines
);
4217 std::unique_ptr
<BorderLines
> m_pBorderLines
;
4222 // set strikethrough for deleted objects anchored to character
4223 void SwFrame::SetDrawObjsAsDeleted( bool bDeleted
)
4225 if ( SwSortedObjs
*pObjs
= GetDrawObjs() )
4227 for (SwAnchoredObject
* pAnchoredObj
: *pObjs
)
4229 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
4231 pFly
->SetDeleted(bDeleted
);
4237 void SwFlyFrame::PaintSwFrame(vcl::RenderContext
& rRenderContext
, SwRect
const& rRect
, PaintFrameMode
) const
4239 //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
4240 SwViewShell
*pShell
= getRootFrame()->GetCurrShell();
4241 if (pShell
&& pShell
->GetDoc() && pShell
->GetDoc()->GetDocShell())
4243 bool bInGenerateThumbnail
= pShell
->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail();
4244 if (bInGenerateThumbnail
)
4246 const SwRect
& aVisRect
= pShell
->VisArea();
4247 if (!aVisRect
.Overlaps(getFrameArea()))
4252 //because of the overlapping of frames and drawing objects the flys have to
4253 //paint their borders (and those of the internal ones) directly.
4255 gProp
.pSLines
->LockLines(true);
4256 BorderLinesGuard blg
; // this should not paint borders added from PaintBaBo
4258 SwRect
aRect( rRect
);
4259 aRect
.Intersection_( getFrameArea() );
4261 rRenderContext
.Push( vcl::PushFlags::CLIPREGION
);
4262 rRenderContext
.SetClipRegion();
4263 const SwPageFrame
* pPage
= FindPageFrame();
4265 const SwNoTextFrame
*pNoText
= Lower() && Lower()->IsNoTextFrame()
4266 ? static_cast<const SwNoTextFrame
*>(Lower()) : nullptr;
4268 bool bIsChart
= false; //#i102950# don't paint additional borders for charts
4269 //check whether we have a chart
4272 const SwNoTextNode
* pNoTNd
= dynamic_cast<const SwNoTextNode
*>(pNoText
->GetNode());
4275 SwOLENode
* pOLENd
= const_cast<SwOLENode
*>(pNoTNd
->GetOLENode());
4276 if( pOLENd
&& pOLENd
->GetOLEObj().GetObject().IsChart() )
4282 bool bContour
= GetFormat()->GetSurround().IsContour();
4283 tools::PolyPolygon aPoly
;
4286 // add 2nd parameter with value <true>
4287 // to indicate that method is called for paint in order to avoid
4288 // load of the intrinsic graphic.
4289 bContour
= GetContour( aPoly
, true );
4292 // #i47804# - distinguish complete background paint
4293 // and margin paint.
4294 // paint complete background for Writer text fly frames
4295 bool bPaintCompleteBack( !pNoText
);
4296 // paint complete background for transparent graphic and contour,
4297 // if own background color exists.
4298 const bool bIsGraphicTransparent
= pNoText
&& pNoText
->IsTransparent();
4299 if ( !bPaintCompleteBack
&&
4300 ( bIsGraphicTransparent
|| bContour
) )
4302 const SwFlyFrameFormat
* pSwFrameFormat
= GetFormat();
4304 if (pSwFrameFormat
&& pSwFrameFormat
->supportsFullDrawingLayerFillAttributeSet())
4306 // check for transparency
4307 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
aFillAttributes(pSwFrameFormat
->getSdrAllFillAttributesHelper());
4309 // check if the new fill attributes are used
4310 if(aFillAttributes
&& aFillAttributes
->isUsed())
4312 bPaintCompleteBack
= true;
4317 std::unique_ptr
<SvxBrushItem
> aBack
= GetFormat()->makeBackgroundBrushItem();
4318 // to determine, if background has to be painted, by checking, if
4319 // background color is not COL_TRANSPARENT ("no fill"/"auto fill")
4320 // or a background graphic exists.
4321 bPaintCompleteBack
=
4322 aBack
->GetColor() != COL_TRANSPARENT
||
4323 aBack
->GetGraphicPos() != GPOS_NONE
;
4326 // paint of margin needed.
4327 const bool bPaintMarginOnly( !bPaintCompleteBack
&&
4328 getFramePrintArea().SSize() != getFrameArea().SSize() );
4330 // #i47804# - paint background of parent fly frame
4331 // for transparent graphics in layer Hell, if parent fly frame isn't
4332 // in layer Hell. It's only painted the intersection between the
4333 // parent fly frame area and the paint area <aRect>
4334 const IDocumentDrawModelAccess
& rIDDMA
= GetFormat()->getIDocumentDrawModelAccess();
4336 if (bIsGraphicTransparent
&&
4337 GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
) &&
4338 GetVirtDrawObj()->GetLayer() == rIDDMA
.GetHellId() &&
4339 GetAnchorFrame()->FindFlyFrame() )
4341 const SwFlyFrame
* pParentFlyFrame
= GetAnchorFrame()->FindFlyFrame();
4342 if ( pParentFlyFrame
->GetDrawObj()->GetLayer() !=
4343 rIDDMA
.GetHellId() )
4345 SwFlyFrame
* pOldRet
= gProp
.pSRetoucheFly2
;
4346 gProp
.pSRetoucheFly2
= const_cast<SwFlyFrame
*>(this);
4348 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pParentFlyFrame
);
4349 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4350 SwRect
aPaintRect( aRect
);
4351 aPaintRect
.Intersection_( pParentFlyFrame
->getFrameArea() );
4352 pParentFlyFrame
->PaintSwFrameBackground( aPaintRect
, pPage
, rAttrs
);
4354 gProp
.pSRetoucheFly2
= pOldRet
;
4358 if ( bPaintCompleteBack
|| bPaintMarginOnly
)
4360 //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder
4361 //receives the original Rect but PaintSwFrameBackground only the limited
4364 rRenderContext
.Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
4365 rRenderContext
.SetLineColor();
4367 pPage
= FindPageFrame();
4369 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(this) );
4370 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4374 SwRegionRects
aRegion( aRect
);
4376 // suppress painting of background in printing area for
4377 // non-transparent graphics.
4378 if ( bPaintMarginOnly
||
4379 ( pNoText
&& !bIsGraphicTransparent
) )
4381 //What we actually want to paint is the small stripe between
4382 //PrtArea and outer border.
4383 SwRect
aTmp( getFramePrintArea() ); aTmp
+= getFrameArea().Pos();
4388 rRenderContext
.Push();
4390 // apply clip region under the same conditions, which are
4391 // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region
4392 // for painting the graphic/OLE. Thus, the clip region is
4393 // also applied for the PDF export.
4394 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
4396 if ( !rRenderContext
.GetConnectMetaFile() || !pSh
|| !pSh
->GetWin() )
4398 rRenderContext
.SetClipRegion(vcl::Region(aPoly
));
4401 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4403 PaintSwFrameBackground( aRegion
[i
], pPage
, rAttrs
, false, true );
4406 rRenderContext
.Pop();
4410 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4412 PaintSwFrameBackground( aRegion
[i
], pPage
, rAttrs
, false, true );
4417 // paint border before painting background
4418 PaintSwFrameShadowAndBorder(rRect
, pPage
, rAttrs
);
4420 rRenderContext
.Pop();
4424 // fly frame will paint it's subsidiary lines and
4425 // the subsidiary lines of its lowers on its own, due to overlapping with
4426 // other fly frames or other objects.
4427 if( gProp
.pSGlobalShell
->GetWin()
4428 && !bIsChart
) //#i102950# don't paint additional borders for charts
4430 bool bSubsLineRectsCreated
;
4431 if ( gProp
.pSSubsLines
)
4433 // Lock already existing subsidiary lines
4434 gProp
.pSSubsLines
->LockLines( true );
4435 bSubsLineRectsCreated
= false;
4439 // create new subsidiary lines
4440 gProp
.pSSubsLines
.reset(new SwSubsRects
);
4441 bSubsLineRectsCreated
= true;
4444 bool bSpecSubsLineRectsCreated
;
4445 if ( gProp
.pSSpecSubsLines
)
4447 // Lock already existing special subsidiary lines
4448 gProp
.pSSpecSubsLines
->LockLines( true );
4449 bSpecSubsLineRectsCreated
= false;
4453 // create new special subsidiary lines
4454 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
4455 bSpecSubsLineRectsCreated
= true;
4457 // Add subsidiary lines of fly frame and its lowers
4458 RefreshLaySubsidiary( pPage
, aRect
);
4459 // paint subsidiary lines of fly frame and its lowers
4460 gProp
.pSSpecSubsLines
->PaintSubsidiary( &rRenderContext
, nullptr, gProp
);
4461 gProp
.pSSubsLines
->PaintSubsidiary(&rRenderContext
, gProp
.pSLines
.get(), gProp
);
4462 if ( !bSubsLineRectsCreated
)
4463 // unlock subsidiary lines
4464 gProp
.pSSubsLines
->LockLines( false );
4467 // delete created subsidiary lines container
4468 gProp
.pSSubsLines
.reset();
4471 if ( !bSpecSubsLineRectsCreated
)
4472 // unlock special subsidiary lines
4473 gProp
.pSSpecSubsLines
->LockLines( false );
4476 // delete created special subsidiary lines container
4477 gProp
.pSSpecSubsLines
.reset();
4481 SwLayoutFrame::PaintSwFrame( rRenderContext
, aRect
);
4486 SwTaggedPDFHelper
tag(nullptr, nullptr, nullptr, rRenderContext
);
4487 // first paint lines added by fly frame paint
4488 // and then unlock other lines.
4489 gProp
.pSLines
->PaintLines( &rRenderContext
, gProp
);
4490 gProp
.pSLines
->LockLines( false );
4491 // have to paint frame borders added in heaven layer here...
4492 ProcessPrimitives(gProp
.pBLines
->GetBorderLines_Clear());
4497 // crossing out for tracked deletion
4498 if ( GetAuthor() != std::string::npos
&& IsDeleted() )
4500 tools::Long startX
= aRect
.Left( ), endX
= aRect
.Right();
4501 tools::Long startY
= aRect
.Top( ), endY
= aRect
.Bottom();
4502 rRenderContext
.SetLineColor( SwPostItMgr::GetColorAnchor(GetAuthor()) );
4503 rRenderContext
.DrawLine(Point(startX
, startY
), Point(endX
, endY
));
4504 rRenderContext
.DrawLine(Point(startX
, endY
), Point(endX
, startY
));
4507 rRenderContext
.Pop();
4509 if ( gProp
.pSProgress
&& pNoText
)
4510 SfxProgress::Reschedule();
4513 void SwFlyFrame::PaintDecorators() const
4515 // Show the un-float button
4516 SwWrtShell
* pWrtSh
= dynamic_cast< SwWrtShell
* >( gProp
.pSGlobalShell
);
4519 UpdateUnfloatButton(pWrtSh
, IsShowUnfloatButton(pWrtSh
));
4523 SwView
* SwTextFrame::GetView()
4525 SwWrtShell
* pWrtSh
= dynamic_cast<SwWrtShell
*>(gProp
.pSGlobalShell
);
4530 return &pWrtSh
->GetView();
4533 void SwTextFrame::PaintParagraphStylesHighlighting() const
4535 // Maybe avoid the dynamic_cast and just use GetActiveWrtShell()
4536 // NO! Multiple windows will not display the highlighting correctly if GetActiveWrtShell is used.
4537 SwWrtShell
* pWrtSh
= dynamic_cast<SwWrtShell
*>(gProp
.pSGlobalShell
);
4542 if (!pWrtSh
->GetView().IsSpotlightParaStyles())
4545 vcl::RenderContext
* pRenderContext
= pWrtSh
->GetOut();
4546 if (!pRenderContext
)
4549 const SwTextFormatColl
* pColl
= GetTextNodeFirst()->GetTextColl();
4550 OUString sStyleName
= pColl
->GetName();
4553 int nStyleNumber(-1);
4555 bool bSpotlightStyle
;
4556 if (comphelper::LibreOfficeKit::isActive())
4558 // For simplicity in kit mode, we render in the document "all styles"
4559 bSpotlightStyle
= true;
4560 // Do this so these are stable across views regardless of an individual
4561 // user's selection mode in the style panel.
4562 nStyleNumber
= pWrtSh
->GetDoc()->GetTextFormatColls()->GetPos(pColl
);
4563 nStyleColor
= ColorHash(sStyleName
);
4567 StylesHighlighterColorMap
& rParaStylesColorMap
4568 = pWrtSh
->GetView().GetStylesHighlighterParaColorMap();
4569 bSpotlightStyle
= rParaStylesColorMap
.contains(sStyleName
);
4570 if (bSpotlightStyle
)
4572 nStyleNumber
= rParaStylesColorMap
[sStyleName
].second
;
4573 nStyleColor
= rParaStylesColorMap
[sStyleName
].first
;
4577 // draw styles highlighter
4578 if (bSpotlightStyle
)
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 aRect
= 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(nStyleColor
);
4607 pRenderContext
->SetLineColor(nStyleColor
);
4609 pRenderContext
->DrawRect(aRect
);
4611 // draw hatch pattern if paragraph has direct formatting
4612 if (SwDoc::HasParagraphDirectFormatting(SwPosition(*GetTextNodeForParaProps())))
4614 Color
aHatchColor(nStyleColor
);
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(aRect
), aHatch
);
4621 pRenderContext
->SetFont(aFont
);
4622 pRenderContext
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default
);
4623 pRenderContext
->SetTextFillColor(nStyleColor
);
4624 pRenderContext
->DrawText(aRect
, OUString::number(nStyleNumber
),
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
, PaintFrameMode
) const
4640 if (!getFramePrintArea().HasArea())
4642 return; // do not paint hidden frame
4644 const SwViewOption
* pViewOption
= gProp
.pSGlobalShell
->GetViewOptions();
4645 if (pViewOption
->IsTable())
4647 // tdf#77388 first paint the cell content to avoid of removing own border
4648 SwLayoutFrame::PaintSwFrame( rRenderContext
, rRect
);
4651 if ( IsCollapsingBorders() )
4653 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), static_cast<SwFrame
const *>(this) );
4654 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
4657 if ( rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
)
4660 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, true, gProp
);
4661 PaintShadow( rRect
, aRect
, rAttrs
);
4664 SwTabFramePainter
aHelper(*this);
4665 aHelper
.PaintLines(rRenderContext
, rRect
);
4668 // #i6467# - no light grey rectangle for page preview
4669 else if ( gProp
.pSGlobalShell
->GetWin() && !gProp
.pSGlobalShell
->IsPreview() )
4671 // #i6467# - intersect output rectangle with table frame
4672 SwRect
aTabRect( getFramePrintArea() );
4673 aTabRect
.Pos() += getFrameArea().Pos();
4674 SwRect
aTabOutRect( rRect
);
4675 aTabOutRect
.Intersection( aTabRect
);
4676 SwViewOption::DrawRect( &rRenderContext
, aTabOutRect
, COL_LIGHTGRAY
);
4678 const_cast<SwTabFrame
*>(this)->ResetComplete();
4682 * Paint border shadow
4684 * @param[in] rRect aligned rect to clip the result
4685 * @param[in,out] rOutRect full painting area as input
4686 * painting area reduced by shadow space for border and background as output
4687 * @param[in] rShadow includes shadow attributes
4688 * @param[in] bDrawFullShadowRectangle paint full rect of shadow
4689 * @param[in] bTop paint top part of the shadow
4690 * @param[in] bBottom paint bottom part of the shadow
4691 * @param[in] bLeft paint left part of the shadow
4692 * @param[in] bRight paint right part of the shadow
4694 static void lcl_PaintShadow( const SwRect
& rRect
, SwRect
& rOutRect
,
4695 const SvxShadowItem
& rShadow
, const bool bDrawFullShadowRectangle
,
4696 const bool bTop
, const bool bBottom
,
4697 const bool bLeft
, const bool bRight
,
4698 SwPaintProperties
const & properties
)
4700 const tools::Long nWidth
= ::lcl_AlignWidth ( rShadow
.GetWidth(), properties
);
4701 const tools::Long nHeight
= ::lcl_AlignHeight( rShadow
.GetWidth(), properties
);
4704 SwRect
aOut( rOutRect
);
4706 switch ( rShadow
.GetLocation() )
4708 case SvxShadowLocation::BottomRight
:
4710 if ( bDrawFullShadowRectangle
)
4712 // draw full shadow rectangle
4713 aOut
.Top( rOutRect
.Top() + nHeight
);
4714 aOut
.Left( rOutRect
.Left() + nWidth
);
4715 aRegion
.push_back( aOut
);
4721 aOut
.Top( rOutRect
.Bottom() - nHeight
);
4723 aOut
.Left( rOutRect
.Left() + nWidth
);
4724 aRegion
.push_back( aOut
);
4728 aOut
.Left( rOutRect
.Right() - nWidth
);
4730 aOut
.Top( rOutRect
.Top() + nHeight
);
4732 aOut
.Top( rOutRect
.Top() );
4734 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4735 aRegion
.push_back( aOut
);
4740 rOutRect
.AddRight(- nWidth
);
4742 rOutRect
.AddBottom(- nHeight
);
4745 case SvxShadowLocation::TopLeft
:
4747 if ( bDrawFullShadowRectangle
)
4749 // draw full shadow rectangle
4750 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4751 aOut
.Right( rOutRect
.Right() - nWidth
);
4752 aRegion
.push_back( aOut
);
4758 aOut
.Bottom( rOutRect
.Top() + nHeight
);
4760 aOut
.Right( rOutRect
.Right() - nWidth
);
4761 aRegion
.push_back( aOut
);
4765 aOut
.Right( rOutRect
.Left() + nWidth
);
4767 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4769 aOut
.Bottom( rOutRect
.Bottom() );
4771 aOut
.Top( rOutRect
.Top() + nHeight
);
4772 aRegion
.push_back( aOut
);
4777 rOutRect
.AddLeft( nWidth
);
4779 rOutRect
.AddTop( nHeight
);
4782 case SvxShadowLocation::TopRight
:
4784 if ( bDrawFullShadowRectangle
)
4786 // draw full shadow rectangle
4787 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4788 aOut
.Left( rOutRect
.Left() + nWidth
);
4789 aRegion
.push_back( aOut
);
4795 aOut
.Bottom( rOutRect
.Top() + nHeight
);
4797 aOut
.Left( rOutRect
.Left() + nWidth
);
4798 aRegion
.push_back( aOut
);
4802 aOut
.Left( rOutRect
.Right() - nWidth
);
4804 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4806 aOut
.Bottom( rOutRect
.Bottom() );
4808 aOut
.Top( rOutRect
.Top() + nHeight
);
4809 aRegion
.push_back( aOut
);
4814 rOutRect
.AddRight( - nWidth
);
4816 rOutRect
.AddTop( nHeight
);
4819 case SvxShadowLocation::BottomLeft
:
4821 if ( bDrawFullShadowRectangle
)
4823 // draw full shadow rectangle
4824 aOut
.Top( rOutRect
.Top() + nHeight
);
4825 aOut
.Right( rOutRect
.Right() - nWidth
);
4826 aRegion
.push_back( aOut
);
4832 aOut
.Top( rOutRect
.Bottom()- nHeight
);
4834 aOut
.Right( rOutRect
.Right() - nWidth
);
4835 aRegion
.push_back( aOut
);
4839 aOut
.Right( rOutRect
.Left() + nWidth
);
4841 aOut
.Top( rOutRect
.Top() + nHeight
);
4843 aOut
.Top( rOutRect
.Top() );
4845 aOut
.Bottom( rOutRect
.Bottom() - nHeight
);
4846 aRegion
.push_back( aOut
);
4851 rOutRect
.AddLeft( nWidth
);
4853 rOutRect
.AddBottom( - nHeight
);
4861 vcl::RenderContext
*pOut
= properties
.pSGlobalShell
->GetOut();
4863 DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
4864 Color
aShadowColor( rShadow
.GetColor().GetRGBColor() );
4865 if( !aRegion
.empty() && properties
.pSGlobalShell
->GetWin() &&
4866 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4868 // In high contrast mode, the output device has already set the
4869 // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function
4870 // to ignore the setting of a new color. Therefore we have to reset
4872 pOut
->SetDrawMode( DrawModeFlags::Default
);
4873 aShadowColor
= properties
.pSGlobalShell
->GetViewOptions()->GetFontColor();
4876 if ( pOut
->GetFillColor() != aShadowColor
)
4877 pOut
->SetFillColor( aShadowColor
);
4879 pOut
->SetLineColor();
4881 pOut
->SetDrawMode( nOldDrawMode
);
4883 for (const SwRect
& rOut
: aRegion
)
4886 if ( rRect
.Overlaps( aOut
) && aOut
.Height() > 0 && aOut
.Width() > 0 )
4888 aOut
.Intersection_( rRect
);
4889 pOut
->DrawRect( aOut
.SVRect() );
4895 * Paints a shadow if the format requests so.
4897 * The shadow is always painted on the outer edge of the OutRect.
4898 * If needed, the OutRect is shrunk so the painting of the border can be
4901 * @note: draw full shadow rectangle for frames with transparent drawn backgrounds (OD 23.08.2002 #99657#)
4903 void SwFrame::PaintShadow( const SwRect
& rRect
, SwRect
& rOutRect
,
4904 const SwBorderAttrs
&rAttrs
) const
4906 SvxShadowItem rShadow
= rAttrs
.GetShadow();
4908 const bool bCnt
= IsContentFrame();
4909 const bool bTop
= !bCnt
|| rAttrs
.GetTopLine ( *(this) );
4910 const bool bBottom
= !bCnt
|| rAttrs
.GetBottomLine( *(this) );
4914 switch( rShadow
.GetLocation() )
4916 case SvxShadowLocation::BottomRight
: rShadow
.SetLocation(SvxShadowLocation::BottomLeft
); break;
4917 case SvxShadowLocation::TopLeft
: rShadow
.SetLocation(SvxShadowLocation::TopRight
); break;
4918 case SvxShadowLocation::TopRight
: rShadow
.SetLocation(SvxShadowLocation::BottomRight
); break;
4919 case SvxShadowLocation::BottomLeft
: rShadow
.SetLocation(SvxShadowLocation::TopLeft
); break;
4924 // determine, if full shadow rectangle have to be drawn or only two shadow rectangles beside the frame.
4925 // draw full shadow rectangle, if frame background is drawn transparent.
4927 // SwLayoutFrame can have transparent drawn backgrounds. Thus,
4928 // "asked" their frame format.
4929 const bool bDrawFullShadowRectangle
=
4930 ( IsLayoutFrame() &&
4931 static_cast<const SwLayoutFrame
*>(this)->GetFormat()->IsBackgroundTransparent()
4934 SwRectFnSet
aRectFnSet(this);
4935 ::lcl_ExtendLeftAndRight( rOutRect
, *(this), rAttrs
, aRectFnSet
.FnRect() );
4937 lcl_PaintShadow(rRect
, rOutRect
, rShadow
, bDrawFullShadowRectangle
, bTop
, bBottom
, true, true, gProp
);
4940 void SwFrame::PaintBorderLine( const SwRect
& rRect
,
4941 const SwRect
& rOutRect
,
4942 const SwPageFrame
* pPage
,
4943 const Color
*pColor
,
4944 const SvxBorderLineStyle nStyle
) const
4946 if ( !rOutRect
.Overlaps( rRect
) )
4949 SwRect
aOut( rOutRect
);
4950 aOut
.Intersection_( rRect
);
4952 const SwTabFrame
*pTab
= IsCellFrame() ? FindTabFrame() : nullptr;
4953 SubColFlags nSubCol
= ( IsCellFrame() || IsRowFrame() )
4957 : ( IsInFly() ? SubColFlags::Fly
: SubColFlags::Page
) );
4958 if( pColor
&& gProp
.pSGlobalShell
->GetWin() &&
4959 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4961 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
4962 const SwViewOption
*pOpt
= pSh
->GetViewOptions();
4963 pColor
= &pOpt
->GetFontColor();
4966 if (pPage
->GetSortedObjs() &&
4967 pPage
->GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
))
4969 SwRegionRects
aRegion( aOut
, 4 );
4970 basegfx::utils::B2DClipState aClipState
;
4971 ::lcl_SubtractFlys( this, pPage
, aOut
, aRegion
, aClipState
, gProp
);
4972 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
4973 gProp
.pSLines
->AddLineRect( aRegion
[i
], pColor
, nStyle
, pTab
, nSubCol
, gProp
);
4976 gProp
.pSLines
->AddLineRect( aOut
, pColor
, nStyle
, pTab
, nSubCol
, gProp
);
4979 namespace drawinglayer::primitive2d
4983 class SwBorderRectanglePrimitive2D
: public BufferedDecompositionPrimitive2D
4986 /// the transformation defining the geometry of this BorderRectangle
4987 basegfx::B2DHomMatrix maB2DHomMatrix
;
4989 /// the four styles to be used
4990 svx::frame::Style maStyleTop
;
4991 svx::frame::Style maStyleRight
;
4992 svx::frame::Style maStyleBottom
;
4993 svx::frame::Style maStyleLeft
;
4996 /// local decomposition.
4997 virtual Primitive2DReference
create2DDecomposition(
4998 const geometry::ViewInformation2D
& rViewInformation
) const override
;
5002 SwBorderRectanglePrimitive2D(
5003 basegfx::B2DHomMatrix aB2DHomMatrix
,
5004 const svx::frame::Style
& rStyleTop
,
5005 const svx::frame::Style
& rStyleRight
,
5006 const svx::frame::Style
& rStyleBottom
,
5007 const svx::frame::Style
& rStyleLeft
);
5009 /// data read access
5010 const basegfx::B2DHomMatrix
& getB2DHomMatrix() const { return maB2DHomMatrix
; }
5011 const svx::frame::Style
& getStyleTop() const { return maStyleTop
; }
5012 const svx::frame::Style
& getStyleRight() const { return maStyleRight
; }
5013 const svx::frame::Style
& getStyleBottom() const { return maStyleBottom
; }
5014 const svx::frame::Style
& getStyleLeft() const { return maStyleLeft
; }
5016 /// compare operator
5017 virtual bool operator==(const BasePrimitive2D
& rPrimitive
) const override
;
5020 virtual basegfx::B2DRange
getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const override
;
5022 /// provide unique ID
5023 virtual sal_uInt32
getPrimitive2DID() const override
;
5028 Primitive2DReference
SwBorderRectanglePrimitive2D::create2DDecomposition(
5029 const geometry::ViewInformation2D
& /*rViewInformation*/) const
5031 basegfx::B2DPoint
aTopLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 0.0));
5032 basegfx::B2DPoint
aTopRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 0.0));
5033 basegfx::B2DPoint
aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0));
5034 basegfx::B2DPoint
aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0));
5036 // prepare SdrFrameBorderDataVector
5037 drawinglayer::primitive2d::SdrFrameBorderDataVector aData
;
5039 if(getStyleTop().IsUsed())
5041 // move top left/right inwards half border width
5042 basegfx::B2DVector
aDown(getB2DHomMatrix() * basegfx::B2DVector(0.0, 1.0));
5043 aDown
.setLength(getStyleTop().GetWidth() * 0.5);
5048 if(getStyleBottom().IsUsed())
5050 // move bottom left/right inwards half border width
5051 basegfx::B2DVector
aUp(getB2DHomMatrix() * basegfx::B2DVector(0.0, -1.0));
5052 aUp
.setLength(getStyleBottom().GetWidth() * 0.5);
5054 aBottomRight
+= aUp
;
5057 if(getStyleLeft().IsUsed())
5059 // move left top/bottom inwards half border width
5060 basegfx::B2DVector
aRight(getB2DHomMatrix() * basegfx::B2DVector(1.0, 0.0));
5061 aRight
.setLength(getStyleLeft().GetWidth() * 0.5);
5063 aBottomLeft
+= aRight
;
5066 if(getStyleRight().IsUsed())
5068 // move right top/bottom inwards half border width
5069 basegfx::B2DVector
aLeft(getB2DHomMatrix() * basegfx::B2DVector(-1.0, 0.0));
5070 aLeft
.setLength(getStyleRight().GetWidth() * 0.5);
5072 aBottomRight
+= aLeft
;
5075 // go round-robin, from TopLeft to TopRight, down, left and back up. That
5076 // way, the borders will not need to be mirrored in any way
5077 if(getStyleTop().IsUsed())
5079 // create BorderPrimitive(s) for top border
5080 const basegfx::B2DVector
aVector(aTopRight
- aTopLeft
);
5086 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5088 if(getStyleLeft().IsUsed())
5090 rInstance
.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft
- aTopLeft
), false);
5093 if(getStyleRight().IsUsed())
5095 rInstance
.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight
- aTopRight
), false);
5099 if(getStyleRight().IsUsed())
5101 // create BorderPrimitive(s) for right border
5102 const basegfx::B2DVector
aVector(aBottomRight
- aTopRight
);
5108 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5110 if(getStyleTop().IsUsed())
5112 rInstance
.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft
- aTopRight
), false);
5115 if(getStyleBottom().IsUsed())
5117 rInstance
.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft
- aBottomRight
), false);
5121 if(getStyleBottom().IsUsed())
5123 // create BorderPrimitive(s) for bottom border
5124 const basegfx::B2DVector
aVector(aBottomLeft
- aBottomRight
);
5130 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5132 if(getStyleRight().IsUsed())
5134 rInstance
.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight
- aBottomRight
), false);
5137 if(getStyleLeft().IsUsed())
5139 rInstance
.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft
- aBottomLeft
), false);
5143 if(getStyleLeft().IsUsed())
5145 // create BorderPrimitive(s) for left border
5146 const basegfx::B2DVector
aVector(aTopLeft
- aBottomLeft
);
5152 drawinglayer::primitive2d::SdrFrameBorderData
& rInstance(aData
.back());
5154 if(getStyleBottom().IsUsed())
5156 rInstance
.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight
- aBottomLeft
), false);
5159 if(getStyleTop().IsUsed())
5161 rInstance
.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight
- aTopLeft
), false);
5165 // create instance of SdrFrameBorderPrimitive2D if
5166 // SdrFrameBorderDataVector is used
5170 return new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
5172 true); // force visualization to minimal one discrete unit (pixel)
5175 SwBorderRectanglePrimitive2D::SwBorderRectanglePrimitive2D(
5176 basegfx::B2DHomMatrix aB2DHomMatrix
,
5177 const svx::frame::Style
& rStyleTop
,
5178 const svx::frame::Style
& rStyleRight
,
5179 const svx::frame::Style
& rStyleBottom
,
5180 const svx::frame::Style
& rStyleLeft
)
5181 : maB2DHomMatrix(std::move(aB2DHomMatrix
)),
5182 maStyleTop(rStyleTop
),
5183 maStyleRight(rStyleRight
),
5184 maStyleBottom(rStyleBottom
),
5185 maStyleLeft(rStyleLeft
)
5189 bool SwBorderRectanglePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
5191 if(BasePrimitive2D::operator==(rPrimitive
))
5193 const SwBorderRectanglePrimitive2D
& rCompare
= static_cast<const SwBorderRectanglePrimitive2D
&>(rPrimitive
);
5195 return (getB2DHomMatrix() == rCompare
.getB2DHomMatrix() &&
5196 getStyleTop() == rCompare
.getStyleTop() &&
5197 getStyleRight() == rCompare
.getStyleRight() &&
5198 getStyleBottom() == rCompare
.getStyleBottom() &&
5199 getStyleLeft() == rCompare
.getStyleLeft());
5205 basegfx::B2DRange
SwBorderRectanglePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& /*rViewInformation*/) const
5207 basegfx::B2DRange
aRetval(0.0, 0.0, 1.0, 1.0);
5209 aRetval
.transform(getB2DHomMatrix());
5213 // provide unique ID
5214 sal_uInt32
SwBorderRectanglePrimitive2D::getPrimitive2DID() const
5216 return PRIMITIVE2D_ID_SWBORDERRECTANGLERIMITIVE
;
5219 } // end of namespace drawinglayer::primitive2d
5223 editeng::SvxBorderLine
const * get_ptr(std::optional
<editeng::SvxBorderLine
> const & opt
) {
5224 return opt
? &*opt
: nullptr;
5229 void PaintCharacterBorder(
5230 const SwFont
& rFont
,
5231 const SwRect
& rPaintArea
,
5232 const bool bVerticalLayout
,
5233 const bool bVerticalLayoutLRBT
,
5234 const bool bJoinWithPrev
,
5235 const bool bJoinWithNext
)
5237 SwRect
aAlignedRect(rPaintArea
);
5238 SwAlignRect(aAlignedRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut());
5241 bool bBottom
= true;
5245 switch (rFont
.GetOrientation(bVerticalLayout
, bVerticalLayoutLRBT
).get())
5248 bLeft
= !bJoinWithPrev
;
5249 bRight
= !bJoinWithNext
;
5252 bBottom
= !bJoinWithPrev
;
5253 bTop
= !bJoinWithNext
;
5256 bRight
= !bJoinWithPrev
;
5257 bLeft
= !bJoinWithNext
;
5260 bTop
= !bJoinWithPrev
;
5261 bBottom
= !bJoinWithNext
;
5265 // Paint shadow (reduce painting rect)
5267 const SvxShadowItem
aShadow(
5268 0, &rFont
.GetShadowColor(), rFont
.GetShadowWidth(),
5269 rFont
.GetAbsShadowLocation(bVerticalLayout
, bVerticalLayoutLRBT
));
5271 if( aShadow
.GetLocation() != SvxShadowLocation::NONE
)
5273 lcl_PaintShadow( rPaintArea
, aAlignedRect
, aShadow
,
5274 false, bTop
, bBottom
, bLeft
, bRight
, gProp
);
5278 const basegfx::B2DHomMatrix
aBorderTransform(
5279 basegfx::utils::createScaleTranslateB2DHomMatrix(
5280 aAlignedRect
.Width(), aAlignedRect
.Height(),
5281 aAlignedRect
.Left(), aAlignedRect
.Top()));
5282 const svx::frame::Style
aStyleTop(
5283 bTop
? get_ptr(rFont
.GetAbsTopBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5285 const svx::frame::Style
aStyleRight(
5286 bRight
? get_ptr(rFont
.GetAbsRightBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5288 const svx::frame::Style
aStyleBottom(
5289 bBottom
? get_ptr(rFont
.GetAbsBottomBorder(bVerticalLayout
, bVerticalLayoutLRBT
))
5292 const svx::frame::Style
aStyleLeft(
5293 bLeft
? get_ptr(rFont
.GetAbsLeftBorder(bVerticalLayout
, bVerticalLayoutLRBT
)) : nullptr,
5295 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget
;
5297 aBorderLineTarget
.append(
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 if (!getFramePrintArea().HasArea())
5536 { // hidden text frame, may be called by upper from PaintSwFrameBackground()
5540 const bool bLine
= rAttrs
.IsLine();
5541 const bool bShadow
= rAttrs
.GetShadow().GetLocation() != SvxShadowLocation::NONE
;
5543 // - flag to control,
5544 //-hack has to be used.
5545 const bool bb4779636HackActive
= true;
5547 const SwFrame
* pCellFrameForBottomBorderAttrs
= nullptr;
5548 const SwFrame
* pCellFrameForTopBorderAttrs
= nullptr;
5549 bool bFoundCellForTopOrBorderAttrs
= false;
5550 if ( bb4779636HackActive
&& IsCellFrame() )
5552 pCellFrameForBottomBorderAttrs
= lcl_GetCellFrameForBorderAttrs( this, rAttrs
, false );
5553 if ( pCellFrameForBottomBorderAttrs
!= this )
5554 bFoundCellForTopOrBorderAttrs
= true;
5555 pCellFrameForTopBorderAttrs
= lcl_GetCellFrameForBorderAttrs( this, rAttrs
, true );
5556 if ( pCellFrameForTopBorderAttrs
!= this )
5557 bFoundCellForTopOrBorderAttrs
= true;
5560 // - add condition <bFoundCellForTopOrBorderAttrs>
5562 if ( !(bLine
|| bShadow
|| bFoundCellForTopOrBorderAttrs
) )
5565 //If the rectangle is completely inside the PrtArea, no border needs to
5567 //For the PrtArea the aligned value needs to be used, otherwise it could
5568 //happen, that some parts won't be processed.
5569 SwRect
aRect( getFramePrintArea() );
5570 aRect
+= getFrameArea().Pos();
5571 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
5572 // new local boolean variable in order to
5573 // suspend border paint under special cases - see below.
5574 // NOTE: This is a fix for the implementation of feature #99657#.
5575 bool bDrawOnlyShadowForTransparentFrame
= false;
5576 if ( aRect
.Contains( rRect
) )
5578 // paint shadow, if background is transparent.
5579 // Because of introduced transparent background for fly frame #99657#,
5580 // the shadow have to be drawn if the background is transparent,
5581 // in spite the fact that the paint rectangle <rRect> lies fully
5582 // in the printing area.
5583 // NOTE to chosen solution:
5584 // On transparent background, continue processing, but suspend
5585 // drawing of border by setting <bDrawOnlyShadowForTransparentFrame>
5587 if ( IsLayoutFrame() &&
5588 static_cast<const SwLayoutFrame
*>(this)->GetFormat()->IsBackgroundTransparent() )
5590 bDrawOnlyShadowForTransparentFrame
= true;
5598 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, true, gProp
);
5599 rAttrs
.SetGetCacheLine( true );
5603 PaintShadow(rRect
, aRect
, rAttrs
);
5606 // suspend drawing of border
5607 // add condition < NOT bDrawOnlyShadowForTransparentFrame > - see above
5608 // - add condition <bFoundCellForTopOrBorderAttrs>
5610 if((bLine
|| bFoundCellForTopOrBorderAttrs
) && !bDrawOnlyShadowForTransparentFrame
)
5612 // define SvxBorderLine(s) to use
5613 const SvxBoxItem
& rBox(rAttrs
.GetBox());
5614 const SvxBorderLine
* pLeftBorder(rBox
.GetLeft());
5615 const SvxBorderLine
* pRightBorder(rBox
.GetRight());
5616 const SvxBorderLine
* pTopBorder(rBox
.GetTop());
5617 const SvxBorderLine
* pBottomBorder(rBox
.GetBottom());
5619 // if R2L, exchange Right/Left
5620 const bool bR2L(IsCellFrame() && IsRightToLeft());
5624 std::swap(pLeftBorder
, pRightBorder
);
5627 // if ContentFrame and joined Prev/Next, reset top/bottom as needed
5628 if(IsContentFrame())
5630 const SwFrame
* pDirRefFrame(IsCellFrame() ? FindTabFrame() : this);
5631 const SwRectFnSet
aRectFnSet(pDirRefFrame
);
5632 const SwRectFn
_aRectFn(aRectFnSet
.FnRect());
5634 if(rAttrs
.JoinedWithPrev(*this))
5636 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5637 // existing gap to previous frame
5638 const SwFrame
* pPrevFrame(GetPrev());
5639 (aRect
.*_aRectFn
->fnSetTop
)( (pPrevFrame
->*_aRectFn
->fnGetPrtBottom
)() );
5641 // ...and disable top border paint/creation
5642 pTopBorder
= nullptr;
5645 if(rAttrs
.JoinedWithNext(*this))
5647 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5648 // existing gap to next frame
5649 const SwFrame
* pNextFrame(GetNext());
5650 (aRect
.*_aRectFn
->fnSetBottom
)( (pNextFrame
->*_aRectFn
->fnGetPrtTop
)() );
5652 // ...and disable bottom border paint/creation
5653 pBottomBorder
= nullptr;
5657 // necessary to replace TopBorder?
5658 if((!IsContentFrame() || rAttrs
.GetTopLine(*this)) && IsCellFrame() && pCellFrameForTopBorderAttrs
!= this)
5660 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pCellFrameForTopBorderAttrs
);
5661 pTopBorder
= aAccess
.Get()->GetBox().GetTop();
5664 // necessary to replace BottomBorder?
5665 if((!IsContentFrame() || rAttrs
.GetBottomLine(*this)) && IsCellFrame() && pCellFrameForBottomBorderAttrs
!= this)
5667 SwBorderAttrAccess
aAccess(SwFrame::GetCache(), pCellFrameForBottomBorderAttrs
);
5668 pBottomBorder
= aAccess
.Get()->GetBox().GetBottom();
5671 bool bWordBorder
= false;
5672 SwViewShell
* pShell
= getRootFrame()->GetCurrShell();
5675 const IDocumentSettingAccess
& rIDSA
= pShell
->GetDoc()->getIDocumentSettingAccess();
5676 bWordBorder
= rIDSA
.get(DocumentSettingId::TABLE_ROW_KEEP
);
5678 bool bInWordTableCell
= IsContentFrame() && GetUpper()->IsCellFrame() && bWordBorder
;
5679 if (bInWordTableCell
)
5681 // Compat mode: don't paint bottom border if we know the bottom of the content was cut
5683 auto pContentFrame
= static_cast<const SwContentFrame
*>(this);
5684 if (pContentFrame
->IsUndersized())
5686 pBottomBorder
= nullptr;
5690 if(nullptr != pLeftBorder
|| nullptr != pRightBorder
|| nullptr != pTopBorder
|| nullptr != pBottomBorder
)
5692 // now we have all SvxBorderLine(s) sorted out, create geometry
5693 const basegfx::B2DHomMatrix
aBorderTransform(
5694 basegfx::utils::createScaleTranslateB2DHomMatrix(
5695 aRect
.Width(), aRect
.Height(),
5696 aRect
.Left(), aRect
.Top()));
5697 const svx::frame::Style
aStyleTop(pTopBorder
, 1.0);
5698 svx::frame::Style
aStyleRight(pRightBorder
, 1.0);
5700 // Right/bottom page borders are always mirrored in Word.
5701 if (IsPageFrame() && bWordBorder
)
5703 aStyleRight
.MirrorSelf();
5706 svx::frame::Style
aStyleBottom(pBottomBorder
, 1.0);
5708 if (IsPageFrame() && bWordBorder
)
5710 aStyleBottom
.MirrorSelf();
5713 const svx::frame::Style
aStyleLeft(pLeftBorder
, 1.0);
5714 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget
;
5716 drawinglayer::primitive2d::Primitive2DReference
aRetval(
5717 new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
5724 if (bInWordTableCell
)
5726 // Compat mode: cut off the borders which are outside of our own area.
5727 const SwRect
& rClip
= getFrameArea();
5728 basegfx::B2DRectangle
aClip(rClip
.Left(), rClip
.Top(), rClip
.Right(),
5730 basegfx::B2DPolyPolygon
aPolyPolygon(
5731 basegfx::utils::createPolygonFromRect(aClip
));
5732 const drawinglayer::primitive2d::Primitive2DReference
xClipped(
5733 new drawinglayer::primitive2d::MaskPrimitive2D(std::move(aPolyPolygon
), { aRetval
}));
5737 aBorderLineTarget
.append(aRetval
);
5738 gProp
.pBLines
->AddBorderLines(std::move(aBorderLineTarget
));
5742 rAttrs
.SetGetCacheLine( false );
5746 * Special implementation because of the footnote line
5748 * Currently only the top frame needs to be taken into account
5749 * Other lines and shadows are set aside
5751 void SwFootnoteContFrame::PaintSwFrameShadowAndBorder(
5752 const SwRect
& rRect
,
5753 const SwPageFrame
* pPage
,
5754 const SwBorderAttrs
&) const
5756 //If the rectangle is completely inside the PrtArea, no border needs to
5758 SwRect
aRect( getFramePrintArea() );
5759 aRect
.Pos() += getFrameArea().Pos();
5760 if ( !aRect
.Contains( rRect
) )
5761 PaintLine( rRect
, pPage
);
5764 /// Paint footnote lines.
5765 void SwFootnoteContFrame::PaintLine( const SwRect
& rRect
,
5766 const SwPageFrame
*pPage
) const
5768 //The length of the line is derived from the percentual indication on the
5769 //PageDesc. The position is also stated on the PageDesc.
5770 //The pen can directly be taken from the PageDesc.
5773 pPage
= FindPageFrame();
5774 const SwPageFootnoteInfo
&rInf
= pPage
->GetPageDesc()->GetFootnoteInfo();
5776 SwRectFnSet
aRectFnSet(this);
5777 SwTwips nPrtWidth
= aRectFnSet
.GetWidth(getFramePrintArea());
5778 Fraction
aFract( nPrtWidth
, 1 );
5779 aFract
*= rInf
.GetWidth();
5780 SwTwips nWidth
= static_cast<tools::Long
>(aFract
);
5782 SwTwips nX
= aRectFnSet
.GetPrtLeft(*this);
5783 switch ( rInf
.GetAdj() )
5785 case css::text::HorizontalAdjust_CENTER
:
5786 nX
+= nPrtWidth
/2 - nWidth
/2; break;
5787 case css::text::HorizontalAdjust_RIGHT
:
5788 nX
+= nPrtWidth
- nWidth
; break;
5789 case css::text::HorizontalAdjust_LEFT
:
5790 /* do nothing */; break;
5792 SAL_WARN("sw.core", "New adjustment for footnote lines?");
5795 SwTwips nLineWidth
= rInf
.GetLineWidth();
5796 std::optional
<SwRect
> oLineRect
;
5797 if (aRectFnSet
.IsVert())
5799 oLineRect
.emplace(Point(getFrameArea().Left()+getFrameArea().Width()-rInf
.GetTopDist()-nLineWidth
,
5800 nX
), Size( nLineWidth
, nWidth
) );
5804 Point
aPoint(nX
, getFrameArea().Pos().Y() + rInf
.GetTopDist());
5805 const IDocumentSettingAccess
& rIDSA
= GetFormat()->getIDocumentSettingAccess();
5806 if (rIDSA
.get(DocumentSettingId::CONTINUOUS_ENDNOTES
))
5808 // Word style: instead of fixed value, upper spacing is 60% of all space.
5809 auto nPrintAreaTop
= static_cast<double>(getFramePrintArea().Top());
5810 aPoint
.setY(getFrameArea().Pos().Y() + nPrintAreaTop
* 0.6);
5812 const SwFootnoteFrame
* pEndnoteFrame
= FindEndNote();
5813 bool bEndnoteContinuation
= pEndnoteFrame
&& pEndnoteFrame
->GetMaster();
5814 if (bEndnoteContinuation
)
5816 // Endnote continuation separator is print area wide.
5821 // Length is 2 inches, but don't paint outside the container frame.
5822 nWidth
= o3tl::convert(2, o3tl::Length::in
, o3tl::Length::twip
);
5823 if (nWidth
> nPrtWidth
)
5829 oLineRect
.emplace(aPoint
, Size(nWidth
, rInf
.GetLineWidth()));
5831 if ( oLineRect
->HasArea() && rInf
.GetLineStyle() != SvxBorderLineStyle::NONE
)
5832 PaintBorderLine( rRect
, *oLineRect
, pPage
, &rInf
.GetLineColor(),
5833 rInf
.GetLineStyle() );
5836 void SwFootnoteContFrame::dumpAsXml(xmlTextWriterPtr writer
) const
5838 (void)xmlTextWriterStartElement(writer
, reinterpret_cast<const xmlChar
*>("ftncont"));
5839 dumpAsXmlAttributes(writer
);
5841 (void)xmlTextWriterStartElement(writer
, BAD_CAST("infos"));
5842 dumpInfosAsXml(writer
);
5843 (void)xmlTextWriterEndElement(writer
);
5844 dumpChildrenAsXml(writer
);
5846 (void)xmlTextWriterEndElement(writer
);
5849 /// Paints the separator line for inside columns
5850 void SwLayoutFrame::PaintColLines( const SwRect
&rRect
, const SwFormatCol
&rFormatCol
,
5851 const SwPageFrame
*pPage
) const
5853 const SwFrame
*pCol
= Lower();
5854 if ( !pCol
|| !pCol
->IsColumnFrame() )
5857 SwRectFnSet
fnRect(pCol
);
5859 SwRect aLineRect
= getFramePrintArea();
5860 aLineRect
+= getFrameArea().Pos();
5862 SwTwips nTop
= (fnRect
.GetHeight(aLineRect
)*rFormatCol
.GetLineHeight())
5863 / 100 - fnRect
.GetHeight(aLineRect
);
5864 SwTwips nBottom
= 0;
5866 switch ( rFormatCol
.GetLineAdj() )
5869 nBottom
= nTop
/ 2; nTop
-= nBottom
; break;
5871 nBottom
= nTop
; nTop
= 0; break;
5875 OSL_ENSURE( false, "New adjustment for column lines?" );
5879 fnRect
.SubTop(aLineRect
, nTop
);
5881 fnRect
.AddBottom(aLineRect
, nBottom
);
5883 SwTwips nPenHalf
= rFormatCol
.GetLineWidth();
5884 fnRect
.SetWidth(aLineRect
, nPenHalf
);
5887 //We need to be a bit generous here, to not lose something.
5888 SwRect
aRect( rRect
);
5889 fnRect
.SubLeft(aRect
, nPenHalf
+ gProp
.nSPixelSzW
);
5890 fnRect
.AddRight(aRect
, nPenHalf
+ gProp
.nSPixelSzW
);
5891 while ( pCol
->GetNext() )
5893 fnRect
.SetPosX(aLineRect
, (IsRightToLeft() ? fnRect
.GetLeft(pCol
->getFrameArea())
5894 : fnRect
.GetRight(pCol
->getFrameArea()))
5896 if ( aRect
.Overlaps( aLineRect
) )
5897 PaintBorderLine( aRect
, aLineRect
, pPage
, &rFormatCol
.GetLineColor(),
5898 rFormatCol
.GetLineStyle() );
5899 pCol
= pCol
->GetNext();
5903 void SwPageFrame::PaintGrid( OutputDevice
const * pOut
, SwRect
const &rRect
) const
5905 if( !m_bHasGrid
|| gProp
.pSRetoucheFly
|| gProp
.pSRetoucheFly2
)
5907 SwTextGridItem
const*const pGrid(GetGridItem(this));
5908 if( !(pGrid
&& ( OUTDEV_PRINTER
!= pOut
->GetOutDevType() ?
5909 pGrid
->GetDisplayGrid() : pGrid
->GetPrintGrid() )) )
5912 const SwLayoutFrame
* pBody
= FindBodyCont();
5916 SwRect
aGrid( pBody
->getFramePrintArea() );
5917 aGrid
+= pBody
->getFrameArea().Pos();
5919 SwRect
aInter( aGrid
);
5920 aInter
.Intersection( rRect
);
5921 if( !aInter
.HasArea() )
5924 bool bGrid
= pGrid
->GetRubyTextBelow();
5925 bool bCell
= SwTextGrid::LinesAndChars
== pGrid
->GetGridType();
5926 tools::Long nGrid
= pGrid
->GetBaseHeight();
5927 const SwDoc
* pDoc
= GetFormat()->GetDoc();
5928 tools::Long nGridWidth
= GetGridWidth(*pGrid
, *pDoc
);
5929 tools::Long nRuby
= pGrid
->GetRubyHeight();
5930 tools::Long nSum
= nGrid
+ nRuby
;
5931 const Color
*pCol
= &pGrid
->GetColor();
5933 SwTwips nRight
= aInter
.Left() + aInter
.Width();
5934 SwTwips nBottom
= aInter
.Top() + aInter
.Height();
5937 SwTwips nOrig
= aGrid
.Left() + aGrid
.Width();
5938 SwTwips nY
= nOrig
+ nSum
*
5939 ( ( nOrig
- aInter
.Left() ) / nSum
);
5940 SwRect
aTmp( Point( nY
, aInter
.Top() ),
5941 Size( 1, aInter
.Height() ) );
5942 SwTwips nX
= aGrid
.Top() + nGrid
*
5943 ( ( aInter
.Top() - aGrid
.Top() )/ nGrid
);
5944 if( nX
< aInter
.Top() )
5946 SwTwips nGridBottom
= aGrid
.Top() + aGrid
.Height();
5947 bool bLeft
= aGrid
.Top() >= aInter
.Top();
5948 bool bRight
= nGridBottom
<= nBottom
;
5949 bool bBorder
= bLeft
|| bRight
;
5950 while( nY
> nRight
)
5952 aTmp
.Pos().setX( nY
);
5956 SwTwips nPosY
= std::max( SwTwips(aInter
.Left()), nY
);
5957 SwTwips nHeight
= std::min(nRight
, SwTwips(aTmp
.Pos().X()))-nPosY
;
5962 SwRect
aVert( Point( nPosY
, nX
),
5963 Size( nHeight
, 1 ) );
5964 while( aVert
.Top() <= nBottom
)
5966 PaintBorderLine(rRect
,aVert
,this,pCol
);
5967 aVert
.Pos().AdjustY(nGrid
);
5972 SwRect
aVert( Point( nPosY
, aGrid
.Top() ),
5973 Size( nHeight
, 1 ) );
5975 PaintBorderLine(rRect
,aVert
,this,pCol
);
5978 aVert
.Pos().setY( nGridBottom
);
5979 PaintBorderLine(rRect
,aVert
,this,pCol
);
5989 SwTwips nPos
= std::max( SwTwips(aInter
.Left()), nY
);
5990 SwTwips nW
= std::min(nRight
, SwTwips(aTmp
.Pos().X())) - nPos
;
5991 SwRect
aVert( Point( nPos
, aGrid
.Top() ),
5996 PaintBorderLine(rRect
,aVert
,this,pCol
);
5999 aVert
.Pos().setY( nGridBottom
);
6000 PaintBorderLine(rRect
,aVert
,this,pCol
);
6007 while( nY
>= aInter
.Left() )
6009 aTmp
.Pos().setX( nY
);
6010 PaintBorderLine( rRect
, aTmp
, this, pCol
);
6014 SwTwips nHeight
= aTmp
.Pos().X()
6015 - std::max(SwTwips(aInter
.Left()), nY
);
6020 SwRect
aVert( Point(aTmp
.Pos().X()-nHeight
,
6021 nX
), Size( nHeight
, 1 ) );
6022 while( aVert
.Top() <= nBottom
)
6024 PaintBorderLine(rRect
,aVert
,this,pCol
);
6025 aVert
.Pos().AdjustY(nGrid
);
6030 SwRect
aVert( Point(aTmp
.Pos().X()-nHeight
,
6031 aGrid
.Top() ), Size( nHeight
, 1 ) );
6033 PaintBorderLine(rRect
,aVert
,this,pCol
);
6036 aVert
.Pos().setY( nGridBottom
);
6037 PaintBorderLine(rRect
,aVert
,this,pCol
);
6047 SwTwips nPos
= std::max( SwTwips(aInter
.Left()), nY
);
6048 SwTwips nW
= std::min(nRight
, SwTwips(aTmp
.Pos().X())) - nPos
;
6049 SwRect
aVert( Point( nPos
, aGrid
.Top() ),
6054 PaintBorderLine(rRect
,aVert
,this,pCol
);
6057 aVert
.Pos().setY( nGridBottom
);
6058 PaintBorderLine(rRect
,aVert
,this,pCol
);
6068 SwTwips nOrig
= aGrid
.Top();
6069 SwTwips nY
= nOrig
+ nSum
*( (aInter
.Top()-nOrig
)/nSum
);
6070 SwRect
aTmp( Point( aInter
.Left(), nY
),
6071 Size( aInter
.Width(), 1 ) );
6072 //for textgrid refactor
6073 SwTwips nX
= aGrid
.Left() + nGridWidth
*
6074 ( ( aInter
.Left() - aGrid
.Left() )/ nGridWidth
);
6075 if( nX
< aInter
.Left() )
6077 SwTwips nGridRight
= aGrid
.Left() + aGrid
.Width();
6078 bool bLeft
= aGrid
.Left() >= aInter
.Left();
6079 bool bRight
= nGridRight
<= nRight
;
6080 bool bBorder
= bLeft
|| bRight
;
6081 while( nY
< aInter
.Top() )
6083 aTmp
.Pos().setY(nY
);
6087 SwTwips nPosY
= std::max( aInter
.Top(), aTmp
.Pos().getY() );
6088 SwTwips nHeight
= std::min(nBottom
, nY
) - nPosY
;
6093 SwRect
aVert( Point( nX
, nPosY
),
6094 Size( 1, nHeight
) );
6095 while( aVert
.Left() <= nRight
)
6097 PaintBorderLine(rRect
,aVert
,this,pCol
);
6098 aVert
.Pos().AdjustX(nGridWidth
); //for textgrid refactor
6103 SwRect
aVert( Point( aGrid
.Left(), nPosY
),
6104 Size( 1, nHeight
) );
6106 PaintBorderLine(rRect
,aVert
,this,pCol
);
6109 aVert
.Pos().setX( nGridRight
);
6110 PaintBorderLine(rRect
,aVert
,this,pCol
);
6120 SwTwips nPos
= std::max(aInter
.Top(),aTmp
.Pos().getY());
6121 SwTwips nH
= std::min( nBottom
, nY
) - nPos
;
6122 SwRect
aVert( Point( aGrid
.Left(), nPos
),
6127 PaintBorderLine(rRect
,aVert
,this,pCol
);
6130 aVert
.Pos().setX(nGridRight
);
6131 PaintBorderLine(rRect
,aVert
,this,pCol
);
6138 while( nY
<= nBottom
)
6140 aTmp
.Pos().setY(nY
);
6141 PaintBorderLine( rRect
, aTmp
, this, pCol
);
6145 SwTwips nHeight
= std::min(nBottom
, nY
) - aTmp
.Pos().getY();
6150 SwRect
aVert( Point( nX
, aTmp
.Pos().getY() ),
6151 Size( 1, nHeight
) );
6152 while( aVert
.Left() <= nRight
)
6154 PaintBorderLine( rRect
, aVert
, this, pCol
);
6155 aVert
.Pos().setX(aVert
.Pos().getX() + nGridWidth
); //for textgrid refactor
6160 SwRect
aVert( Point( aGrid
.Left(),
6161 aTmp
.Pos().getY() ), Size( 1, nHeight
) );
6163 PaintBorderLine(rRect
,aVert
,this,pCol
);
6166 aVert
.Pos().setX(nGridRight
);
6167 PaintBorderLine(rRect
,aVert
,this,pCol
);
6177 SwTwips nPos
= std::max(aInter
.Top(),aTmp
.Pos().Y());
6178 SwTwips nH
= std::min( nBottom
, nY
) - nPos
;
6179 SwRect
aVert( Point( aGrid
.Left(), nPos
),
6184 PaintBorderLine(rRect
,aVert
,this,pCol
);
6187 aVert
.Pos().setX(nGridRight
);
6188 PaintBorderLine(rRect
,aVert
,this,pCol
);
6199 * Paint margin area of a page
6201 * OD 20.11.2002 for #104598#:
6202 * implement paint of margin area; margin area will be painted for a
6203 * view shell with a window and if the document is not in online layout.
6205 * @param _rOutputRect
6206 * input parameter - constant instance reference of the rectangle, for
6207 * which an output has to be generated.
6209 * @param _pViewShell
6210 * input parameter - instance of the view shell, on which the output
6211 * has to be generated.
6213 void SwPageFrame::PaintMarginArea( const SwRect
& _rOutputRect
,
6214 SwViewShell
const * _pViewShell
) const
6216 if ( !_pViewShell
->GetWin() || _pViewShell
->GetViewOptions()->getBrowseMode() )
6219 // Simplified paint with DrawingLayer FillStyle
6220 SwRect aPgRect
= getFrameArea();
6221 aPgRect
.Intersection_( _rOutputRect
);
6223 if(!aPgRect
.IsEmpty())
6225 OutputDevice
*pOut
= _pViewShell
->GetOut();
6227 if(pOut
->GetFillColor() != aGlobalRetoucheColor
)
6229 pOut
->SetFillColor(aGlobalRetoucheColor
);
6232 pOut
->DrawRect(aPgRect
.SVRect());
6236 const sal_Int8
SwPageFrame::snShadowPxWidth
= 9;
6238 bool SwPageFrame::IsRightShadowNeeded() const
6240 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6241 const bool bIsLTR
= getRootFrame()->IsLeftToRightViewLayout();
6243 // We paint the right shadow if we're not in book mode
6244 // or if we've no sibling or are the last page of the "row"
6245 return !pSh
|| (!pSh
->GetViewOptions()->IsViewLayoutBookMode()) || !GetNext()
6246 || (this == Lower()) || (bIsLTR
&& OnRightPage())
6247 || (!bIsLTR
&& !OnRightPage());
6251 bool SwPageFrame::IsLeftShadowNeeded() const
6253 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6254 const bool bIsLTR
= getRootFrame()->IsLeftToRightViewLayout();
6256 // We paint the left shadow if we're not in book mode
6257 // or if we've no sibling or are the last page of the "row"
6258 return !pSh
|| (!pSh
->GetViewOptions()->IsViewLayoutBookMode()) || !GetPrev()
6259 || (bIsLTR
&& !OnRightPage())
6260 || (!bIsLTR
&& OnRightPage());
6264 * Determine rectangle for bottom page shadow
6267 /*static*/ void SwPageFrame::GetHorizontalShadowRect( const SwRect
& _rPageRect
,
6268 const SwViewShell
* _pViewShell
,
6269 OutputDevice
const * pRenderContext
,
6270 SwRect
& _orHorizontalShadowRect
,
6271 bool bPaintLeftShadow
,
6272 bool bPaintRightShadow
,
6273 bool bRightSidebar
)
6275 const SwPostItMgr
*pMgr
= _pViewShell
->GetPostItMgr();
6276 SwRect
aAlignedPageRect( _rPageRect
);
6277 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, pRenderContext
);
6278 SwRect
aPagePxRect(pRenderContext
->LogicToPixel( aAlignedPageRect
.SVRect() ));
6280 tools::Long lShadowAdjustment
= snShadowPxWidth
- 1; // TODO: extract this
6282 _orHorizontalShadowRect
.Chg(
6283 Point( aPagePxRect
.Left() + (bPaintLeftShadow
? lShadowAdjustment
: 0), 0 ),
6284 Size( aPagePxRect
.Width() - ( (bPaintLeftShadow
? lShadowAdjustment
: 0) + (bPaintRightShadow
? lShadowAdjustment
: 0) ),
6285 snShadowPxWidth
) );
6287 if(pMgr
&& pMgr
->ShowNotes() && pMgr
->HasNotes())
6289 // Notes are displayed, we've to extend borders
6290 SwTwips aSidebarTotalWidth
= pMgr
->GetSidebarWidth(true) + pMgr
->GetSidebarBorderWidth(true);
6292 _orHorizontalShadowRect
.AddRight( aSidebarTotalWidth
);
6294 _orHorizontalShadowRect
.AddLeft( - aSidebarTotalWidth
);
6300 enum PaintArea
{LEFT
, RIGHT
, TOP
, BOTTOM
};
6304 #define BORDER_TILE_SIZE 512
6306 /// Wrapper around pOut->DrawBitmapEx.
6307 static void lcl_paintBitmapExToRect(vcl::RenderContext
*pOut
, const Point
& aPoint
, const Size
& aSize
, const BitmapEx
& rBitmapEx
, PaintArea eArea
)
6309 if(!comphelper::LibreOfficeKit::isActive())
6311 // The problem is that if we get called multiple times and the color is
6312 // partly transparent, then the result will get darker and darker. To avoid
6313 // this, always paint the background color before doing the real paint.
6314 tools::Rectangle
aRect(aPoint
, aSize
);
6316 if (!aRect
.IsEmpty())
6320 case LEFT
: aRect
.SetLeft( aRect
.Right() - 1 ); break;
6321 case RIGHT
: aRect
.SetRight( aRect
.Left() + 1 ); break;
6322 case TOP
: aRect
.SetTop( aRect
.Bottom() - 1 ); break;
6323 case BOTTOM
: aRect
.SetBottom( aRect
.Top() + 1 ); break;
6327 pOut
->SetFillColor(SwViewOption::GetCurrentViewOptions().GetAppBackgroundColor());
6328 pOut
->SetLineColor();
6329 pOut
->DrawRect(pOut
->PixelToLogic(aRect
));
6332 // Tiled render if necessary
6333 tools::Rectangle
aComplete(aPoint
, aSize
);
6334 Size
aTileSize(BORDER_TILE_SIZE
, BORDER_TILE_SIZE
);
6336 tools::Long iterX
= eArea
!= RIGHT
&& eArea
!= LEFT
? BORDER_TILE_SIZE
: 0;
6337 tools::Long iterY
= eArea
== RIGHT
|| eArea
== LEFT
? BORDER_TILE_SIZE
: 0;
6339 for (tools::Rectangle
aTile(aPoint
, aTileSize
); true; aTile
.Move(iterX
, iterY
))
6341 tools::Rectangle aRender
= aComplete
.GetIntersection(aTile
);
6342 if (aRender
.IsEmpty())
6344 pOut
->DrawBitmapEx(pOut
->PixelToLogic(aRender
.TopLeft()),
6345 pOut
->PixelToLogic(aRender
.GetSize()),
6346 Point(0, 0), aRender
.GetSize(),
6353 * Paint page border and shadow
6356 * implement paint of page border and shadow
6358 /*static*/ void SwPageFrame::PaintBorderAndShadow( const SwRect
& _rPageRect
,
6359 const SwViewShell
* _pViewShell
,
6360 bool bPaintLeftShadow
,
6361 bool bPaintRightShadow
,
6362 bool bRightSidebar
)
6364 // No shadow in prefs
6365 if (!_pViewShell
->GetViewOptions()->IsShadow())
6368 // #i16816# tagged pdf support
6369 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *_pViewShell
->GetOut() );
6371 static tools::DeleteOnDeinit
<drawinglayer::primitive2d::DiscreteShadow
> shadowMaskObj(
6372 vcl::bitmap::loadFromName(BMP_PAGE_SHADOW_MASK
,
6373 ImageLoadFlags::IgnoreDarkTheme
| ImageLoadFlags::IgnoreScalingFactor
));
6375 drawinglayer::primitive2d::DiscreteShadow
& shadowMask
= *shadowMaskObj
.get();
6376 static tools::DeleteOnDeinit
< BitmapEx
> aPageTopRightShadowObj
{};
6377 static tools::DeleteOnDeinit
< BitmapEx
> aPageBottomRightShadowObj
{};
6378 static tools::DeleteOnDeinit
< BitmapEx
> aPageBottomLeftShadowObj
{};
6379 static tools::DeleteOnDeinit
< BitmapEx
> aPageBottomShadowBaseObj
{};
6380 static tools::DeleteOnDeinit
< BitmapEx
> aPageRightShadowBaseObj
{};
6381 static tools::DeleteOnDeinit
< BitmapEx
> aPageTopShadowBaseObj
{};
6382 static tools::DeleteOnDeinit
< BitmapEx
> aPageTopLeftShadowObj
{};
6383 static tools::DeleteOnDeinit
< BitmapEx
> aPageLeftShadowBaseObj
{};
6384 BitmapEx
& aPageTopRightShadow
= *aPageTopRightShadowObj
.get();
6385 BitmapEx
& aPageBottomRightShadow
= *aPageBottomRightShadowObj
.get();
6386 BitmapEx
& aPageBottomLeftShadow
= *aPageBottomLeftShadowObj
.get();
6387 BitmapEx
& aPageBottomShadow
= *aPageBottomShadowBaseObj
.get();
6388 BitmapEx
& aPageRightShadow
= *aPageRightShadowBaseObj
.get();
6389 BitmapEx
& aPageTopShadow
= *aPageTopShadowBaseObj
.get();
6390 BitmapEx
& aPageTopLeftShadow
= *aPageTopLeftShadowObj
.get();
6391 BitmapEx
& aPageLeftShadow
= *aPageLeftShadowBaseObj
.get();
6392 static Color
aShadowColor( COL_AUTO
);
6394 SwRect
aAlignedPageRect( _rPageRect
);
6395 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, _pViewShell
->GetOut() );
6396 SwRect
aPagePxRect(_pViewShell
->GetOut()->LogicToPixel( aAlignedPageRect
.SVRect() ));
6398 if (aShadowColor
!= _pViewShell
->GetViewOptions()->GetShadowColor())
6400 aShadowColor
= _pViewShell
->GetViewOptions()->GetShadowColor();
6402 AlphaMask
aMask( shadowMask
.getBottomRight().GetBitmap() );
6403 Bitmap
aFilledSquare(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6404 aFilledSquare
.Erase( aShadowColor
);
6405 aPageBottomRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6407 aMask
= AlphaMask( shadowMask
.getBottomLeft().GetBitmap() );
6408 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6409 aFilledSquare
.Erase( aShadowColor
);
6410 aPageBottomLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6412 aMask
= AlphaMask( shadowMask
.getBottom().GetBitmap() );
6413 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6414 aFilledSquare
.Erase( aShadowColor
);
6415 aPageBottomShadow
= BitmapEx( aFilledSquare
, aMask
);
6417 aMask
= AlphaMask( shadowMask
.getTop().GetBitmap() );
6418 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6419 aFilledSquare
.Erase( aShadowColor
);
6420 aPageTopShadow
= BitmapEx( aFilledSquare
, aMask
);
6422 aMask
= AlphaMask( shadowMask
.getTopRight().GetBitmap() );
6423 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6424 aFilledSquare
.Erase( aShadowColor
);
6425 aPageTopRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6427 aMask
= AlphaMask( shadowMask
.getRight().GetBitmap() );
6428 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6429 aFilledSquare
.Erase( aShadowColor
);
6430 aPageRightShadow
= BitmapEx( aFilledSquare
, aMask
);
6432 aMask
= AlphaMask( shadowMask
.getTopLeft().GetBitmap() );
6433 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6434 aFilledSquare
.Erase( aShadowColor
);
6435 aPageTopLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6437 aMask
= AlphaMask( shadowMask
.getLeft().GetBitmap() );
6438 aFilledSquare
= Bitmap(aMask
.GetSizePixel(), vcl::PixelFormat::N24_BPP
);
6439 aFilledSquare
.Erase( aShadowColor
);
6440 aPageLeftShadow
= BitmapEx( aFilledSquare
, aMask
);
6444 OutputDevice
*pOut
= _pViewShell
->GetOut();
6446 SwPageFrame::GetHorizontalShadowRect( _rPageRect
, _pViewShell
, pOut
, aPaintRect
, bPaintLeftShadow
, bPaintRightShadow
, bRightSidebar
);
6448 // Right shadow & corners
6449 if ( bPaintRightShadow
)
6451 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( aPaintRect
.Right(), aPagePxRect
.Bottom() + 1 - (aPageBottomRightShadow
.GetSizePixel().Height() - snShadowPxWidth
) ) ),
6452 aPageBottomRightShadow
);
6453 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( aPaintRect
.Right(), aPagePxRect
.Top() - snShadowPxWidth
) ),
6454 aPageTopRightShadow
);
6456 if (aPagePxRect
.Height() > 2 * snShadowPxWidth
)
6458 const tools::Long nWidth
= aPageRightShadow
.GetSizePixel().Width();
6459 const tools::Long nHeight
= aPagePxRect
.Height() - 2 * (snShadowPxWidth
- 1);
6460 if (aPageRightShadow
.GetSizePixel().Height() < BORDER_TILE_SIZE
)
6461 aPageRightShadow
.Scale(Size(nWidth
, BORDER_TILE_SIZE
), BmpScaleFlag::Fast
);
6463 lcl_paintBitmapExToRect(pOut
,
6464 Point(aPaintRect
.Right() + snShadowPxWidth
, aPagePxRect
.Top() + snShadowPxWidth
- 1),
6465 Size(nWidth
, nHeight
),
6466 aPageRightShadow
, RIGHT
);
6470 // Left shadows and corners
6471 if(bPaintLeftShadow
)
6473 const tools::Long lLeft
= aPaintRect
.Left() - aPageBottomLeftShadow
.GetSizePixel().Width();
6474 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( lLeft
,
6475 aPagePxRect
.Bottom() + 1 + snShadowPxWidth
- aPageBottomLeftShadow
.GetSizePixel().Height() ) ), aPageBottomLeftShadow
);
6476 pOut
->DrawBitmapEx( pOut
->PixelToLogic( Point( lLeft
, aPagePxRect
.Top() - snShadowPxWidth
) ), aPageTopLeftShadow
);
6477 if (aPagePxRect
.Height() > 2 * snShadowPxWidth
)
6479 const tools::Long nWidth
= aPageLeftShadow
.GetSizePixel().Width();
6480 const tools::Long nHeight
= aPagePxRect
.Height() - 2 * (snShadowPxWidth
- 1);
6481 if (aPageLeftShadow
.GetSizePixel().Height() < BORDER_TILE_SIZE
)
6482 aPageLeftShadow
.Scale(Size(nWidth
, BORDER_TILE_SIZE
), BmpScaleFlag::Fast
);
6484 lcl_paintBitmapExToRect(pOut
,
6485 Point(lLeft
, aPagePxRect
.Top() + snShadowPxWidth
- 1),
6486 Size(nWidth
, nHeight
),
6487 aPageLeftShadow
, LEFT
);
6492 const tools::Long nBottomHeight
= aPageBottomShadow
.GetSizePixel().Height();
6493 if (aPageBottomShadow
.GetSizePixel().Width() < BORDER_TILE_SIZE
)
6494 aPageBottomShadow
.Scale(Size(BORDER_TILE_SIZE
, nBottomHeight
), BmpScaleFlag::Fast
);
6496 lcl_paintBitmapExToRect(pOut
,
6497 Point(aPaintRect
.Left(), aPagePxRect
.Bottom() + 2),
6498 Size(aPaintRect
.Width(), nBottomHeight
),
6499 aPageBottomShadow
, BOTTOM
);
6502 const tools::Long nTopHeight
= aPageTopShadow
.GetSizePixel().Height();
6503 if (aPageTopShadow
.GetSizePixel().Width() < BORDER_TILE_SIZE
)
6504 aPageTopShadow
.Scale(Size(BORDER_TILE_SIZE
, nTopHeight
), BmpScaleFlag::Fast
);
6506 lcl_paintBitmapExToRect(pOut
,
6507 Point(aPaintRect
.Left(), aPagePxRect
.Top() - snShadowPxWidth
),
6508 Size(aPaintRect
.Width(), nTopHeight
),
6509 aPageTopShadow
, TOP
);
6513 * mod #i6193# paint sidebar for notes
6514 * IMPORTANT: if you change the rects here, also change SwPostItMgr::ScrollbarHit
6516 /*static*/void SwPageFrame::PaintNotesSidebar(const SwRect
& _rPageRect
, SwViewShell
* _pViewShell
, sal_uInt16 nPageNum
, bool bRight
)
6518 //TODO: cut out scrollbar area and arrows out of sidepane rect, otherwise it could flicker when pressing arrow buttons
6522 SwRect
aPageRect( _rPageRect
);
6523 SwAlignRect( aPageRect
, _pViewShell
, _pViewShell
->GetOut() );
6525 const SwPostItMgr
*pMgr
= _pViewShell
->GetPostItMgr();
6526 if (!(pMgr
&& pMgr
->ShowNotes() && pMgr
->HasNotes())) // do not show anything in print preview
6529 sal_Int32 nScrollerHeight
= pMgr
->GetSidebarScrollerHeight();
6530 const tools::Rectangle aVisRect
= _pViewShell
->VisArea().SVRect();
6531 //draw border and sidepane
6532 _pViewShell
->GetOut()->SetLineColor();
6535 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetDocBoundariesColor());
6536 _pViewShell
->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect
.Left()-pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarBorderWidth(),aPageRect
.Height()))) ;
6537 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6538 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6540 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetSectionBoundColor());
6541 _pViewShell
->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect
.Left()-pMgr
->GetSidebarWidth()-pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarWidth(),aPageRect
.Height()))) ;
6545 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetDocBoundariesColor());
6546 SwRect
aSidebarBorder(aPageRect
.TopRight(),Size(pMgr
->GetSidebarBorderWidth(),aPageRect
.Height()));
6547 _pViewShell
->GetOut()->DrawRect(aSidebarBorder
.SVRect());
6548 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6549 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6551 _pViewShell
->GetOut()->SetFillColor(_pViewShell
->GetViewOptions()->GetSectionBoundColor());
6552 SwRect
aSidebar(Point(aPageRect
.Right()+pMgr
->GetSidebarBorderWidth(),aPageRect
.Top()),Size(pMgr
->GetSidebarWidth(),aPageRect
.Height()));
6553 _pViewShell
->GetOut()->DrawRect(aSidebar
.SVRect());
6555 if (!pMgr
->ShowScrollbar(nPageNum
))
6558 // draw scrollbar area and arrows
6561 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()) :
6562 Point(aPageRect
.Right() + pMgr
->GetSidebarBorderWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Bottom()- _pViewShell
->GetOut()->PixelToLogic(Size(0,2+pMgr
->GetSidebarScrollerHeight())).Height());
6563 aPointTop
= !bRight
? Point(aPageRect
.Left() - pMgr
->GetSidebarWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + _pViewShell
->GetOut()->PixelToLogic(Size(0,2)).Height()) :
6564 Point(aPageRect
.Right() + pMgr
->GetSidebarBorderWidth() + _pViewShell
->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect
.Top() + _pViewShell
->GetOut()->PixelToLogic(Size(0,2)).Height());
6565 Size
aSize(pMgr
->GetSidebarWidth() - _pViewShell
->GetOut()->PixelToLogic(Size(4,0)).Width(), _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()) ;
6566 tools::Rectangle
aRectBottom(aPointBottom
,aSize
);
6567 tools::Rectangle
aRectTop(aPointTop
,aSize
);
6569 if (aRectBottom
.Overlaps(aVisRect
))
6572 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6574 _pViewShell
->GetOut()->SetLineColor(COL_WHITE
);
6575 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6579 _pViewShell
->GetOut()->SetLineColor(COL_BLACK
);
6580 _pViewShell
->GetOut()->SetFillColor(COL_LIGHTGRAY
);
6582 _pViewShell
->GetOut()->DrawRect(aRectBottom
);
6583 _pViewShell
->GetOut()->DrawLine(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3,0), aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3 , _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()));
6585 _pViewShell
->GetOut()->SetLineColor();
6586 Point
aMiddleFirst(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/6,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6587 Point
aMiddleSecond(aPointBottom
+ Point(pMgr
->GetSidebarWidth()/3*2,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6588 PaintNotesSidebarArrows(aMiddleFirst
,aMiddleSecond
,_pViewShell
,pMgr
->GetArrowColor(KEY_PAGEUP
,nPageNum
), pMgr
->GetArrowColor(KEY_PAGEDOWN
,nPageNum
));
6590 if (!aRectTop
.Overlaps(aVisRect
))
6593 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6595 _pViewShell
->GetOut()->SetLineColor(COL_WHITE
);
6596 _pViewShell
->GetOut()->SetFillColor(COL_BLACK
);
6600 _pViewShell
->GetOut()->SetLineColor(COL_BLACK
);
6601 _pViewShell
->GetOut()->SetFillColor(COL_LIGHTGRAY
);
6603 _pViewShell
->GetOut()->DrawRect(aRectTop
);
6604 _pViewShell
->GetOut()->DrawLine(aPointTop
+ Point(pMgr
->GetSidebarWidth()/3*2,0), aPointTop
+ Point(pMgr
->GetSidebarWidth()/3*2 , _pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()));
6606 _pViewShell
->GetOut()->SetLineColor();
6607 Point
aMiddleFirst(aPointTop
+ Point(pMgr
->GetSidebarWidth()/3,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6608 Point
aMiddleSecond(aPointTop
+ Point(pMgr
->GetSidebarWidth()/6*5,_pViewShell
->GetOut()->PixelToLogic(Size(0,nScrollerHeight
)).Height()/2));
6609 PaintNotesSidebarArrows(aMiddleFirst
,aMiddleSecond
,_pViewShell
, pMgr
->GetArrowColor(KEY_PAGEUP
,nPageNum
), pMgr
->GetArrowColor(KEY_PAGEDOWN
,nPageNum
));
6612 /*static*/ void SwPageFrame::PaintNotesSidebarArrows(const Point
&aMiddleFirst
, const Point
&aMiddleSecond
, SwViewShell
const * _pViewShell
, const Color
& rColorUp
, const Color
& rColorDown
)
6614 tools::Polygon
aTriangleUp(3);
6615 tools::Polygon
aTriangleDown(3);
6617 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(0,_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6618 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),1);
6619 aTriangleUp
.SetPoint(aMiddleFirst
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6621 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6622 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(_pViewShell
->GetOut()->PixelToLogic(Size(+3,0)).Width(),_pViewShell
->GetOut()->PixelToLogic(Size(0,-3)).Height()),1);
6623 aTriangleDown
.SetPoint(aMiddleSecond
+ Point(0,_pViewShell
->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6625 _pViewShell
->GetOut()->SetFillColor(rColorUp
);
6626 _pViewShell
->GetOut()->DrawPolygon(aTriangleUp
);
6627 _pViewShell
->GetOut()->SetFillColor(rColorDown
);
6628 _pViewShell
->GetOut()->DrawPolygon(aTriangleDown
);
6632 * Get bound rectangle of border and shadow for repaints
6636 /*static*/ void SwPageFrame::GetBorderAndShadowBoundRect( const SwRect
& _rPageRect
,
6637 const SwViewShell
* _pViewShell
,
6638 OutputDevice
const * pRenderContext
,
6639 SwRect
& _orBorderAndShadowBoundRect
,
6645 SwRect
aAlignedPageRect( _rPageRect
);
6646 ::SwAlignRect( aAlignedPageRect
, _pViewShell
, pRenderContext
);
6647 SwRect
aPagePxRect(pRenderContext
->LogicToPixel( aAlignedPageRect
.SVRect() ));
6648 aPagePxRect
.AddBottom( snShadowPxWidth
+ 1 );
6649 aPagePxRect
.AddTop( - snShadowPxWidth
- 1 );
6653 // Always ask for full shadow since we want a bounding rect
6654 // including at least the page frame
6655 SwPageFrame::GetHorizontalShadowRect( _rPageRect
, _pViewShell
, pRenderContext
, aTmpRect
, false, false, bRightSidebar
);
6657 if(bLeftShadow
) aPagePxRect
.Left( aTmpRect
.Left() - snShadowPxWidth
- 1);
6658 if(bRightShadow
) aPagePxRect
.Right( aTmpRect
.Right() + snShadowPxWidth
+ 1);
6660 _orBorderAndShadowBoundRect
= SwRect(pRenderContext
->PixelToLogic( aPagePxRect
.SVRect() ));
6663 SwRect
SwPageFrame::GetBoundRect(OutputDevice
const * pOutputDevice
) const
6665 const SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
6666 SwRect
aPageRect( getFrameArea() );
6670 return SwRect( Point(0, 0), Size(0, 0) );
6673 SwPageFrame::GetBorderAndShadowBoundRect( aPageRect
, pSh
, pOutputDevice
, aResult
,
6674 IsLeftShadowNeeded(), IsRightShadowNeeded(), SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT
);
6678 /*static*/ SwTwips
SwPageFrame::GetSidebarBorderWidth( const SwViewShell
* _pViewShell
)
6680 const SwPostItMgr
* pPostItMgr
= _pViewShell
? _pViewShell
->GetPostItMgr() : nullptr;
6681 const SwTwips nRet
= pPostItMgr
&& pPostItMgr
->HasNotes() && pPostItMgr
->ShowNotes() ? pPostItMgr
->GetSidebarWidth() + pPostItMgr
->GetSidebarBorderWidth() : 0;
6685 const SwFrame
* SwFrame::SkipFrame(const SwFrame
* pFrame
, PaintFrameMode ePaintFrameMode
)
6687 if (ePaintFrameMode
!= PAINT_ALL
)
6689 if (ePaintFrameMode
== PAINT_NON_HEADER_FOOTER
)
6691 while (pFrame
&& (pFrame
->IsHeaderFrame() || pFrame
->IsFooterFrame()))
6692 pFrame
= pFrame
->GetNext();
6696 while ( pFrame
&& !pFrame
->IsHeaderFrame() && !pFrame
->IsFooterFrame())
6697 pFrame
= pFrame
->GetNext();
6703 void SwFrame::PaintBaBo( const SwRect
& rRect
, const SwPageFrame
*pPage
,
6704 const bool bOnlyTextBackground
, PaintFrameMode ePaintFrameMode
) const
6707 pPage
= FindPageFrame();
6709 OutputDevice
*pOut
= gProp
.pSGlobalShell
->GetOut();
6711 // #i16816# tagged pdf support
6712 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut
);
6714 pOut
->Push( vcl::PushFlags::FILLCOLOR
|vcl::PushFlags::LINECOLOR
);
6715 pOut
->SetLineColor();
6717 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), this );
6718 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
6720 // take care of page margin area
6721 // Note: code move from <SwFrame::PaintSwFrameBackground(..)> to new method
6722 // <SwPageFrame::Paintmargin(..)>.
6723 if ( IsPageFrame() && !bOnlyTextBackground
)
6725 static_cast<const SwPageFrame
*>(this)->PaintMarginArea( rRect
, gProp
.pSGlobalShell
);
6730 PaintSwFrameBackground( rRect
, pPage
, rAttrs
, false, true/*bLowerBorder*/, bOnlyTextBackground
, ePaintFrameMode
);
6733 // paint border before painting background
6734 // paint grid for page frame and paint border
6735 if (!bOnlyTextBackground
)
6737 SwRect
aRect( rRect
);
6741 static_cast<const SwPageFrame
*>(this)->PaintGrid( pOut
, aRect
);
6744 PaintSwFrameShadowAndBorder(aRect
, pPage
, rAttrs
);
6750 static bool lcl_compareFillAttributes(const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& pA
, const drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& pB
)
6756 return pA
->getFillAttribute() == pB
->getFillAttribute();
6759 /// Do not paint background for fly frames without a background brush by
6760 /// calling <PaintBaBo> at the page or at the fly frame its anchored
6761 void SwFrame::PaintSwFrameBackground( const SwRect
&rRect
, const SwPageFrame
*pPage
,
6762 const SwBorderAttrs
& rAttrs
,
6763 const bool bLowerMode
,
6764 const bool bLowerBorder
,
6765 const bool bOnlyTextBackground
,
6766 PaintFrameMode ePaintFrameMode
) const
6768 // #i1837# - no paint of table background, if corresponding option is *not* set.
6769 SwViewShell
*pSh
= gProp
.pSGlobalShell
;
6771 !pSh
->GetViewOptions()->IsTable() )
6776 // nothing to do for covered table cells:
6777 if( IsCellFrame() && IsCoveredCell() )
6780 // #i16816# tagged pdf support
6781 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh
->GetOut() );
6783 const SvxBrushItem
* pItem
;
6784 // temporary background brush for a fly frame without a background brush
6785 std::unique_ptr
<SvxBrushItem
> pTmpBackBrush
;
6786 std::optional
<Color
> pCol
;
6787 SwRect aOrigBackRect
;
6788 const bool bPageFrame
= IsPageFrame();
6789 bool bLowMode
= true;
6790 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
6792 bool bBack
= GetBackgroundBrush( aFillAttributes
, pItem
, pCol
, aOrigBackRect
, bLowerMode
, /*bConsiderTextBox=*/false );
6794 // show track changes of table row
6795 if( IsRowFrame() && !getRootFrame()->IsHideRedlines() )
6797 RedlineType eType
= static_cast<const SwRowFrame
*>(this)->GetTabLine()->GetRedlineType();
6798 if ( RedlineType::Delete
== eType
|| RedlineType::Insert
== eType
)
6800 pCol
= RedlineType::Delete
== eType
? COL_AUTHOR_TABLE_DEL
: COL_AUTHOR_TABLE_INS
;
6804 else if ( IsCellFrame() && !getRootFrame()->IsHideRedlines() )
6806 RedlineType eType
= static_cast<const SwCellFrame
*>(this)->GetTabBox()->GetRedlineType();
6807 if ( RedlineType::Delete
== eType
|| RedlineType::Insert
== eType
)
6809 pCol
= RedlineType::Delete
== eType
? COL_AUTHOR_TABLE_DEL
: COL_AUTHOR_TABLE_INS
;
6814 if ( bBack
&& IsCellFrame() && !getRootFrame()->IsHideRedlines() &&
6815 // skip cell background to show the row colored according to its tracked change
6816 RedlineType::None
!= static_cast<const SwRowFrame
*>(GetUpper())->GetTabLine()->GetRedlineType() )
6821 //- Output if a separate background is used.
6822 bool bNoFlyBackground
= !gProp
.bSFlyMetafile
&& !bBack
&& IsFlyFrame();
6823 if ( bNoFlyBackground
)
6825 // Fly frame has no background.
6826 // Try to find background brush at parents, if previous call of
6827 // <GetBackgroundBrush> disabled this option with the parameter <bLowerMode>
6830 bBack
= GetBackgroundBrush( aFillAttributes
, pItem
, pCol
, aOrigBackRect
, false, /*bConsiderTextBox=*/false );
6832 // If still no background found for the fly frame, initialize the
6833 // background brush <pItem> with global retouche color and set <bBack>
6834 // to true, that fly frame will paint its background using this color.
6837 // #i6467# - on print output, pdf output and in embedded mode not editing color COL_WHITE is used
6838 // instead of the global retouche color.
6839 if ( pSh
->GetOut()->GetOutDevType() == OUTDEV_PRINTER
||
6840 pSh
->GetViewOptions()->IsPDFExport() ||
6841 ( pSh
->GetDoc()->GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED
&&
6842 !pSh
->GetDoc()->GetDocShell()->IsInPlaceActive()
6846 pTmpBackBrush
.reset(new SvxBrushItem( COL_WHITE
, RES_BACKGROUND
));
6849 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(COL_WHITE
);
6853 pTmpBackBrush
.reset(new SvxBrushItem( aGlobalRetoucheColor
, RES_BACKGROUND
));
6856 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(aGlobalRetoucheColor
);
6859 pItem
= pTmpBackBrush
.get();
6864 SwRect
aPaintRect( getFrameArea() );
6865 if( IsTextFrame() || IsSctFrame() )
6866 aPaintRect
= UnionFrame( true );
6868 // bOnlyTextBackground means background that's on top of background shapes,
6869 // this includes both text and cell frames.
6870 if ( (!bOnlyTextBackground
|| IsTextFrame() || IsCellFrame()) && aPaintRect
.Overlaps( rRect
) )
6872 if ( bBack
|| bPageFrame
|| !bLowerMode
)
6874 const bool bBrowse
= pSh
->GetViewOptions()->getBrowseMode();
6876 if ( (bPageFrame
&& bBrowse
) ||
6877 (IsTextFrame() && getFramePrintArea().SSize() == getFrameArea().SSize()) )
6879 aRect
= getFrameArea();
6880 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
6884 if (bPageFrame
&& GetAttrSet()->GetItem
<SfxBoolItem
>(RES_BACKGROUND_FULL_SIZE
)->GetValue())
6886 aRect
= getFrameArea();
6887 ::SwAlignRect(aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut());
6891 ::lcl_CalcBorderRect( aRect
, this, rAttrs
, false, gProp
);
6894 if ( (IsTextFrame() || IsTabFrame()) && GetPrev() )
6896 if ( GetPrev()->GetAttrSet()->GetBackground() == GetAttrSet()->GetBackground() &&
6897 lcl_compareFillAttributes(GetPrev()->getSdrAllFillAttributesHelper(), getSdrAllFillAttributesHelper()))
6899 aRect
.Top( getFrameArea().Top() );
6903 aRect
.Intersection( rRect
);
6905 OutputDevice
*pOut
= pSh
->GetOut();
6907 if ( aRect
.HasArea() )
6909 std::unique_ptr
<SvxBrushItem
> pNewItem
;
6913 pNewItem
.reset(new SvxBrushItem( *pCol
, RES_BACKGROUND
));
6914 pItem
= pNewItem
.get();
6915 aFillAttributes
= std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(*pCol
);
6918 SwRegionRects
aRegion( aRect
);
6919 basegfx::B2DPolygon aB2DPolygon
{tools::Polygon(aRect
.SVRect()).getB2DPolygon()};
6920 basegfx::utils::B2DClipState aClipState
{basegfx::B2DPolyPolygon(aB2DPolygon
)};
6921 if (pPage
->GetSortedObjs() &&
6922 pSh
->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS
))
6924 ::lcl_SubtractFlys( this, pPage
, aRect
, aRegion
, aClipState
, gProp
);
6927 // Determine, if background transparency
6928 // have to be considered for drawing.
6929 // Status Quo: background transparency have to be
6930 // considered for fly frames
6931 const bool bConsiderBackgroundTransparency
= IsFlyFrame();
6934 // #i125189# We are also done when the new DrawingLayer FillAttributes are used
6935 // or the FillStyle is set (different from drawing::FillStyle_NONE)
6936 if (aFillAttributes
)
6938 if(aFillAttributes
->isUsed())
6940 // check if really something is painted
6941 bDone
= DrawFillAttributes(aFillAttributes
, aOrigBackRect
, aRegion
, aClipState
, *pOut
);
6946 // if not, still a FillStyle could be set but the transparency is at 100%,
6947 // thus need to check the model data itself for FillStyle (do not rely on
6948 // SdrAllFillAttributesHelper since it already contains optimized information,
6949 // e.g. transparency leads to no fill)
6950 const drawing::FillStyle
eFillStyle(GetAttrSet()->Get(XATTR_FILLSTYLE
).GetValue());
6952 if(drawing::FillStyle_NONE
!= eFillStyle
)
6961 for (size_t i
= 0; i
< aRegion
.size(); ++i
)
6963 if (1 < aRegion
.size())
6965 ::SwAlignRect( aRegion
[i
], gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
6966 if( !aRegion
[i
].HasArea() )
6969 // add 6th parameter to indicate, if background transparency have to be considered
6970 // Set missing 5th parameter to the default value GRFNUM_NO
6971 // - see declaration in /core/inc/frmtool.hxx.
6978 bConsiderBackgroundTransparency
);
6984 bLowMode
= bLowerMode
;
6987 // delete temporary background brush.
6988 pTmpBackBrush
.reset();
6990 //Now process lower and his neighbour.
6991 //We end this as soon as a Frame leaves the chain and therefore is not a lower
6993 const SwFrame
*pFrame
= GetLower();
6998 SwRect
aRect( GetPaintArea() );
6999 aRect
.Intersection_( rRect
);
7000 SwRect
aBorderRect( aRect
);
7002 pFrame
= SkipFrame(pFrame
, ePaintFrameMode
);
7006 SwShortCut
aShortCut( *pFrame
, aBorderRect
);
7008 { if ( gProp
.pSProgress
)
7009 SfxProgress::Reschedule();
7011 aFrameRect
= pFrame
->GetPaintArea();
7012 if ( aFrameRect
.Overlaps( aBorderRect
) )
7014 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFrame
);
7015 const SwBorderAttrs
&rTmpAttrs
= *aAccess
.Get();
7016 if ( ( pFrame
->IsLayoutFrame() && bLowerBorder
) || aFrameRect
.Overlaps( aRect
) )
7018 pFrame
->PaintSwFrameBackground( aRect
, pPage
, rTmpAttrs
, bLowMode
,
7019 bLowerBorder
, bOnlyTextBackground
);
7024 pFrame
->PaintSwFrameShadowAndBorder( aBorderRect
, pPage
, rTmpAttrs
);
7027 pFrame
= pFrame
->GetNext();
7028 pFrame
= SkipFrame(pFrame
, ePaintFrameMode
);
7029 } while ( pFrame
&& pFrame
->GetUpper() == this &&
7030 !aShortCut
.Stop( aFrameRect
) );
7033 /// Refreshes all subsidiary lines of a page.
7034 void SwPageFrame::RefreshSubsidiary( const SwRect
&rRect
) const
7036 if ( !(isSubsidiaryLinesEnabled() ||
7037 gProp
.pSGlobalShell
->GetViewOptions()->IsTextBoundaries() ||
7038 gProp
.pSGlobalShell
->GetViewOptions()->IsSectionBoundaries() ||
7039 gProp
.pSGlobalShell
->GetViewOptions()->IsTableBoundaries()) )
7042 if ( !rRect
.HasArea() )
7045 //During paint using the root, the array is controlled from there.
7046 //Otherwise we'll handle it for our self.
7047 bool bDelSubs
= false;
7048 if ( !gProp
.pSSubsLines
)
7050 gProp
.pSSubsLines
.reset(new SwSubsRects
);
7051 // create container for special subsidiary lines
7052 gProp
.pSSpecSubsLines
.reset(new SwSubsRects
);
7056 RefreshLaySubsidiary( this, rRect
);
7060 // paint special subsidiary lines and delete its container
7061 gProp
.pSSpecSubsLines
->PaintSubsidiary( gProp
.pSGlobalShell
->GetOut(), nullptr, gProp
);
7062 gProp
.pSSpecSubsLines
.reset();
7064 gProp
.pSSubsLines
->PaintSubsidiary(gProp
.pSGlobalShell
->GetOut(), gProp
.pSLines
.get(), gProp
);
7065 gProp
.pSSubsLines
.reset();
7069 void SwLayoutFrame::RefreshLaySubsidiary( const SwPageFrame
*pPage
,
7070 const SwRect
&rRect
) const
7072 if (isSubsidiaryLinesEnabled())
7073 PaintSubsidiaryLines( pPage
, rRect
);
7075 const SwFrame
*pLow
= Lower();
7078 SwShortCut
aShortCut( *pLow
, rRect
);
7079 while( pLow
&& !aShortCut
.Stop( pLow
->getFrameArea() ) )
7081 if ( pLow
->getFrameArea().Overlaps( rRect
) && pLow
->getFrameArea().HasArea() )
7083 if ( pLow
->IsLayoutFrame() )
7084 static_cast<const SwLayoutFrame
*>(pLow
)->RefreshLaySubsidiary( pPage
, rRect
);
7085 else if ( pLow
->GetDrawObjs() )
7087 const SwSortedObjs
& rObjs
= *(pLow
->GetDrawObjs());
7088 for (SwAnchoredObject
* pAnchoredObj
: rObjs
)
7090 if ( pPage
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
7091 pAnchoredObj
->GetDrawObj()->GetLayer() ) )
7092 if (auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7094 if ( pFly
->IsFlyInContentFrame() && pFly
->getFrameArea().Overlaps( rRect
) )
7096 SwFrame
* pLower
= pFly
->Lower();
7097 if ( !pLower
|| !pLower
->IsNoTextFrame() ||
7098 !static_cast<const SwNoTextFrame
*>(pLower
)->HasAnimation())
7099 pFly
->RefreshLaySubsidiary( pPage
, rRect
);
7105 pLow
= pLow
->GetNext();
7110 * Subsidiary lines to paint the PrtAreas
7111 * Only the LayoutFrames which directly contain Content
7112 * Paints the desired line and pays attention to not overpaint any flys
7114 static void lcl_RefreshLine( const SwLayoutFrame
*pLay
,
7115 const SwPageFrame
*pPage
,
7118 const SubColFlags nSubColor
,
7119 SwLineRects
* pSubsLines
)
7121 //In which direction do we loop? Can only be horizontal or vertical.
7122 OSL_ENSURE( ((rP1
.X() == rP2
.X()) || (rP1
.Y() == rP2
.Y())),
7123 "Sloped subsidiary lines are not allowed." );
7125 const bool bHori
= rP1
.Y() == rP2
.Y();
7127 // use pointers to member function in order to unify flow
7128 typedef tools::Long (Point::*pmfPtGet
)() const;
7129 typedef void (Point::*pmfPtSet
)(tools::Long
);
7130 const pmfPtGet pDirPtX
= &Point::X
;
7131 const pmfPtGet pDirPtY
= &Point::Y
;
7132 const pmfPtGet pDirPt
= bHori
? pDirPtX
: pDirPtY
;
7133 const pmfPtSet pDirPtSetX
= &Point::setX
;
7134 const pmfPtSet pDirPtSetY
= &Point::setY
;
7135 const pmfPtSet pDirPtSet
= bHori
? pDirPtSetX
: pDirPtSetY
;
7140 while ( (aP1
.*pDirPt
)() < (aP2
.*pDirPt
)() )
7142 //If the starting point lies in a fly, it is directly set behind the
7144 //The end point moves to the start if the end point lies in a fly or we
7145 //have a fly between starting point and end point.
7146 // In this way, every position is output one by one.
7148 //If I'm a fly I'll only avoid those flys which are places 'above' me;
7149 //this means those who are behind me in the array.
7150 //Even if I'm inside a fly or inside a fly inside a fly a.s.o I won't
7151 //avoid any of those flys.
7152 SwOrderIter
aIter( pPage
);
7153 const SwFlyFrame
*pMyFly
= pLay
->FindFlyFrame();
7156 aIter
.Current( pMyFly
->GetVirtDrawObj() );
7157 while ( nullptr != (pMyFly
= pMyFly
->GetAnchorFrame()->FindFlyFrame()) )
7159 if ( aIter()->GetOrdNum() > pMyFly
->GetVirtDrawObj()->GetOrdNum() )
7160 aIter
.Current( pMyFly
->GetVirtDrawObj() );
7168 const SwVirtFlyDrawObj
*pObj
= static_cast<const SwVirtFlyDrawObj
*>(aIter());
7169 const SwFlyFrame
*pFly
= pObj
? pObj
->GetFlyFrame() : nullptr;
7171 //I certainly won't avoid myself, even if I'm placed _inside_ the
7172 //fly I won't avoid it.
7173 if ( !pFly
|| (pFly
== pLay
|| pFly
->IsAnLower( pLay
)) )
7179 // do *not* consider fly frames with a transparent background.
7180 // do *not* consider fly frame, which belongs to an invisible layer
7181 if ( pFly
->IsBackgroundTransparent() ||
7182 !pFly
->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( pObj
->GetLayer() ) )
7188 //Is the Obj placed on the line
7189 const tools::Long nP1OthPt
= !bHori
? rP1
.X() : rP1
.Y();
7190 const tools::Rectangle
&rBound
= pObj
->GetCurrentBoundRect();
7191 const Point
aDrPt( rBound
.TopLeft() );
7192 const tools::Long nDrOthPt
= !bHori
? aDrPt
.X() : aDrPt
.Y();
7193 const Size
aDrSz( rBound
.GetSize() );
7194 const tools::Long nDrOthSz
= !bHori
? aDrSz
.Width() : aDrSz
.Height();
7196 if ( nP1OthPt
>= nDrOthPt
&& nP1OthPt
<= nDrOthPt
+ nDrOthSz
)
7198 const tools::Long nDrDirPt
= bHori
? aDrPt
.X() : aDrPt
.Y();
7199 const tools::Long nDrDirSz
= bHori
? aDrSz
.Width() : aDrSz
.Height();
7201 if ( (aP1
.*pDirPt
)() >= nDrDirPt
&& (aP1
.*pDirPt
)() <= nDrDirPt
+ nDrDirSz
)
7202 (aP1
.*pDirPtSet
)( nDrDirPt
+ nDrDirSz
);
7204 if ( (aP2
.*pDirPt
)() >= nDrDirPt
&& (aP1
.*pDirPt
)() < (nDrDirPt
- 1) )
7205 (aP2
.*pDirPtSet
)( nDrDirPt
- 1 );
7210 if ( (aP1
.*pDirPt
)() < (aP2
.*pDirPt
)() )
7212 SwRect
aRect( aP1
, aP2
);
7213 // use parameter <pSubsLines> instead of global variable <gProp.pSSubsLines>.
7214 pSubsLines
->AddLineRect( aRect
, nullptr, SvxBorderLineStyle::SOLID
,
7215 nullptr, nSubColor
, gProp
);
7218 (aP1
.*pDirPtSet
)( (aP1
.*pDirPt
)() + 1 );
7223 static std::vector
<basegfx::B2DPolygon
> lcl_CreatePageAreaDelimiterPolygons(const SwRect
& rRect
, bool bHeaderFooter
)
7225 std::vector
<basegfx::B2DPolygon
> aPolygons
;
7227 // Hide text boundaries by default - cool#3491
7228 if (!bHeaderFooter
&& comphelper::LibreOfficeKit::isActive())
7231 double nLineLength
= 200.0; // in Twips
7233 Point aPoints
[] = { rRect
.TopLeft(), rRect
.TopRight(), rRect
.BottomRight(), rRect
.BottomLeft() };
7234 double const aXOffDirs
[] = { -1.0, 1.0, 1.0, -1.0 };
7235 double const aYOffDirs
[] = { -1.0, -1.0, 1.0, 1.0 };
7237 // Actually loop over the corners to create the two lines
7238 for ( int i
= 0; i
< 4; i
++ )
7240 basegfx::B2DVector
aHorizVector( aXOffDirs
[i
], 0.0 );
7241 basegfx::B2DVector
aVertVector( 0.0, aYOffDirs
[i
] );
7243 basegfx::B2DPoint
aBPoint( aPoints
[i
].getX(), aPoints
[i
].getY() );
7245 basegfx::B2DPolygon aPolygon
;
7246 aPolygon
.append( aBPoint
+ aHorizVector
* nLineLength
);
7247 aPolygon
.append( aBPoint
);
7248 aPolygon
.append( aBPoint
+ aVertVector
* nLineLength
);
7250 aPolygons
.emplace_back(aPolygon
);
7256 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateDelimiterPrimitives(
7257 const std::vector
<basegfx::B2DPolygon
>& rPolygons
)
7259 drawinglayer::primitive2d::Primitive2DContainer
aSeq(rPolygons
.size());
7261 basegfx::BColor aLineColor
= SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
7262 for (size_t i
= 0; i
< rPolygons
.size(); ++i
)
7263 aSeq
[i
] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(rPolygons
[i
], aLineColor
);
7268 static std::vector
<basegfx::B2DPolygon
> lcl_CreateRectangleDelimiterPolygons(const SwRect
& rRect
)
7270 std::vector
<basegfx::B2DPolygon
> aRet(1);
7271 aRet
[0].append( basegfx::B2DPoint( rRect
.Left(), rRect
.Top() ) );
7272 aRet
[0].append( basegfx::B2DPoint( rRect
.Right(), rRect
.Top() ) );
7273 aRet
[0].append( basegfx::B2DPoint( rRect
.Right(), rRect
.Bottom() ) );
7274 aRet
[0].append( basegfx::B2DPoint( rRect
.Left(), rRect
.Bottom() ) );
7275 aRet
[0].setClosed( true );
7279 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateRectangleDelimiterPrimitives (
7280 const SwRect
& rRect
)
7282 return lcl_CreateDelimiterPrimitives(lcl_CreateRectangleDelimiterPolygons(rRect
));
7285 static drawinglayer::primitive2d::Primitive2DContainer
lcl_CreateColumnAreaDelimiterPrimitives(
7286 const SwRect
& rRect
)
7288 drawinglayer::primitive2d::Primitive2DContainer
aSeq( 4 );
7290 basegfx::BColor aLineColor
= SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
7291 double nLineLength
= 100.0; // in Twips
7293 Point aPoints
[] = { rRect
.TopLeft(), rRect
.TopRight(), rRect
.BottomRight(), rRect
.BottomLeft() };
7294 double const aXOffDirs
[] = { 1.0, -1.0, -1.0, 1.0 };
7295 double const aYOffDirs
[] = { 1.0, 1.0, -1.0, -1.0 };
7297 // Actually loop over the corners to create the two lines
7298 for ( int i
= 0; i
< 4; i
++ )
7300 basegfx::B2DVector
aHorizVector( aXOffDirs
[i
], 0.0 );
7301 basegfx::B2DVector
aVertVector( 0.0, aYOffDirs
[i
] );
7303 basegfx::B2DPoint
aBPoint( aPoints
[i
].getX(), aPoints
[i
].getY() );
7305 basegfx::B2DPolygon aPolygon
;
7306 aPolygon
.append( aBPoint
+ aHorizVector
* nLineLength
);
7307 aPolygon
.append( aBPoint
);
7308 aPolygon
.append( aBPoint
+ aVertVector
* nLineLength
);
7310 aSeq
[i
] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
7311 std::move(aPolygon
), aLineColor
);
7317 std::vector
<basegfx::B2DPolygon
> SwPageFrame::GetSubsidiaryLinesPolygons(const SwViewShell
& rViewShell
) const
7319 std::vector
<basegfx::B2DPolygon
> aPolygons
;
7321 if (!rViewShell
.GetViewOptions()->IsTextBoundaries())
7324 const SwFrame
* pLay
= Lower();
7325 const SwFrame
* pFootnoteCont
= nullptr;
7326 const SwFrame
* pPageBody
= nullptr;
7331 while ( pLay
&& !( pFootnoteCont
&& pPageBody
) )
7333 if ( pLay
->IsFootnoteContFrame( ) )
7334 pFootnoteCont
= pLay
;
7335 if ( pLay
->IsBodyFrame() )
7337 pLay
= pLay
->GetNext();
7343 SwRect
aArea( pPageBody
->getFrameArea() );
7344 if ( pFootnoteCont
)
7345 aArea
.AddBottom( pFootnoteCont
->getFrameArea().Bottom() - aArea
.Bottom() );
7347 if (aArea
.IsEmpty())
7350 if (!rViewShell
.GetViewOptions()->IsTextBoundariesFull())
7351 aPolygons
= lcl_CreatePageAreaDelimiterPolygons(aArea
, false /* body */);
7353 aPolygons
= lcl_CreateRectangleDelimiterPolygons(aArea
);
7358 void SwPageFrame::PaintSubsidiaryLines(const SwPageFrame
*, const SwRect
&) const
7360 if (gProp
.pSGlobalShell
->IsHeaderFooterEdit())
7363 std::vector
<basegfx::B2DPolygon
> aPolygons
= GetSubsidiaryLinesPolygons(*gProp
.pSGlobalShell
);
7364 if (aPolygons
.empty())
7367 ProcessPrimitives(lcl_CreateDelimiterPrimitives(aPolygons
));
7370 static void lclAddSubsidiaryLinesBounds(const std::vector
<basegfx::B2DPolygon
>& rPolygons
, RectangleVector
& rRects
)
7372 for (const auto& rPolygon
: rPolygons
)
7374 tools::Rectangle
aRect(vcl::unotools::rectangleFromB2DRectangle(rPolygon
.getB2DRange()));
7376 if (basegfx::utils::isRectangle(rPolygon
) && aRect
.GetWidth() > 4 && aRect
.GetHeight() > 4)
7378 // turn hairline rectangle into four non-overlapping blocks that cover the borders
7379 rRects
.emplace_back(tools::Rectangle(Point(aRect
.Left(), aRect
.Top()), Size(aRect
.GetWidth(), 2)));
7380 rRects
.emplace_back(tools::Rectangle(Point(aRect
.Left(), aRect
.Top() + 2), Size(2, aRect
.GetHeight() - 4)));
7381 rRects
.emplace_back(tools::Rectangle(Point(aRect
.Right() - 2, aRect
.Top() + 2), Size(2, aRect
.GetHeight() - 4)));
7382 rRects
.emplace_back(tools::Rectangle(Point(aRect
.Left(), aRect
.Top() + aRect
.GetHeight() - 2), Size(aRect
.GetWidth(), 2)));
7385 rRects
.emplace_back(aRect
);
7389 void SwPageFrame::AddSubsidiaryLinesBounds(const SwViewShell
& rViewShell
, RectangleVector
& rRects
) const
7391 lclAddSubsidiaryLinesBounds(GetSubsidiaryLinesPolygons(rViewShell
), rRects
);
7393 const SwFrame
*pLow
= Lower();
7396 if (pLow
->getFrameArea().HasArea())
7398 if (pLow
->IsHeaderFrame() || pLow
->IsFooterFrame())
7400 static_cast<const SwHeadFootFrame
*>(pLow
)->AddSubsidiaryLinesBounds(rViewShell
, rRects
);
7403 pLow
= pLow
->GetNext();
7407 void SwColumnFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7408 const SwRect
& ) const
7410 const SwFrame
* pLay
= Lower();
7411 const SwFrame
* pFootnoteCont
= nullptr;
7412 const SwFrame
* pColBody
= nullptr;
7413 while ( pLay
&& !( pFootnoteCont
&& pColBody
) )
7415 if ( pLay
->IsFootnoteContFrame( ) )
7416 pFootnoteCont
= pLay
;
7417 if ( pLay
->IsBodyFrame() )
7419 pLay
= pLay
->GetNext();
7422 assert(pColBody
&& "presumably this is impossible");
7424 SwRect
aArea( pColBody
->getFrameArea() );
7426 // #i3662# - enlarge top of column body frame's printing area
7427 // in sections to top of section frame.
7428 const bool bColInSection
= GetUpper()->IsSctFrame();
7429 if ( bColInSection
)
7432 aArea
.Right( GetUpper()->getFrameArea().Right() );
7434 aArea
.Top( GetUpper()->getFrameArea().Top() );
7437 if ( pFootnoteCont
)
7438 aArea
.AddBottom( pFootnoteCont
->getFrameArea().Bottom() - aArea
.Bottom() );
7440 ::SwAlignRect( aArea
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7442 if ( !gProp
.pSGlobalShell
->GetViewOptions()->IsTextBoundariesFull( ) )
7443 ProcessPrimitives( lcl_CreateColumnAreaDelimiterPrimitives( aArea
) );
7445 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea
) );
7448 void SwSectionFrame::PaintSubsidiaryLines( const SwPageFrame
* pPage
,
7449 const SwRect
& rRect
) const
7451 if (!gProp
.pSGlobalShell
->GetViewOptions()->IsSectionBoundaries())
7454 SwLayoutFrame::PaintSubsidiaryLines( pPage
, rRect
);
7458 * The SwBodyFrame doesn't print any subsidiary line: it's bounds are painted
7459 * either by the parent page or the parent column frame.
7461 void SwBodyFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7462 const SwRect
& ) const
7466 std::vector
<basegfx::B2DPolygon
> SwHeadFootFrame::GetSubsidiaryLinesPolygons(const SwViewShell
& rViewShell
) const
7468 std::vector
<basegfx::B2DPolygon
> aPolygons
;
7470 if (!rViewShell
.GetViewOptions()->IsTextBoundaries())
7473 SwRect
aArea( getFramePrintArea() );
7474 aArea
.Pos() += getFrameArea().Pos();
7475 if (!rViewShell
.GetViewOptions()->IsTextBoundariesFull( ))
7476 aPolygons
= lcl_CreatePageAreaDelimiterPolygons(aArea
, true /* header/footer*/);
7478 aPolygons
= lcl_CreateRectangleDelimiterPolygons(aArea
);
7483 void SwHeadFootFrame::PaintSubsidiaryLines(const SwPageFrame
*, const SwRect
&) const
7485 if (!gProp
.pSGlobalShell
->IsHeaderFooterEdit())
7488 std::vector
<basegfx::B2DPolygon
> aPolygons
= GetSubsidiaryLinesPolygons(*gProp
.pSGlobalShell
);
7489 if (aPolygons
.empty())
7492 ProcessPrimitives(lcl_CreateDelimiterPrimitives(aPolygons
));
7495 void SwHeadFootFrame::AddSubsidiaryLinesBounds(const SwViewShell
& rViewShell
, RectangleVector
& rRects
) const
7497 lclAddSubsidiaryLinesBounds(GetSubsidiaryLinesPolygons(rViewShell
), rRects
);
7501 * This method is overridden in order to have no subsidiary lines
7502 * around the footnotes.
7504 void SwFootnoteFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7505 const SwRect
& ) const
7510 * This method is overridden in order to have no subsidiary lines
7511 * around the footnotes containers.
7513 void SwFootnoteContFrame::PaintSubsidiaryLines( const SwPageFrame
*,
7514 const SwRect
& ) const
7518 void SwLayoutFrame::PaintSubsidiaryLines( const SwPageFrame
*pPage
,
7519 const SwRect
&rRect
) const
7521 bool bNewTableModel
= false;
7524 if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
7526 const SwTabFrame
* pTabFrame
= FindTabFrame();
7527 if ( pTabFrame
->IsCollapsingBorders() )
7530 bNewTableModel
= pTabFrame
->GetTable()->IsNewModel();
7531 // in the new table model, we have an early return for all cell-related
7532 // frames, except from non-covered table cells
7533 if ( bNewTableModel
)
7534 if ( IsTabFrame() ||
7536 ( IsCellFrame() && IsCoveredCell() ) )
7540 const bool bFlys
= pPage
->GetSortedObjs() != nullptr;
7542 const bool bCell
= IsCellFrame();
7544 if ( (IsSctFrame() || IsFlyFrame()) &&
7545 !gProp
.pSGlobalShell
->GetViewOptions()->IsSectionBoundaries() )
7547 if ( IsTextFrame() &&
7548 !gProp
.pSGlobalShell
->GetViewOptions()->IsTextBoundaries() )
7551 // #i3662# - use frame area for cells for section use also frame area
7552 const bool bUseFrameArea
= bCell
|| IsSctFrame();
7553 SwRect
aOriginal( bUseFrameArea
? getFrameArea() : getFramePrintArea() );
7554 if ( !bUseFrameArea
)
7555 aOriginal
.Pos() += getFrameArea().Pos();
7557 ::SwAlignRect( aOriginal
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7559 if ( !aOriginal
.Overlaps( rRect
) )
7562 SwRect
aOut( aOriginal
);
7563 aOut
.Intersection_( rRect
);
7565 const SwTwips nRight
= aOut
.Right();
7566 const SwTwips nBottom
= aOut
.Bottom();
7568 const Point
aRT( nRight
, aOut
.Top() );
7569 const Point
aRB( nRight
, nBottom
);
7570 const Point
aLB( aOut
.Left(), nBottom
);
7572 SubColFlags nSubColor
= ( bCell
|| IsRowFrame() )
7576 : ( IsInFly() ? SubColFlags::Fly
: SubColFlags::Page
) );
7578 // collect body, header, footer, footnote and section
7579 // sub-lines in <pSpecSubsLine> array.
7580 const bool bSpecialSublines
= IsBodyFrame() || IsHeaderFrame() || IsFooterFrame() ||
7581 IsFootnoteFrame() || IsSctFrame();
7582 SwLineRects
*const pUsedSubsLines
= bSpecialSublines
7583 ? gProp
.pSSpecSubsLines
.get() : gProp
.pSSubsLines
.get();
7585 // NOTE: for cell frames only left and right (horizontal layout) respectively
7586 // top and bottom (vertical layout) lines painted.
7587 // NOTE2: this does not hold for the new table model!!! We paint the top border
7588 // of each non-covered table cell.
7589 const bool bVert
= IsVertical();
7592 // add control for drawing left and right lines
7593 if ( !bCell
|| bNewTableModel
|| !bVert
)
7595 if ( aOriginal
.Left() == aOut
.Left() )
7596 ::lcl_RefreshLine( this, pPage
, aOut
.Pos(), aLB
, nSubColor
, pUsedSubsLines
);
7597 // in vertical layout set page/column break at right
7598 if ( aOriginal
.Right() == nRight
)
7599 ::lcl_RefreshLine( this, pPage
, aRT
, aRB
, nSubColor
, pUsedSubsLines
);
7601 // adjust control for drawing top and bottom lines
7602 if ( !bCell
|| bNewTableModel
|| bVert
)
7604 if ( aOriginal
.Top() == aOut
.Top() )
7605 // in horizontal layout set page/column break at top
7606 ::lcl_RefreshLine( this, pPage
, aOut
.Pos(), aRT
, nSubColor
, pUsedSubsLines
);
7607 if ( aOriginal
.Bottom() == nBottom
)
7608 ::lcl_RefreshLine( this, pPage
, aLB
, aRB
, nSubColor
,
7614 // add control for drawing left and right lines
7615 if ( !bCell
|| bNewTableModel
|| !bVert
)
7617 if ( aOriginal
.Left() == aOut
.Left() )
7619 const SwRect
aRect( aOut
.Pos(), aLB
);
7620 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7621 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7623 // in vertical layout set page/column break at right
7624 if ( aOriginal
.Right() == nRight
)
7626 const SwRect
aRect( aRT
, aRB
);
7627 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7628 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7631 // adjust control for drawing top and bottom lines
7632 if ( !bCell
|| bNewTableModel
|| bVert
)
7634 if ( aOriginal
.Top() == aOut
.Top() )
7636 // in horizontal layout set page/column break at top
7637 const SwRect
aRect( aOut
.Pos(), aRT
);
7638 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7639 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7641 if ( aOriginal
.Bottom() == nBottom
)
7643 const SwRect
aRect( aLB
, aRB
);
7644 pUsedSubsLines
->AddLineRect( aRect
, nullptr,
7645 SvxBorderLineStyle::SOLID
, nullptr, nSubColor
, gProp
);
7652 * Refreshes all extra data (line breaks a.s.o) of the page. Basically only those objects
7653 * are considered which horizontally overlap the Rect.
7655 void SwPageFrame::RefreshExtraData( const SwRect
&rRect
) const
7657 const SwLineNumberInfo
&rInfo
= GetFormat()->GetDoc()->GetLineNumberInfo();
7658 bool bLineInFly
= (rInfo
.IsPaintLineNumbers() && rInfo
.IsCountInFlys())
7659 || static_cast<sal_Int16
>(SwModule::get()->GetRedlineMarkPos()) != text::HoriOrientation::NONE
;
7661 SwRect
aRect( rRect
);
7662 ::SwAlignRect( aRect
, gProp
.pSGlobalShell
, gProp
.pSGlobalShell
->GetOut() );
7663 if ( !aRect
.HasArea() )
7666 SwLayoutFrame::RefreshExtraData( aRect
);
7668 if ( bLineInFly
&& GetSortedObjs() )
7669 for (SwAnchoredObject
* pAnchoredObj
: *GetSortedObjs())
7671 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7673 if ( pFly
->getFrameArea().Top() <= aRect
.Bottom() &&
7674 pFly
->getFrameArea().Bottom() >= aRect
.Top() )
7675 pFly
->RefreshExtraData( aRect
);
7680 void SwLayoutFrame::RefreshExtraData( const SwRect
&rRect
) const
7683 const SwLineNumberInfo
&rInfo
= GetFormat()->GetDoc()->GetLineNumberInfo();
7684 bool bLineInBody
= rInfo
.IsPaintLineNumbers(),
7685 bLineInFly
= bLineInBody
&& rInfo
.IsCountInFlys(),
7686 bRedLine
= static_cast<sal_Int16
>(SwModule::get()->GetRedlineMarkPos())!=text::HoriOrientation::NONE
;
7688 const SwContentFrame
*pCnt
= ContainsContent();
7689 while ( pCnt
&& IsAnLower( pCnt
) )
7691 if ( pCnt
->IsTextFrame() && ( bRedLine
||
7692 ( !pCnt
->IsInTab() &&
7693 ((bLineInBody
&& pCnt
->IsInDocBody()) ||
7694 (bLineInFly
&& pCnt
->IsInFly())) ) ) &&
7695 pCnt
->getFrameArea().Top() <= rRect
.Bottom() &&
7696 pCnt
->getFrameArea().Bottom() >= rRect
.Top() )
7698 static_cast<const SwTextFrame
*>(pCnt
)->PaintExtraData( rRect
);
7700 if ( bLineInFly
&& pCnt
->GetDrawObjs() )
7701 for (SwAnchoredObject
* pAnchoredObj
: *pCnt
->GetDrawObjs())
7703 if ( auto pFly
= pAnchoredObj
->DynCastFlyFrame() )
7705 if ( pFly
->IsFlyInContentFrame() &&
7706 pFly
->getFrameArea().Top() <= rRect
.Bottom() &&
7707 pFly
->getFrameArea().Bottom() >= rRect
.Top() )
7708 pFly
->RefreshExtraData( rRect
);
7711 pCnt
= pCnt
->GetNextContentFrame();
7717 * Determine the color, that is respectively will be drawn as background
7718 * for the page frame.
7719 * Using existing method SwFrame::GetBackgroundBrush to determine the color
7720 * that is set at the page frame respectively is parent. If none is found
7721 * return the global retouche color
7725 Color
SwPageFrame::GetDrawBackgroundColor() const
7727 const SvxBrushItem
* pBrushItem
;
7728 std::optional
<Color
> xDummyColor
;
7730 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes
;
7732 if ( GetBackgroundBrush( aFillAttributes
, pBrushItem
, xDummyColor
, aDummyRect
, true, /*bConsiderTextBox=*/false) )
7734 if(aFillAttributes
&& aFillAttributes
->isUsed())
7736 // let SdrAllFillAttributesHelper do the average color calculation
7737 return Color(aFillAttributes
->getAverageColor(aGlobalRetoucheColor
.getBColor()));
7742 SwViewShell
* sh1
= getRootFrame()->GetCurrShell();
7743 if (sh1
!= nullptr) {
7744 SfxObjectShell
* sh2
= sh1
->GetDoc()->GetPersist();
7745 if (sh2
!= nullptr && sh2
->HasName()) {
7746 referer
= sh2
->GetMedium()->GetName();
7749 const Graphic
* pGraphic
= pBrushItem
->GetGraphic(referer
);
7753 // #29105# when a graphic is set, it may be possible to calculate a single
7754 // color which looks good in all places of the graphic. Since it is
7755 // planned to have text edit on the overlay one day and the fallback
7756 // to aGlobalRetoucheColor returns something useful, just use that
7761 // not a graphic, use (hopefully) initialized color
7762 return pBrushItem
->GetColor();
7767 return aGlobalRetoucheColor
;
7770 /// create/return font used to paint the "empty page" string
7771 const vcl::Font
& SwPageFrame::GetEmptyPageFont()
7773 static vcl::Font aEmptyPgFont
= []()
7776 tmp
.SetFontSize( Size( 0, 80 * 20 )); // == 80 pt
7777 tmp
.SetWeight( WEIGHT_BOLD
);
7778 tmp
.SetStyleName(OUString());
7779 tmp
.SetFamilyName(u
"Noto Sans"_ustr
);
7780 tmp
.SetFamily( FAMILY_SWISS
);
7781 tmp
.SetTransparent( true );
7782 tmp
.SetColor( COL_GRAY
);
7786 return aEmptyPgFont
;
7790 * Retouch for a section
7792 * Retouch will only be done, if the Frame is the last one in his chain.
7793 * The whole area of the upper which is located below the Frame will be
7794 * cleared using PaintSwFrameBackground.
7796 void SwFrame::Retouch( const SwPageFrame
* pPage
, const SwRect
&rRect
) const
7798 if ( gProp
.bSFlyMetafile
)
7801 OSL_ENSURE( GetUpper(), "Retouche try without Upper." );
7802 OSL_ENSURE( getRootFrame()->GetCurrShell() && gProp
.pSGlobalShell
->GetWin(), "Retouche on a printer?" );
7804 SwRect
aRetouche( GetUpper()->GetPaintArea() );
7805 aRetouche
.Top( getFrameArea().Top() + getFrameArea().Height() );
7806 aRetouche
.Intersection( gProp
.pSGlobalShell
->VisArea() );
7808 if ( aRetouche
.HasArea() )
7810 //Omit the passed Rect. To do this, we unfortunately need a region to
7812 SwRegionRects
aRegion( aRetouche
);
7814 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
7816 // #i16816# tagged pdf support
7817 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh
->GetOut() );
7819 for ( size_t i
= 0; i
< aRegion
.size(); ++i
)
7821 const SwRect
&rRetouche
= aRegion
[i
];
7823 GetUpper()->PaintBaBo( rRetouche
, pPage
);
7825 //Hell and Heaven need to be refreshed too.
7826 //To avoid recursion my retouch flag needs to be reset first!
7828 if ( rRetouche
.HasArea() )
7830 const Color
aPageBackgrdColor(pPage
->GetDrawBackgroundColor());
7831 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
7833 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
7836 pSh
->Imp()->PaintLayer( rIDDMA
.GetHellId(), nullptr,
7837 *pPage
, rRetouche
, &aPageBackgrdColor
,
7838 pPage
->IsRightToLeft(),
7840 pSh
->Imp()->PaintLayer( rIDDMA
.GetHeavenId(), nullptr,
7841 *pPage
, rRetouche
, &aPageBackgrdColor
,
7842 pPage
->IsRightToLeft(),
7848 //Because we leave all paint areas, we need to refresh the
7850 pPage
->RefreshSubsidiary( rRetouche
);
7853 if ( SwViewShell::IsLstEndAction() )
7858 * Determine the background brush for the frame:
7859 * the background brush is taken from it-self or from its parent (anchor/upper).
7860 * Normally, the background brush is taken, which has no transparent color or
7861 * which has a background graphic. But there are some special cases:
7862 * (1) No background brush is taken from a page frame, if view option "IsPageBack"
7864 * (2) Background brush from an index section is taken under special conditions.
7865 * In this case parameter <rpCol> is set to the index shading color.
7866 * (3) New (OD 20.08.2002) - Background brush is taken, if on background drawing
7867 * of the frame transparency is considered and its color is not "no fill"/"auto fill"
7869 * Old description in German:
7870 * Returns the Backgroundbrush for the area of the Frame.
7871 * The Brush is defined by the Frame or by an upper, the first Brush is
7872 * used. If no Brush is defined for a Frame, false is returned.
7875 * output parameter - constant reference pointer the found background brush
7877 * @param rpFillStyle
7878 * output parameter - constant reference pointer the found background fill style
7880 * @param rpFillGradient
7881 * output parameter - constant reference pointer the found background fill gradient
7884 * output parameter - constant reference pointer to the color of the index shading
7885 * set under special conditions, if background brush is taken from an index section.
7888 * in-/output parameter - reference to the rectangle the background brush is
7889 * considered for - adjusted to the frame, from which the background brush is
7893 * input parameter - boolean indicating, if background brush should *not* be
7894 * taken from parent.
7896 * @param bConsiderTextBox
7897 * consider the TextBox of this fly frame (if there is any) when determining
7898 * the background color, useful for automatic font color.
7900 * @return true, if a background brush for the frame is found
7902 bool SwFrame::GetBackgroundBrush(
7903 drawinglayer::attribute::SdrAllFillAttributesHelperPtr
& rFillAttributes
,
7904 const SvxBrushItem
* & rpBrush
,
7905 std::optional
<Color
>& rxCol
,
7908 bool bConsiderTextBox
) const
7910 const SwFrame
*pFrame
= this;
7911 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
7912 const SwViewOption
*pOpt
= pSh
->GetViewOptions();
7917 if ( pFrame
->IsPageFrame() && !pOpt
->IsPageBack() )
7920 if (pFrame
->supportsFullDrawingLayerFillAttributeSet())
7922 bool bHandledTextBox
= false;
7923 if (pFrame
->IsFlyFrame() && bConsiderTextBox
)
7925 const SwFlyFrame
* pFlyFrame
= static_cast<const SwFlyFrame
*>(pFrame
);
7926 SwFrameFormat
* pShape
7927 = SwTextBoxHelper::getOtherTextBoxFormat(pFlyFrame
->GetFormat(), RES_FLYFRMFMT
);
7930 SdrObject
* pObject
= pShape
->FindRealSdrObject();
7933 // Work with the fill attributes of the shape of the fly frame.
7935 std::make_shared
<drawinglayer::attribute::SdrAllFillAttributesHelper
>(
7936 pObject
->GetMergedItemSet());
7937 bHandledTextBox
= true;
7942 if (!bHandledTextBox
)
7943 rFillAttributes
= pFrame
->getSdrAllFillAttributesHelper();
7945 const SvxBrushItem
&rBack
= pFrame
->GetAttrSet()->GetBackground();
7947 if( pFrame
->IsSctFrame() )
7949 const SwSection
* pSection
= static_cast<const SwSectionFrame
*>(pFrame
)->GetSection();
7950 // Note: If frame <pFrame> is a section of the index and
7951 // it its background color is "no fill"/"auto fill" and
7952 // it has no background graphic and
7953 // we are not in the page preview and
7954 // we are not in read-only mode and
7955 // option "index shadings" is set and
7956 // the output is not the printer
7957 // then set <rpCol> to the color of the index shading
7958 if( pSection
&& ( SectionType::ToxHeader
== pSection
->GetType() ||
7959 SectionType::ToxContent
== pSection
->GetType() ) &&
7960 (rBack
.GetColor() == COL_TRANSPARENT
) &&
7961 rBack
.GetGraphicPos() == GPOS_NONE
&&
7962 !pOpt
->IsPagePreview() &&
7963 !pOpt
->IsReadonly() &&
7964 // #114856# Form view
7965 !pOpt
->IsFormView() &&
7966 pOpt
->IsIndexShadings() &&
7967 !pOpt
->IsPDFExport() &&
7968 pSh
->GetOut()->GetOutDevType() != OUTDEV_PRINTER
)
7970 rxCol
= pOpt
->GetIndexShadingsColor();
7974 // determine, if background draw of frame <pFrame> considers transparency
7975 // Status Quo: background transparency have to be
7976 // considered for fly frames
7977 const bool bConsiderBackgroundTransparency
= pFrame
->IsFlyFrame();
7979 // #i125189# Do not base the decision for using the parent's fill style for this
7980 // frame when the new DrawingLayer FillAttributes are used on the SdrAllFillAttributesHelper
7981 // information. There the data is already optimized to no fill in the case that the
7982 // transparence is at 100% while no fill is the criteria for derivation
7983 bool bNewDrawingLayerFillStyleIsUsedAndNotNoFill(false);
7987 // the new DrawingLayer FillStyle is used
7988 if(rFillAttributes
->isUsed())
7990 // it's not drawing::FillStyle_NONE
7991 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
= true;
7995 // maybe optimized already when 100% transparency is used somewhere, need to test
7996 // XFillStyleItem directly from the model data
7997 const drawing::FillStyle
eFillStyle(pFrame
->GetAttrSet()->Get(XATTR_FILLSTYLE
).GetValue());
7999 if(drawing::FillStyle_NONE
!= eFillStyle
)
8001 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
= true;
8007 // If <bConsiderBackgroundTransparency> is set - see above -,
8008 // return brush of frame <pFrame>, if its color is *not* "no fill"/"auto fill"
8010 // #i125189# Done when the new DrawingLayer FillAttributes are used and
8011 // not drawing::FillStyle_NONE (see above)
8012 bNewDrawingLayerFillStyleIsUsedAndNotNoFill
||
8014 // done when SvxBrushItem is used
8015 rBack
.GetColor().GetAlpha() == 255 || rBack
.GetGraphicPos() != GPOS_NONE
||
8017 // done when direct color is forced
8020 // done when consider BG transparency and color is not completely transparent
8021 (bConsiderBackgroundTransparency
&& (rBack
.GetColor() != COL_TRANSPARENT
))
8025 if ( pFrame
->IsPageFrame() && pSh
->GetViewOptions()->getBrowseMode() )
8027 rOrigRect
= pFrame
->getFrameArea();
8028 ::SwAlignRect(rOrigRect
, pSh
, pSh
->GetOut());
8032 if (pFrame
->IsPageFrame()
8033 && pFrame
->GetAttrSet()->GetItem
<SfxBoolItem
>(RES_BACKGROUND_FULL_SIZE
)->GetValue())
8035 rOrigRect
= pFrame
->getFrameArea();
8037 else if (pFrame
->getFrameArea().SSize() != pFrame
->getFramePrintArea().SSize())
8039 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFrame
);
8040 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
8041 ::lcl_CalcBorderRect( rOrigRect
, pFrame
, rAttrs
, false, gProp
);
8045 rOrigRect
= pFrame
->getFramePrintArea();
8046 rOrigRect
+= pFrame
->getFrameArea().Pos();
8055 // Do not try to get background brush from parent (anchor/upper)
8059 // get parent frame - anchor or upper - for next loop
8060 if ( pFrame
->IsFlyFrame() )
8062 pFrame
= static_cast<const SwFlyFrame
*>(pFrame
)->GetAnchorFrame();
8066 pFrame
= pFrame
->GetUpper();
8073 void SetOutDevAndWin( SwViewShell
*pSh
, OutputDevice
*pO
,
8074 vcl::Window
*pW
, sal_uInt16 nZoom
)
8078 pSh
->mpOpt
->SetZoom( nZoom
);
8081 Graphic
SwFrameFormat::MakeGraphic( ImageMap
*, const sal_uInt32
/*nMaximumQuadraticPixels*/, const std::optional
<Size
>& /*rTargetDPI*/ )
8086 Graphic
SwFlyFrameFormat::MakeGraphic( ImageMap
* pMap
, const sal_uInt32
/*nMaximumQuadraticPixels*/, const std::optional
<Size
>& /*rTargetDPI*/ )
8090 SwIterator
<SwFrame
,SwFormat
> aIter( *this );
8091 SwFrame
*pFirst
= aIter
.First();
8092 SwViewShell
*const pSh
=
8093 pFirst
? pFirst
->getRootFrame()->GetCurrShell() : nullptr;
8096 SwViewShell
*pOldGlobal
= gProp
.pSGlobalShell
;
8097 gProp
.pSGlobalShell
= pSh
;
8099 bool bNoteURL
= pMap
&&
8100 SfxItemState::SET
!= GetAttrSet().GetItemState( RES_URL
);
8104 pNoteURL
= new SwNoteURL
;
8106 SwFlyFrame
*pFly
= static_cast<SwFlyFrame
*>(pFirst
);
8108 OutputDevice
*pOld
= pSh
->GetOut();
8109 ScopedVclPtrInstance
< VirtualDevice
> pDev( *pOld
);
8110 pDev
->EnableOutput( false );
8113 MapMode
aMap( pOld
->GetMapMode().GetMapUnit() );
8114 pDev
->SetMapMode( aMap
);
8115 aMet
.SetPrefMapMode( aMap
);
8117 ::SwCalcPixStatics( pSh
->GetOut() );
8118 aMet
.SetPrefSize( pFly
->getFrameArea().SSize() );
8120 aMet
.Record( pDev
.get() );
8121 pDev
->SetLineColor();
8122 pDev
->SetFillColor();
8123 pDev
->SetFont( pOld
->GetFont() );
8125 //Enlarge the rectangle if needed, so the border is painted too.
8126 SwRect
aOut( pFly
->getFrameArea() );
8127 SwBorderAttrAccess
aAccess( SwFrame::GetCache(), pFly
);
8128 const SwBorderAttrs
&rAttrs
= *aAccess
.Get();
8129 if ( rAttrs
.CalcRightLine() )
8130 aOut
.AddWidth(2*gProp
.nSPixelSzW
);
8131 if ( rAttrs
.CalcBottomLine() )
8132 aOut
.AddHeight(2*gProp
.nSPixelSzH
);
8134 // #i92711# start Pre/PostPaint encapsulation before pOut is changed to the buffering VDev
8135 const vcl::Region
aRepaintRegion(aOut
.SVRect());
8136 pSh
->DLPrePaint2(aRepaintRegion
);
8138 vcl::Window
*pWin
= pSh
->GetWin();
8139 sal_uInt16 nZoom
= pSh
->GetViewOptions()->GetZoom();
8140 ::SetOutDevAndWin( pSh
, pDev
, nullptr, 100 );
8141 gProp
.bSFlyMetafile
= true;
8142 gProp
.pSFlyMetafileOut
= pWin
->GetOutDev();
8144 SwViewShellImp
*pImp
= pSh
->Imp();
8145 gProp
.pSFlyOnlyDraw
= pFly
;
8146 gProp
.pSLines
.reset(new SwLineRects
);
8148 // determine page, fly frame is on
8149 const SwPageFrame
* pFlyPage
= pFly
->FindPageFrame();
8150 const Color
aPageBackgrdColor(pFlyPage
->GetDrawBackgroundColor());
8151 const IDocumentDrawModelAccess
& rIDDMA
= pSh
->getIDocumentDrawModelAccess();
8153 SwViewObjectContactRedirector
aSwRedirector( *pSh
);
8155 pImp
->PaintLayer( rIDDMA
.GetHellId(), nullptr,
8156 *pFlyPage
, aOut
, &aPageBackgrdColor
,
8157 pFlyPage
->IsRightToLeft(),
8159 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8160 if ( pFly
->IsFlyInContentFrame() )
8161 pFly
->PaintSwFrame( *pDev
, aOut
);
8162 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8163 pImp
->PaintLayer( rIDDMA
.GetHeavenId(), nullptr,
8164 *pFlyPage
, aOut
, &aPageBackgrdColor
,
8165 pFlyPage
->IsRightToLeft(),
8167 gProp
.pSLines
->PaintLines( pDev
, gProp
);
8168 gProp
.pSLines
.reset();
8169 gProp
.pSFlyOnlyDraw
= nullptr;
8171 gProp
.pSFlyMetafileOut
= nullptr;
8172 gProp
.bSFlyMetafile
= false;
8173 ::SetOutDevAndWin( pSh
, pOld
, pWin
, nZoom
);
8175 // #i92711# end Pre/PostPaint encapsulation when pOut is back and content is painted
8176 pSh
->DLPostPaint2(true);
8179 aMet
.Move( -pFly
->getFrameArea().Left(), -pFly
->getFrameArea().Top() );
8180 aRet
= Graphic( aMet
);
8185 pNoteURL
->FillImageMap(pMap
, pFly
->getFrameArea().Pos(), aMap
);
8189 gProp
.pSGlobalShell
= pOldGlobal
;
8194 Graphic
SwDrawFrameFormat::MakeGraphic( ImageMap
*, const sal_uInt32 nMaximumQuadraticPixels
, const std::optional
<Size
>& rTargetDPI
)
8197 SwDrawModel
* pMod
= getIDocumentDrawModelAccess().GetDrawModel();
8200 SdrObject
*pObj
= FindSdrObject();
8201 SdrView
aView( *pMod
);
8202 SdrPageView
*pPgView
= aView
.ShowSdrPage(aView
.GetModel().GetPage(0));
8203 aView
.MarkObj( pObj
, pPgView
);
8204 aRet
= aView
.GetMarkedObjBitmapEx(/*bNoVDevIfOneBmpMarked=*/false, nMaximumQuadraticPixels
, rTargetDPI
);
8205 aView
.HideSdrPage();
8210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */