LibreOffice Module sw (master)  1
paintfrm.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <vcl/lazydelete.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <sfx2/progress.hxx>
23 #include <editeng/brushitem.hxx>
24 #include <editeng/prntitem.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/shaditem.hxx>
27 #include <svx/framelink.hxx>
28 #include <drawdoc.hxx>
29 #include <tgrditem.hxx>
30 #include <calbck.hxx>
31 #include <fmtsrnd.hxx>
32 #include <fmtclds.hxx>
33 #include <strings.hrc>
34 #include <swmodule.hxx>
35 #include <rootfrm.hxx>
36 #include <pagefrm.hxx>
37 #include <section.hxx>
38 #include <sectfrm.hxx>
39 #include <viewimp.hxx>
40 #include <dflyobj.hxx>
41 #include <flyfrm.hxx>
42 #include <frmatr.hxx>
43 #include <frmtool.hxx>
44 #include <viewopt.hxx>
45 #include <dview.hxx>
46 #include <dcontact.hxx>
47 #include <txtfrm.hxx>
48 #include <ftnfrm.hxx>
49 #include <tabfrm.hxx>
50 #include <rowfrm.hxx>
51 #include <cellfrm.hxx>
52 #include <notxtfrm.hxx>
53 #include <layact.hxx>
54 #include <pagedesc.hxx>
55 #include <ptqueue.hxx>
56 #include <noteurl.hxx>
57 #include "virtoutp.hxx"
58 #include <lineinfo.hxx>
59 #include <dbg_lay.hxx>
60 #include <docsh.hxx>
61 #include <svx/svdogrp.hxx>
62 #include <sortedobjs.hxx>
64 #include <bodyfrm.hxx>
65 #include <hffrm.hxx>
66 #include <colfrm.hxx>
67 #include <sw_primitivetypes2d.hxx>
68 #include <swfont.hxx>
69 
77 
78 #include <ndole.hxx>
79 #include <PostItMgr.hxx>
80 #include <FrameControlsManager.hxx>
81 #include <vcl/settings.hxx>
82 
85 
86 #include <svtools/borderhelper.hxx>
87 
88 #include <bitmaps.hlst>
98 #include <svx/unoapi.hxx>
99 #include <svx/svdpagv.hxx>
100 #include <svx/xfillit0.hxx>
104 #include <sal/log.hxx>
105 
106 #include <memory>
107 #include <vector>
108 #include <algorithm>
109 #include <wrtsh.hxx>
110 #include <edtwin.hxx>
111 #include <view.hxx>
112 #include <paintfrm.hxx>
113 #include <textboxhelper.hxx>
114 #include <o3tl/typed_flags_set.hxx>
115 
116 #include <vcl/BitmapTools.hxx>
117 #include <comphelper/lok.hxx>
118 
119 #define COL_NOTES_SIDEPANE Color(230,230,230)
120 #define COL_NOTES_SIDEPANE_BORDER Color(200,200,200)
121 #define COL_NOTES_SIDEPANE_SCROLLAREA Color(230,230,220)
122 
123 using namespace ::editeng;
124 using namespace ::com::sun::star;
125 using ::drawinglayer::primitive2d::BorderLinePrimitive2D;
126 using ::drawinglayer::primitive2d::BorderLine;
127 using std::pair;
128 using std::make_pair;
129 
130 struct SwPaintProperties;
131 
132 namespace {
133 
134 //Class declaration; here because they are only used in this file
135 enum class SubColFlags {
136  Page = 0x01, //Helplines of the page
137  Tab = 0x08, //Helplines inside tables
138  Fly = 0x10, //Helplines inside fly frames
139  Sect = 0x20, //Helplines inside sections
140 };
141 
142 }
143 
144 namespace o3tl {
145  template<> struct typed_flags<SubColFlags> : is_typed_flags<SubColFlags, 0x39> {};
146 }
147 
148 // Classes collecting the border lines and help lines
149 class SwLineRect : public SwRect
150 {
153  const SwTabFrame *pTab;
154  SubColFlags nSubColor; //colorize subsidiary lines
155  bool bPainted; //already painted?
156  sal_uInt8 nLock; //To distinguish the line and the hell layer.
157 public:
158  SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
159  const SwTabFrame *pT , const SubColFlags nSCol );
160 
161  const Color& GetColor() const { return aColor;}
162  SvxBorderLineStyle GetStyle() const { return nStyle; }
163  const SwTabFrame *GetTab() const { return pTab; }
164  void SetPainted() { bPainted = true; }
165  void Lock( bool bLock ) { if ( bLock )
166  ++nLock;
167  else if ( nLock )
168  --nLock;
169  }
170  bool IsPainted() const { return bPainted; }
171  bool IsLocked() const { return nLock != 0; }
172  SubColFlags GetSubColor() const { return nSubColor;}
173 
174  bool MakeUnion( const SwRect &rRect, SwPaintProperties const &properties );
175 };
176 
177 #ifdef IOS
178 static void dummy_function()
179 {
180  pid_t pid = getpid();
181  (void) pid;
182 }
183 #endif
184 
186 {
187 public:
188  std::vector< SwLineRect > aLineRects;
189  typedef std::vector< SwLineRect >::const_iterator const_iterator;
190  typedef std::vector< SwLineRect >::iterator iterator;
191  typedef std::vector< SwLineRect >::reverse_iterator reverse_iterator;
192  typedef std::vector< SwLineRect >::size_type size_type;
193  size_t nLastCount; //avoid unnecessary cycles in PaintLines
194  SwLineRects() : nLastCount( 0 )
195  {
196 #ifdef IOS
197  // Work around what is either a compiler bug in Xcode 5.1.1,
198  // or some unknown problem in this file. If I ifdef out this
199  // call, I get a crash in SwSubsRects::PaintSubsidiary: the
200  // address of the rLi reference variable is claimed to be
201  // 0x4000000!
202  dummy_function();
203 #endif
204  }
205  void AddLineRect( const SwRect& rRect, const Color *pColor, const SvxBorderLineStyle nStyle,
206  const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const &properties );
207  void ConnectEdges( OutputDevice const *pOut, SwPaintProperties const &properties );
208  void PaintLines ( OutputDevice *pOut, SwPaintProperties const &properties );
209  void LockLines( bool bLock );
210 
211  //Limit lines to 100
212  bool isFull() const { return aLineRects.size()>100; }
213 };
214 
215 class SwSubsRects : public SwLineRects
216 {
217  void RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const &properties );
218 public:
219  void PaintSubsidiary( OutputDevice *pOut, const SwLineRects *pRects, SwPaintProperties const &properties );
220 };
221 
223 {
225 public:
228  {
230  lines.swap(m_Lines);
231  return lines;
232  }
233 };
234 
235 // Default zoom factor
236 const static double aEdgeScale = 0.5;
237 
238 //To optimize the expensive RetouchColor determination
240 
241 namespace sw
242 {
244 {
245  return &aGlobalRetoucheColor;
246 }
247 }
248 
253  // Only repaint the Fly content as well as the background of the Fly content if
254  // a metafile is taken of the Fly.
258 
259  // Retouch for transparent Flys is done by the background of the Flys.
260  // The Fly itself should certainly not be spared out. See PaintSwFrameBackground and
261  // lcl_SubtractFlys()
265 
266  // The borders will be collected in pSLines during the Paint and later
267  // possibly merge them.
268  // The help lines will be collected and merged in gProp.pSSubsLines. These will
269  // be compared with pSLines before the work in order to avoid help lines
270  // to hide borders.
271  std::unique_ptr<BorderLines> pBLines;
272  std::unique_ptr<SwLineRects> pSLines;
273  std::unique_ptr<SwSubsRects> pSSubsLines;
274 
275  // global variable for sub-lines of body, header, footer, section and footnote frames.
276  std::unique_ptr<SwSubsRects> pSSpecSubsLines;
278 
279  // Sizes of a pixel and the corresponding halves. Will be reset when
280  // entering SwRootFrame::PaintSwFrame
287 
289 
290  // Current zoom factor
291  double aSScaleX;
292  double aSScaleY;
293 
295  : bSFlyMetafile(false)
296  , pSFlyMetafileOut(nullptr)
297  , pSGlobalShell(nullptr)
298  , pSRetoucheFly(nullptr)
299  , pSRetoucheFly2(nullptr)
300  , pSFlyOnlyDraw(nullptr)
301  , pSProgress(nullptr)
302  , nSPixelSzW(0)
303  , nSPixelSzH(0)
304  , nSHalfPixelSzW(0)
305  , nSHalfPixelSzH(0)
306  , nSMinDistPixelW(0)
307  , nSMinDistPixelH(0)
308  , aSScaleX(1)
309  , aSScaleY(1)
310  {
311  }
312 
313 };
314 
316 
318 {
319  return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
320  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
321  !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
323 }
324 //other subsidiary lines enabled?
326 {
327  return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
328  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
329  !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
332 }
333 //subsidiary lines for sections
335 {
336  return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
337  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
338  !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
340 }
341 
342 
343 namespace {
344 
345 bool isTableBoundariesEnabled()
346 {
347  if (!gProp.pSGlobalShell->GetViewOptions()->IsTable())
348  return false;
349 
351  return false;
352 
353  if (gProp.pSGlobalShell->GetViewOptions()->IsReadonly())
354  return false;
355 
356  if (gProp.pSGlobalShell->GetViewOptions()->IsFormView())
357  return false;
358 
360 }
361 
362 }
363 
371 {
372  // determine 'small' twip-to-pixel relation
373  bool bSmallTwipToPxRelW = false;
374  bool bSmallTwipToPxRelH = false;
375  {
376  Size aCheckTwipToPxRelSz( pOut->PixelToLogic( Size( 100, 100 )) );
377  if ( (aCheckTwipToPxRelSz.Width()/100.0) < 2.0 )
378  {
379  bSmallTwipToPxRelW = true;
380  }
381  if ( (aCheckTwipToPxRelSz.Height()/100.0) < 2.0 )
382  {
383  bSmallTwipToPxRelH = true;
384  }
385  }
386 
387  Size aSz( pOut->PixelToLogic( Size( 1,1 )) );
388 
389  gProp.nSPixelSzW = aSz.Width();
390  if( !gProp.nSPixelSzW )
391  gProp.nSPixelSzW = 1;
392  gProp.nSPixelSzH = aSz.Height();
393  if( !gProp.nSPixelSzH )
394  gProp.nSPixelSzH = 1;
395 
396  // consider 'small' twip-to-pixel relations
397  if ( !bSmallTwipToPxRelW )
398  {
399  gProp.nSHalfPixelSzW = gProp.nSPixelSzW / 2 + 1;
400  }
401  else
402  {
403  gProp.nSHalfPixelSzW = 0;
404  }
405  // consider 'small' twip-to-pixel relations
406  if ( !bSmallTwipToPxRelH )
407  {
408  gProp.nSHalfPixelSzH = gProp.nSPixelSzH / 2 + 1;
409  }
410  else
411  {
412  gProp.nSHalfPixelSzH = 0;
413  }
414 
415  gProp.nSMinDistPixelW = gProp.nSPixelSzW * 2 + 1;
416  gProp.nSMinDistPixelH = gProp.nSPixelSzH * 2 + 1;
417 
418  const MapMode &rMap = pOut->GetMapMode();
419  gProp.aSScaleX = double(rMap.GetScaleX());
420  gProp.aSScaleY = double(rMap.GetScaleY());
421 }
422 
427 {
428 public:
431 };
432 
434 {
435  // Saving globales
442  pBLines = std::move(gProp.pBLines);
443  pSLines = std::move(gProp.pSLines);
444  pSSubsLines = std::move(gProp.pSSubsLines);
445  pSSpecSubsLines = std::move(gProp.pSSpecSubsLines);
446  pSProgress = gProp.pSProgress;
447  nSPixelSzW = gProp.nSPixelSzW;
448  nSPixelSzH = gProp.nSPixelSzH;
454  aSScaleX = gProp.aSScaleX;
455  aSScaleY = gProp.aSScaleY;
456 
457  // Restoring globales to default
458  gProp.bSFlyMetafile = false;
459  gProp.pSFlyMetafileOut = nullptr;
460  gProp.pSRetoucheFly = nullptr;
461  gProp.pSRetoucheFly2 = nullptr;
462  gProp.nSPixelSzW = gProp.nSPixelSzH =
463  gProp.nSHalfPixelSzW = gProp.nSHalfPixelSzH =
464  gProp.nSMinDistPixelW = gProp.nSMinDistPixelH = 0;
465  gProp.aSScaleX = gProp.aSScaleY = 1.0;
466  gProp.pSProgress = nullptr;
467 }
468 
470 {
471  // Restoring globales to saved one
478  gProp.pBLines = std::move(pBLines);
479  gProp.pSLines = std::move(pSLines);
480  gProp.pSSubsLines = std::move(pSSubsLines);
481  gProp.pSSpecSubsLines = std::move(pSSpecSubsLines);
482  gProp.pSProgress = pSProgress;
483  gProp.nSPixelSzW = nSPixelSzW;
484  gProp.nSPixelSzH = nSPixelSzH;
489  aGlobalRetoucheColor = aSGlobalRetoucheColor;
490  gProp.aSScaleX = aSScaleX;
491  gProp.aSScaleY = aSScaleY;
492 }
493 
495 {
496  if(!rContainer.empty())
497  {
498  m_Lines.append(rContainer);
499  }
500 }
501 
502 SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
503  const SwTabFrame *pT, const SubColFlags nSCol ) :
504  SwRect( rRect ),
505  nStyle( nStyl ),
506  pTab( pT ),
507  nSubColor( nSCol ),
508  bPainted( false ),
509  nLock( 0 )
510 {
511  if ( pCol != nullptr )
512  aColor = *pCol;
513 }
514 
515 bool SwLineRect::MakeUnion( const SwRect &rRect, SwPaintProperties const & properties)
516 {
517  // It has already been tested outside, whether the rectangles have
518  // the same orientation (horizontal or vertical), color, etc.
519  if ( Height() > Width() ) //Vertical line
520  {
521  if ( Left() == rRect.Left() && Width() == rRect.Width() )
522  {
523  // Merge when there is no gap between the lines
524  const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
525  if ( Bottom() + nAdd >= rRect.Top() &&
526  Top() - nAdd <= rRect.Bottom() )
527  {
528  Bottom( std::max( Bottom(), rRect.Bottom() ) );
529  Top ( std::min( Top(), rRect.Top() ) );
530  return true;
531  }
532  }
533  }
534  else
535  {
536  if ( Top() == rRect.Top() && Height() == rRect.Height() )
537  {
538  // Merge when there is no gap between the lines
539  const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
540  if ( Right() + nAdd >= rRect.Left() &&
541  Left() - nAdd <= rRect.Right() )
542  {
543  Right( std::max( Right(), rRect.Right() ) );
544  Left ( std::min( Left(), rRect.Left() ) );
545  return true;
546  }
547  }
548  }
549  return false;
550 }
551 
552 void SwLineRects::AddLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
553  const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const & properties )
554 {
555  // Loop backwards because lines which can be combined, can usually be painted
556  // in the same context
557  for (reverse_iterator it = aLineRects.rbegin(); it != aLineRects.rend();
558  ++it)
559  {
560  SwLineRect &rLRect = *it;
561  // Test for the orientation, color, table
562  if ( rLRect.GetTab() == pTab &&
563  !rLRect.IsPainted() && rLRect.GetSubColor() == nSCol &&
564  (rLRect.Height() > rLRect.Width()) == (rRect.Height() > rRect.Width()) &&
565  (pCol && rLRect.GetColor() == *pCol) )
566  {
567  if ( rLRect.MakeUnion( rRect, properties ) )
568  return;
569  }
570  }
571  aLineRects.emplace_back( rRect, pCol, nStyle, pTab, nSCol );
572 }
573 
574 void SwLineRects::ConnectEdges( OutputDevice const *pOut, SwPaintProperties const & properties )
575 {
576  if ( pOut->GetOutDevType() != OUTDEV_PRINTER )
577  {
578  // I'm not doing anything for a too small zoom
579  if ( properties.aSScaleX < aEdgeScale || properties.aSScaleY < aEdgeScale )
580  return;
581  }
582 
583  static const long nAdd = 20;
584 
585  std::vector<SwLineRect*> aCheck;
586 
587  for (size_t i = 0; i < aLineRects.size(); ++i)
588  {
589  SwLineRect &rL1 = aLineRects[i];
590  if ( !rL1.GetTab() || rL1.IsPainted() || rL1.IsLocked() )
591  continue;
592 
593  aCheck.clear();
594 
595  const bool bVert = rL1.Height() > rL1.Width();
596  long nL1a, nL1b, nL1c, nL1d;
597 
598  if ( bVert )
599  {
600  nL1a = rL1.Top(); nL1b = rL1.Left();
601  nL1c = rL1.Right(); nL1d = rL1.Bottom();
602  }
603  else
604  {
605  nL1a = rL1.Left(); nL1b = rL1.Top();
606  nL1c = rL1.Bottom(); nL1d = rL1.Right();
607  }
608 
609  // Collect all lines to possibly link with i1
610  for (iterator it2 = aLineRects.begin(); it2 != aLineRects.end(); ++it2)
611  {
612  SwLineRect &rL2 = *it2;
613  if ( rL2.GetTab() != rL1.GetTab() ||
614  rL2.IsPainted() ||
615  rL2.IsLocked() ||
616  (bVert == (rL2.Height() > rL2.Width())) )
617  continue;
618 
619  long nL2a, nL2b, nL2c, nL2d;
620  if ( bVert )
621  {
622  nL2a = rL2.Top(); nL2b = rL2.Left();
623  nL2c = rL2.Right(); nL2d = rL2.Bottom();
624  }
625  else
626  {
627  nL2a = rL2.Left(); nL2b = rL2.Top();
628  nL2c = rL2.Bottom(); nL2d = rL2.Right();
629  }
630 
631  if ( (nL1a - nAdd < nL2d && nL1d + nAdd > nL2a) &&
632  ((nL1b > nL2b && nL1c < nL2c) ||
633  (nL1c >= nL2c && nL1b - nAdd < nL2c) ||
634  (nL1b <= nL2b && nL1c + nAdd > nL2b)) )
635  {
636  aCheck.push_back( &rL2 );
637  }
638  }
639  if ( aCheck.size() < 2 )
640  continue;
641 
642  bool bRemove = false;
643 
644  // For each line test all following ones.
645  for ( size_t k = 0; !bRemove && k < aCheck.size(); ++k )
646  {
647  SwLineRect &rR1 = *aCheck[k];
648 
649  for ( size_t k2 = k+1; !bRemove && k2 < aCheck.size(); ++k2 )
650  {
651  SwLineRect &rR2 = *aCheck[k2];
652  if ( bVert )
653  {
654  SwLineRect *pLA = nullptr;
655  SwLineRect *pLB = nullptr;
656  if ( rR1.Top() < rR2.Top() )
657  {
658  pLA = &rR1; pLB = &rR2;
659  }
660  else if ( rR1.Top() > rR2.Top() )
661  {
662  pLA = &rR2; pLB = &rR1;
663  }
664  // are k1 and k2 describing a double line?
665  if ( pLA && pLA->Bottom() + 60 > pLB->Top() )
666  {
667  if ( rL1.Top() < pLA->Top() )
668  {
669  if ( rL1.Bottom() == pLA->Bottom() )
670  continue; //Small mistake (where?)
671 
672  SwRect aIns( rL1 );
673  aIns.Bottom( pLA->Bottom() );
674  if ( !rL1.IsInside( aIns ) )
675  continue;
676  aLineRects.emplace_back( aIns, &rL1.GetColor(),
677  SvxBorderLineStyle::SOLID,
678  rL1.GetTab(), SubColFlags::Tab );
679  if ( isFull() )
680  {
681  --i;
682  k = aCheck.size();
683  break;
684  }
685  }
686 
687  if ( rL1.Bottom() > pLB->Bottom() )
688  rL1.Top( pLB->Top() ); // extend i1 on the top
689  else
690  bRemove = true; //stopping, remove i1
691  }
692  }
693  else
694  {
695  SwLineRect *pLA = nullptr;
696  SwLineRect *pLB = nullptr;
697  if ( rR1.Left() < rR2.Left() )
698  {
699  pLA = &rR1; pLB = &rR2;
700  }
701  else if ( rR1.Left() > rR2.Left() )
702  {
703  pLA = &rR2; pLB = &rR1;
704  }
705  // Is it double line?
706  if ( pLA && pLA->Right() + 60 > pLB->Left() )
707  {
708  if ( rL1.Left() < pLA->Left() )
709  {
710  if ( rL1.Right() == pLA->Right() )
711  continue; //small error
712 
713  SwRect aIns( rL1 );
714  aIns.Right( pLA->Right() );
715  if ( !rL1.IsInside( aIns ) )
716  continue;
717  aLineRects.emplace_back( aIns, &rL1.GetColor(),
718  SvxBorderLineStyle::SOLID,
719  rL1.GetTab(), SubColFlags::Tab );
720  if ( isFull() )
721  {
722  --i;
723  k = aCheck.size();
724  break;
725  }
726  }
727  if ( rL1.Right() > pLB->Right() )
728  rL1.Left( pLB->Left() );
729  else
730  bRemove = true;
731  }
732  }
733  }
734  }
735  if ( bRemove )
736  {
737  aLineRects.erase(aLineRects.begin() + i);
738  --i;
739  }
740  }
741 }
742 
744 {
745  // All help lines that are covered by any border will be removed or split
746  for (size_t i = 0; i < aLineRects.size(); ++i)
747  {
748  // get a copy instead of a reference, because an <insert> may destroy
749  // the object due to a necessary array resize.
750  const SwLineRect aSubsLineRect(aLineRects[i]);
751 
752  // add condition <aSubsLineRect.IsLocked()> in order to consider only
753  // border lines, which are *not* locked.
754  if ( aSubsLineRect.IsPainted() ||
755  aSubsLineRect.IsLocked() )
756  continue;
757 
758  const bool bVerticalSubs = aSubsLineRect.Height() > aSubsLineRect.Width();
759  SwRect aSubsRect( aSubsLineRect );
760  if ( bVerticalSubs )
761  {
762  aSubsRect.Left ( aSubsRect.Left() - (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
763  aSubsRect.Right ( aSubsRect.Right() + (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
764  }
765  else
766  {
767  aSubsRect.Top ( aSubsRect.Top() - (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
768  aSubsRect.Bottom( aSubsRect.Bottom() + (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
769  }
770  for (const_iterator itK = rRects.aLineRects.begin(); itK != rRects.aLineRects.end(); ++itK)
771  {
772  const SwLineRect &rLine = *itK;
773 
774  // do *not* consider painted or locked border lines.
775  // #i1837# - locked border lines have to be considered.
776  if ( rLine.IsLocked () )
777  continue;
778 
779  if ( !bVerticalSubs == ( rLine.Height() > rLine.Width() ) ) //same direction?
780  continue;
781 
782  if ( aSubsRect.IsOver( rLine ) )
783  {
784  if ( bVerticalSubs ) // Vertical?
785  {
786  if ( aSubsRect.Left() <= rLine.Right() &&
787  aSubsRect.Right() >= rLine.Left() )
788  {
789  long nTmp = rLine.Top()-(properties.nSPixelSzH+1);
790  if ( aSubsLineRect.Top() < nTmp )
791  {
792  SwRect aNewSubsRect( aSubsLineRect );
793  aNewSubsRect.Bottom( nTmp );
794  aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
795  aSubsLineRect.GetSubColor() );
796  }
797  nTmp = rLine.Bottom()+properties.nSPixelSzH+1;
798  if ( aSubsLineRect.Bottom() > nTmp )
799  {
800  SwRect aNewSubsRect( aSubsLineRect );
801  aNewSubsRect.Top( nTmp );
802  aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
803  aSubsLineRect.GetSubColor() );
804  }
805  aLineRects.erase(aLineRects.begin() + i);
806  --i;
807  break;
808  }
809  }
810  else // Horizontal
811  {
812  if ( aSubsRect.Top() <= rLine.Bottom() &&
813  aSubsRect.Bottom() >= rLine.Top() )
814  {
815  long nTmp = rLine.Left()-(properties.nSPixelSzW+1);
816  if ( aSubsLineRect.Left() < nTmp )
817  {
818  SwRect aNewSubsRect( aSubsLineRect );
819  aNewSubsRect.Right( nTmp );
820  aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
821  aSubsLineRect.GetSubColor() );
822  }
823  nTmp = rLine.Right()+properties.nSPixelSzW+1;
824  if ( aSubsLineRect.Right() > nTmp )
825  {
826  SwRect aNewSubsRect( aSubsLineRect );
827  aNewSubsRect.Left( nTmp );
828  aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
829  aSubsLineRect.GetSubColor() );
830  }
831  aLineRects.erase(aLineRects.begin() + i);
832  --i;
833  break;
834  }
835  }
836  }
837  }
838  }
839 }
840 
841 void SwLineRects::LockLines( bool bLock )
842 {
843  for (iterator it = aLineRects.begin(); it != aLineRects.end(); ++it)
844  (*it).Lock( bLock );
845 }
846 
847 static void lcl_DrawDashedRect( OutputDevice * pOut, SwLineRect const & rLRect )
848 {
849  long startX = rLRect.Left( ), endX;
850  long startY = rLRect.Top( ), endY;
851 
852  // Discriminate vertically stretched rect from horizontally stretched
853  // and restrict minimum nHalfLWidth to 1
854  long nHalfLWidth = std::max( static_cast<long>(std::min( rLRect.Width( ), rLRect.Height( ) ) / 2), 1L );
855 
856  if ( rLRect.Height( ) > rLRect.Width( ) )
857  {
858  startX += nHalfLWidth;
859  endX = startX;
860  endY = startY + rLRect.Height( );
861  }
862  else
863  {
864  startY += nHalfLWidth;
865  endY = startY;
866  endX = startX + rLRect.Width( );
867  }
868 
869  svtools::DrawLine( *pOut, Point( startX, startY ), Point( endX, endY ),
870  sal_uInt32( nHalfLWidth * 2 ), rLRect.GetStyle( ) );
871 }
872 
874 {
875  // Paint the borders. Sadly two passes are needed.
876  // Once for the inside and once for the outside edges of tables
877  if ( aLineRects.size() == nLastCount )
878  return;
879 
880  // #i16816# tagged pdf support
881  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
882 
883  pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
884  pOut->SetFillColor();
885  pOut->SetLineColor();
886  ConnectEdges( pOut, properties );
887  const Color *pLast = nullptr;
888 
889  bool bPaint2nd = false;
890  size_t nMinCount = aLineRects.size();
891 
892  for ( size_t i = 0; i < aLineRects.size(); ++i )
893  {
894  SwLineRect &rLRect = aLineRects[i];
895 
896  if ( rLRect.IsPainted() )
897  continue;
898 
899  if ( rLRect.IsLocked() )
900  {
901  nMinCount = std::min( nMinCount, i );
902  continue;
903  }
904 
905  // Paint it now or in the second pass?
906  bool bPaint = true;
907  if ( rLRect.GetTab() )
908  {
909  if ( rLRect.Height() > rLRect.Width() )
910  {
911  // Vertical edge, overlapping with the table edge?
912  SwTwips nLLeft = rLRect.Left() - 30,
913  nLRight = rLRect.Right() + 30,
914  nTLeft = rLRect.GetTab()->getFrameArea().Left() + rLRect.GetTab()->getFramePrintArea().Left(),
915  nTRight = rLRect.GetTab()->getFrameArea().Left() + rLRect.GetTab()->getFramePrintArea().Right();
916  if ( (nTLeft >= nLLeft && nTLeft <= nLRight) ||
917  (nTRight>= nLLeft && nTRight<= nLRight) )
918  bPaint = false;
919  }
920  else
921  {
922  // Horizontal edge, overlapping with the table edge?
923  SwTwips nLTop = rLRect.Top() - 30,
924  nLBottom = rLRect.Bottom() + 30,
925  nTTop = rLRect.GetTab()->getFrameArea().Top() + rLRect.GetTab()->getFramePrintArea().Top(),
926  nTBottom = rLRect.GetTab()->getFrameArea().Top() + rLRect.GetTab()->getFramePrintArea().Bottom();
927  if ( (nTTop >= nLTop && nTTop <= nLBottom) ||
928  (nTBottom >= nLTop && nTBottom <= nLBottom) )
929  bPaint = false;
930  }
931  }
932  if ( bPaint )
933  {
934  if ( !pLast || *pLast != rLRect.GetColor() )
935  {
936  pLast = &rLRect.GetColor();
937 
938  DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
939  if( properties.pSGlobalShell->GetWin() &&
941  pOut->SetDrawMode( DrawModeFlags::Default );
942 
943  pOut->SetLineColor( *pLast );
944  pOut->SetFillColor( *pLast );
945  pOut->SetDrawMode( nOldDrawMode );
946  }
947 
948  if( !rLRect.IsEmpty() )
949  lcl_DrawDashedRect( pOut, rLRect );
950  rLRect.SetPainted();
951  }
952  else
953  bPaint2nd = true;
954  }
955  if ( bPaint2nd )
956  {
957  for ( size_t i = 0; i < aLineRects.size(); ++i )
958  {
959  SwLineRect &rLRect = aLineRects[i];
960  if ( rLRect.IsPainted() )
961  continue;
962 
963  if ( rLRect.IsLocked() )
964  {
965  nMinCount = std::min( nMinCount, i );
966  continue;
967  }
968 
969  if ( !pLast || *pLast != rLRect.GetColor() )
970  {
971  pLast = &rLRect.GetColor();
972 
973  DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
974  if( properties.pSGlobalShell->GetWin() &&
976  {
977  pOut->SetDrawMode( DrawModeFlags::Default );
978  }
979 
980  pOut->SetFillColor( *pLast );
981  pOut->SetDrawMode( nOldDrawMode );
982  }
983  if( !rLRect.IsEmpty() )
984  lcl_DrawDashedRect( pOut, rLRect );
985  rLRect.SetPainted();
986  }
987  }
988  nLastCount = nMinCount;
989  pOut->Pop();
990 
991 }
992 
994  const SwLineRects *pRects,
995  SwPaintProperties const & properties )
996 {
997  if ( !aLineRects.empty() )
998  {
999  // #i16816# tagged pdf support
1000  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
1001 
1002  // Remove all help line that are almost covered (tables)
1003  for (size_type i = 0; i != aLineRects.size(); ++i)
1004  {
1005  SwLineRect &rLi = aLineRects[i];
1006  const bool bVerticalSubs = rLi.Height() > rLi.Width();
1007 
1008  for (size_type k = i + 1; k != aLineRects.size(); ++k)
1009  {
1010  SwLineRect &rLk = aLineRects[k];
1011  if ( rLi.SSize() == rLk.SSize() )
1012  {
1013  if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) )
1014  {
1015  if ( bVerticalSubs )
1016  {
1017  long nLi = rLi.Right();
1018  long nLk = rLk.Right();
1019  if ( rLi.Top() == rLk.Top() &&
1020  ((nLi < rLk.Left() && nLi+21 > rLk.Left()) ||
1021  (nLk < rLi.Left() && nLk+21 > rLi.Left())))
1022  {
1023  aLineRects.erase(aLineRects.begin() + k);
1024  // don't continue with inner loop any more:
1025  // the array may shrink!
1026  --i;
1027  break;
1028  }
1029  }
1030  else
1031  {
1032  long nLi = rLi.Bottom();
1033  long nLk = rLk.Bottom();
1034  if ( rLi.Left() == rLk.Left() &&
1035  ((nLi < rLk.Top() && nLi+21 > rLk.Top()) ||
1036  (nLk < rLi.Top() && nLk+21 > rLi.Top())))
1037  {
1038  aLineRects.erase(aLineRects.begin() + k);
1039  // don't continue with inner loop any more:
1040  // the array may shrink!
1041  --i;
1042  break;
1043  }
1044  }
1045  }
1046  }
1047  }
1048  }
1049 
1050  if ( pRects && (!pRects->aLineRects.empty()) )
1051  RemoveSuperfluousSubsidiaryLines( *pRects, properties );
1052 
1053  if ( !aLineRects.empty() )
1054  {
1055  pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
1056  pOut->SetLineColor();
1057 
1058  // Reset draw mode in high contrast mode in order to get fill color
1059  // set at output device. Recover draw mode after draw of lines.
1060  // Necessary for the subsidiary lines painted by the fly frames.
1061  DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
1062  if( gProp.pSGlobalShell->GetWin() &&
1064  {
1065  pOut->SetDrawMode( DrawModeFlags::Default );
1066  }
1067 
1068  for (SwLineRect& rLRect : aLineRects)
1069  {
1070  // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
1071  if ( !rLRect.IsPainted() &&
1072  !rLRect.IsLocked() )
1073  {
1074  const Color *pCol = nullptr;
1075  switch ( rLRect.GetSubColor() )
1076  {
1077  case SubColFlags::Page: pCol = &SwViewOption::GetDocBoundariesColor(); break;
1078  case SubColFlags::Fly: pCol = &SwViewOption::GetObjectBoundariesColor(); break;
1079  case SubColFlags::Tab: pCol = &SwViewOption::GetTableBoundariesColor(); break;
1080  case SubColFlags::Sect: pCol = &SwViewOption::GetSectionBoundColor(); break;
1081  }
1082 
1083  if (pCol && pOut->GetFillColor() != *pCol)
1084  pOut->SetFillColor( *pCol );
1085  pOut->DrawRect( rLRect.SVRect() );
1086 
1087  rLRect.SetPainted();
1088  }
1089  }
1090 
1091  pOut->SetDrawMode( nOldDrawMode );
1092 
1093  pOut->Pop();
1094  }
1095  }
1096 }
1097 
1098 // Various functions that are use in this file.
1099 
1107 void SwAlignRect( SwRect &rRect, const SwViewShell *pSh, const vcl::RenderContext* pRenderContext )
1108 {
1109  if( !rRect.HasArea() )
1110  return;
1111 
1112  // Make sure that view shell (parameter <pSh>) exists, if the output device
1113  // is taken from this view shell --> no output device, no alignment
1114  // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
1115  if ( !gProp.bSFlyMetafile && !pSh )
1116  {
1117  return;
1118  }
1119 
1120  const vcl::RenderContext *pOut = gProp.bSFlyMetafile ?
1121  gProp.pSFlyMetafileOut.get() : pRenderContext;
1122 
1123  // Hold original rectangle in pixel
1124  const tools::Rectangle aOrgPxRect = pOut->LogicToPixel( rRect.SVRect() );
1125  // Determine pixel-center rectangle in twip
1126  const SwRect aPxCenterRect( pOut->PixelToLogic( aOrgPxRect ) );
1127 
1128  // Perform adjustments on pixel level.
1129  SwRect aAlignedPxRect( aOrgPxRect );
1130  if ( rRect.Top() > aPxCenterRect.Top() )
1131  {
1132  // 'leave pixel overlapping on top'
1133  aAlignedPxRect.Top( aAlignedPxRect.Top() + 1 );
1134  }
1135 
1136  if ( rRect.Bottom() < aPxCenterRect.Bottom() )
1137  {
1138  // 'leave pixel overlapping on bottom'
1139  aAlignedPxRect.Bottom( aAlignedPxRect.Bottom() - 1 );
1140  }
1141 
1142  if ( rRect.Left() > aPxCenterRect.Left() )
1143  {
1144  // 'leave pixel overlapping on left'
1145  aAlignedPxRect.Left( aAlignedPxRect.Left() + 1 );
1146  }
1147 
1148  if ( rRect.Right() < aPxCenterRect.Right() )
1149  {
1150  // 'leave pixel overlapping on right'
1151  aAlignedPxRect.Right( aAlignedPxRect.Right() - 1 );
1152  }
1153 
1154  // Consider negative width/height check, if aligned SwRect has negative width/height.
1155  // If Yes, adjust it to width/height = 0 twip.
1156  // NOTE: A SwRect with negative width/height can occur, if the width/height
1157  // of the given SwRect in twip was less than a pixel in twip and that
1158  // the alignment calculates that the aligned SwRect should not contain
1159  // the pixels the width/height is on.
1160  if ( aAlignedPxRect.Width() < 0 )
1161  {
1162  aAlignedPxRect.Width(0);
1163  }
1164  if ( aAlignedPxRect.Height() < 0 )
1165  {
1166  aAlignedPxRect.Height(0);
1167  }
1168  // Consider zero width/height for converting a rectangle from
1169  // pixel to logic it needs a width/height. Thus, set width/height
1170  // to one, if it's zero and correct this on the twip level after the conversion.
1171  bool bZeroWidth = false;
1172  if ( aAlignedPxRect.Width() == 0 )
1173  {
1174  aAlignedPxRect.Width(1);
1175  bZeroWidth = true;
1176  }
1177  bool bZeroHeight = false;
1178  if ( aAlignedPxRect.Height() == 0 )
1179  {
1180  aAlignedPxRect.Height(1);
1181  bZeroHeight = true;
1182  }
1183 
1184  rRect = pOut->PixelToLogic( aAlignedPxRect.SVRect() );
1185 
1186  // Consider zero width/height and adjust calculated aligned twip rectangle.
1187  // Reset width/height to zero; previous negative width/height haven't to be considered.
1188  if ( bZeroWidth )
1189  {
1190  rRect.Width(0);
1191  }
1192  if ( bZeroHeight )
1193  {
1194  rRect.Height(0);
1195  }
1196 }
1197 
1213 void SwAlignGrfRect( SwRect *pGrfRect, const vcl::RenderContext &rOut )
1214 {
1215  tools::Rectangle aPxRect = rOut.LogicToPixel( pGrfRect->SVRect() );
1216  pGrfRect->Pos( rOut.PixelToLogic( aPxRect.TopLeft() ) );
1217  pGrfRect->SSize( rOut.PixelToLogic( aPxRect.GetSize() ) );
1218 }
1219 
1220 static long lcl_AlignWidth( const long nWidth, SwPaintProperties const & properties )
1221 {
1222  if ( nWidth )
1223  {
1224  const long nW = nWidth % properties.nSPixelSzW;
1225 
1226  if ( !nW || nW > properties.nSHalfPixelSzW )
1227  return std::max(1L, nWidth - properties.nSHalfPixelSzW);
1228  }
1229  return nWidth;
1230 }
1231 
1232 static long lcl_AlignHeight( const long nHeight, SwPaintProperties const & properties )
1233 {
1234  if ( nHeight )
1235  {
1236  const long nH = nHeight % properties.nSPixelSzH;
1237 
1238  if ( !nH || nH > properties.nSHalfPixelSzH )
1239  return std::max(1L, nHeight - properties.nSHalfPixelSzH);
1240  }
1241  return nHeight;
1242 }
1243 
1247 static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame,
1248  const SwBorderAttrs &rAttrs,
1249  const bool bShadow,
1250  SwPaintProperties const & properties)
1251 {
1252  // Special handling for cell frames.
1253  // The printing area of a cell frame is completely enclosed in the frame area
1254  // and a cell frame has no shadow. Thus, for cell frames the calculated
1255  // area equals the frame area.
1256  // Notes: Borders of cell frames in R2L text direction will switch its side
1257  // - left border is painted on the right; right border on the left.
1258  // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
1259  if( pFrame->IsSctFrame() )
1260  {
1261  rRect = pFrame->getFramePrintArea();
1262  rRect.Pos() += pFrame->getFrameArea().Pos();
1263  }
1264  else if ( pFrame->IsCellFrame() )
1265  rRect = pFrame->getFrameArea();
1266  else
1267  {
1268  rRect = pFrame->getFramePrintArea();
1269  rRect.Pos() += pFrame->getFrameArea().Pos();
1270 
1271  SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? (pFrame->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
1272 
1273  const SvxBoxItem &rBox = rAttrs.GetBox();
1274  const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
1275  if ( bTop )
1276  {
1277  SwTwips nDiff = rBox.GetTop() ?
1278  rBox.CalcLineSpace( SvxBoxItemLine::TOP ) :
1279  rBox.GetDistance( SvxBoxItemLine::TOP );
1280  if( nDiff )
1281  (rRect.*fnRect->fnSubTop)( nDiff );
1282  }
1283 
1284  const bool bBottom = 0 != (pFrame->*fnRect->fnGetBottomMargin)();
1285  if ( bBottom )
1286  {
1287  SwTwips nDiff = 0;
1288  // #i29550#
1289  if ( pFrame->IsTabFrame() &&
1290  static_cast<const SwTabFrame*>(pFrame)->IsCollapsingBorders() )
1291  {
1292  // For collapsing borders, we have to add the height of
1293  // the height of the last line
1294  nDiff = static_cast<const SwTabFrame*>(pFrame)->GetBottomLineSize();
1295  }
1296  else
1297  {
1298  nDiff = rBox.GetBottom() ?
1299  rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM ) :
1300  rBox.GetDistance( SvxBoxItemLine::BOTTOM );
1301  }
1302  if( nDiff )
1303  (rRect.*fnRect->fnAddBottom)( nDiff );
1304  }
1305 
1306  if ( rBox.GetLeft() )
1307  (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( SvxBoxItemLine::LEFT ) );
1308  else
1309  (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( SvxBoxItemLine::LEFT ) );
1310 
1311  if ( rBox.GetRight() )
1312  (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( SvxBoxItemLine::RIGHT ) );
1313  else
1314  (rRect.*fnRect->fnAddRight)( rBox.GetDistance( SvxBoxItemLine::RIGHT ) );
1315 
1316  if ( bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
1317  {
1318  const SvxShadowItem &rShadow = rAttrs.GetShadow();
1319  if ( bTop )
1320  (rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
1321  (rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
1322  if ( bBottom )
1323  (rRect.*fnRect->fnAddBottom)
1324  (rShadow.CalcShadowSpace( SvxShadowItemSide::BOTTOM ));
1325  (rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
1326  }
1327  }
1328 
1329  ::SwAlignRect( rRect, properties.pSGlobalShell, properties.pSGlobalShell ? properties.pSGlobalShell->GetOut() : nullptr );
1330 }
1331 
1336 static void lcl_ExtendLeftAndRight( SwRect& _rRect,
1337  const SwFrame& _rFrame,
1338  const SwBorderAttrs& _rAttrs,
1339  const SwRectFn& _rRectFn )
1340 {
1341  if ( _rAttrs.JoinedWithPrev( _rFrame ) )
1342  {
1343  const SwFrame* pPrevFrame = _rFrame.GetPrev();
1344  (_rRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
1345  }
1346  if ( _rAttrs.JoinedWithNext( _rFrame ) )
1347  {
1348  const SwFrame* pNextFrame = _rFrame.GetNext();
1349  (_rRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
1350  }
1351 }
1352 
1356 {
1357  static MapMode aMapMode(MapUnit::MapTwip);
1358  static const Size aSingleUnit = Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode);
1359 
1360  double x1 = rRect.Left() + aSingleUnit.getWidth();
1361  double y1 = rRect.Top() + aSingleUnit.getHeight();
1362  double x2 = rRect.Right() - aSingleUnit.getWidth();
1363  double y2 = rRect.Bottom() - aSingleUnit.getHeight();
1364 
1365  return basegfx::B2DRange(x1, y1, x2, y2);
1366 }
1367 
1368 static void lcl_SubtractFlys( const SwFrame *pFrame, const SwPageFrame *pPage,
1369  const SwRect &rRect, SwRegionRects &rRegion, basegfx::utils::B2DClipState& rClipState, SwPaintProperties const & rProperties)
1370 {
1371  const SwSortedObjs& rObjs = *pPage->GetSortedObjs();
1372  const SwFlyFrame* pSelfFly = pFrame->IsInFly() ? pFrame->FindFlyFrame() : gProp.pSRetoucheFly2;
1373  if (!gProp.pSRetoucheFly)
1374  gProp.pSRetoucheFly = gProp.pSRetoucheFly2;
1375 
1376  for (size_t j = 0; (j < rObjs.size()) && !rRegion.empty(); ++j)
1377  {
1378  const SwAnchoredObject* pAnchoredObj = rObjs[j];
1379  const SdrObject* pSdrObj = pAnchoredObj->GetDrawObj();
1380 
1381  // Do not consider invisible objects
1382  if (!pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj->GetLayer()))
1383  continue;
1384 
1385  if (dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr)
1386  continue;
1387 
1388  const SwFlyFrame *pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
1389 
1390  if (pSelfFly == pFly || gProp.pSRetoucheFly == pFly || !rRect.IsOver(pFly->getFrameArea()))
1391  continue;
1392 
1393  if (!pFly->GetFormat()->GetPrint().GetValue() &&
1395  gProp.pSGlobalShell->IsPreview()))
1396  continue;
1397 
1398  const bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly );
1399 
1400  //For character bound Flys only examine those Flys in which it is not
1401  //anchored itself.
1402  //Why only for character bound ones you may ask? It never makes sense to
1403  //subtract frames in which it is anchored itself right?
1404  if (pSelfFly && pSelfFly->IsLowerOf(pFly))
1405  continue;
1406 
1407  //Any why does it not apply for the RetoucheFly too?
1408  if (gProp.pSRetoucheFly && gProp.pSRetoucheFly->IsLowerOf(pFly))
1409  continue;
1410 
1411 #if OSL_DEBUG_LEVEL > 0
1412  //Flys who are anchored inside their own one, must have a bigger OrdNum
1413  //or be character bound.
1414  if (pSelfFly && bLowerOfSelf)
1415  {
1416  OSL_ENSURE( pFly->IsFlyInContentFrame() ||
1417  pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(),
1418  "Fly with wrong z-Order" );
1419  }
1420 #endif
1421 
1422  bool bStopOnHell = true;
1423  if (pSelfFly)
1424  {
1425  const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
1426  if (pSdrObj->GetLayer() == pTmp->GetLayer())
1427  {
1428  if (pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect())
1429  //In the same layer we only observe those that are above.
1430  continue;
1431  }
1432  else
1433  {
1434  if (!bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue())
1435  //From other layers we are only interested in non
1436  //transparent ones or those that are internal
1437  continue;
1438  bStopOnHell = false;
1439  }
1440  }
1441  if (gProp.pSRetoucheFly)
1442  {
1443  const SdrObject *pTmp = gProp.pSRetoucheFly->GetVirtDrawObj();
1444  if ( pSdrObj->GetLayer() == pTmp->GetLayer() )
1445  {
1446  if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
1447  //In the same layer we only observe those that are above.
1448  continue;
1449  }
1450  else
1451  {
1452  if (!pFly->IsLowerOf( gProp.pSRetoucheFly ) && !pFly->GetFormat()->GetOpaque().GetValue())
1453  //From other layers we are only interested in non
1454  //transparent ones or those that are internal
1455  continue;
1456  bStopOnHell = false;
1457  }
1458  }
1459 
1460  //If the content of the Fly is transparent, we subtract it only if it's
1461  //contained in the hell layer.
1463  bool bHell = pSdrObj->GetLayer() == rIDDMA.GetHellId();
1464  if ( (bStopOnHell && bHell) ||
1468  ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTextFrame() &&
1469  (static_cast<SwNoTextFrame const*>(pFly->Lower())->IsTransparent() ||
1470  static_cast<SwNoTextFrame const*>(pFly->Lower())->HasAnimation() ||
1471  pFly->GetFormat()->GetSurround().IsContour()
1472  )
1473  )
1474  )
1475  continue;
1476 
1477  // Own if-statements for transparent background/shadow of fly frames
1478  // in order to handle special conditions.
1479  if (pFly->IsBackgroundTransparent())
1480  {
1481  // Background <pFly> is transparent drawn. Thus normally, its region
1482  // have not to be subtracted from given region.
1483  // But, if method is called for a fly frame and
1484  // <pFly> is a direct lower of this fly frame and
1485  // <pFly> inherites its transparent background brush from its parent,
1486  // then <pFly> frame area have to be subtracted from given region.
1487  // NOTE: Because in Status Quo transparent backgrounds can only be
1488  // assigned to fly frames, the handle of this special case
1489  // avoids drawing of transparent areas more than once, if
1490  // a fly frame inherites a transparent background from its
1491  // parent fly frame.
1492  if (pFrame->IsFlyFrame() &&
1493  (pFly->GetAnchorFrame()->FindFlyFrame() == pFrame) &&
1495  )
1496  {
1497  SwRect aRect;
1498  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1499  const SwBorderAttrs &rAttrs = *aAccess.Get();
1500  ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1501  rRegion -= aRect;
1502  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1503  continue;
1504  }
1505  else
1506  {
1507  continue;
1508  }
1509  }
1510 
1511  if (bHell && pFly->GetAnchorFrame()->IsInFly())
1512  {
1513  //So the border won't get dismantled by the background of the other
1514  //Fly.
1515  SwRect aRect;
1516  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1517  const SwBorderAttrs &rAttrs = *aAccess.Get();
1518  ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1519  rRegion -= aRect;
1520  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1521  }
1522  else
1523  {
1524  SwRect aRect( pFly->getFramePrintArea() );
1525  aRect += pFly->getFrameArea().Pos();
1526  rRegion -= aRect;
1527  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1528  }
1529  }
1530  if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
1531  gProp.pSRetoucheFly = nullptr;
1532 }
1533 
1534 static void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1535  vcl::RenderContext* _pOut,
1536  const SwRect& _rAlignedPaintRect,
1537  const GraphicObject& _rGraphicObj,
1538  SwPaintProperties const & properties)
1539 {
1544  const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || properties.bSFlyMetafile )
1545  ? _rBackgrdBrush.GetColor()
1547 
1550  sal_Int8 nTransparencyPercent = 0;
1551  bool bDrawTransparent = false;
1552  if ( aColor.GetTransparency() != 0 )
1554  {
1555  bDrawTransparent = true;
1556  nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF;
1557  }
1558  else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) &&
1559  (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) )
1562  {
1563  bDrawTransparent = true;
1564  nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF;
1565  }
1566 
1567  if ( bDrawTransparent )
1568  {
1570  if( _pOut->GetFillColor() != aColor.GetRGBColor() )
1571  _pOut->SetFillColor( aColor.GetRGBColor() );
1572  tools::PolyPolygon aPoly( _rAlignedPaintRect.SVRect() );
1573  _pOut->DrawTransparent( aPoly, nTransparencyPercent );
1574  }
1575  else
1576  {
1578  if ( _pOut->GetFillColor() != aColor )
1579  _pOut->SetFillColor( aColor );
1580  _pOut->DrawRect( _rAlignedPaintRect.SVRect() );
1581  }
1582 }
1583 
1616 static void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1617  OutputDevice* _pOut,
1618  const SwRect& _rAlignedPaintRect,
1619  const GraphicObject& _rGraphicObj,
1620  bool _bNumberingGraphic,
1621  SwPaintProperties const & properties,
1622  bool _bBackgrdAlreadyDrawn = false)
1623 {
1624  // draw background with background color, if
1625  // (1) graphic is not used as a numbering AND
1626  // (2) background is not already drawn AND
1627  // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
1628  if ( !_bNumberingGraphic &&
1629  !_bBackgrdAlreadyDrawn &&
1630  ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GraphicType::NONE )
1631  )
1632  {
1633  lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj, properties );
1634  }
1635 }
1636 
1652 static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext *pOut,
1653  SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut,
1654  bool bGrfNum,
1655  SwPaintProperties const & properties,
1656  bool bBackgrdAlreadyDrawn )
1657  // add parameter <bBackgrdAlreadyDrawn> to indicate
1658  // that the background is already drawn.
1659 {
1660  // Calculate align rectangle from parameter <rGrf> and use aligned
1661  // rectangle <aAlignedGrfRect> in the following code
1662  SwRect aAlignedGrfRect = rGrf;
1663  ::SwAlignRect( aAlignedGrfRect, &rSh, pOut );
1664 
1665  // Change type from <bool> to <bool>.
1666  const bool bNotInside = !rOut.IsInside( aAlignedGrfRect );
1667  if ( bNotInside )
1668  {
1669  pOut->Push( PushFlags::CLIPREGION );
1670  pOut->IntersectClipRegion( rOut.SVRect() );
1671  }
1672 
1673  GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
1674 
1675  // Outsource drawing of background with a background color
1676  ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, properties, bBackgrdAlreadyDrawn );
1677 
1678  // Because for drawing a graphic left-top-corner and size coordinates are
1679  // used, these coordinates have to be determined on pixel level.
1680  ::SwAlignGrfRect( &aAlignedGrfRect, *pOut );
1681 
1682  const basegfx::B2DHomMatrix aGraphicTransform(
1684  aAlignedGrfRect.Width(), aAlignedGrfRect.Height(),
1685  aAlignedGrfRect.Left(), aAlignedGrfRect.Top()));
1686 
1688  *pOut,
1689  *pGrf,
1690  pGrf->GetAttr(),
1691  aGraphicTransform,
1692  OUString(),
1693  OUString(),
1694  OUString());
1695 
1696  if ( bNotInside )
1697  pOut->Pop();
1698 }
1699 
1702  const SwRect& rOriginalLayoutRect,
1703  const SwRegionRects& rPaintRegion,
1704  const basegfx::utils::B2DClipState& rClipState,
1705  vcl::RenderContext& rOut)
1706 {
1707  if(rFillAttributes.get() && rFillAttributes->isUsed())
1708  {
1709  basegfx::B2DRange aPaintRange(
1710  rPaintRegion.GetOrigin().Left(),
1711  rPaintRegion.GetOrigin().Top(),
1712  rPaintRegion.GetOrigin().Right(),
1713  rPaintRegion.GetOrigin().Bottom());
1714 
1715  if (!aPaintRange.isEmpty() &&
1716  !rPaintRegion.empty() &&
1717  !basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
1718  !basegfx::fTools::equalZero(aPaintRange.getHeight()))
1719  {
1720  const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1721 
1722  // need to expand for correct AAed and non-AAed visualization as primitive.
1723  // This must probably be removed again when we will be able to get all Writer visualization
1724  // as primitives and Writer prepares all it's stuff in high precision coordinates (also
1725  // needs to avoid moving boundaries around to better show overlapping stuff...)
1726  if(aSvtOptionsDrawinglayer.IsAntiAliasing())
1727  {
1728  // if AAed in principle expand by 0.5 in all directions. Since painting edges of
1729  // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
1730  // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
1731  // artifacts. Checked experimentally - a little bit more in Y is needed, probably
1732  // due to still existing integer alignment and crunching in writer.
1733  static const double fExpandX = 0.55;
1734  static const double fExpandY = 0.70;
1735  const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX, fExpandY));
1736 
1737  aPaintRange.expand(aPaintRange.getMinimum() - aSingleUnit);
1738  aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1739  }
1740  else
1741  {
1742  // if not AAed expand by one unit to bottom right due to the missing unit
1743  // from SwRect/Rectangle integer handling
1744  const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
1745 
1746  aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1747  }
1748 
1749  const basegfx::B2DRange aDefineRange(
1750  rOriginalLayoutRect.Left(),
1751  rOriginalLayoutRect.Top(),
1752  rOriginalLayoutRect.Right(),
1753  rOriginalLayoutRect.Bottom());
1754 
1755  const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rFillAttributes->getPrimitive2DSequence(
1756  aPaintRange,
1757  aDefineRange);
1758 
1759  if(rSequence.size())
1760  {
1762  pPrimitives(&rSequence);
1764  // tdf#86578 the awful lcl_SubtractFlys hack
1765  if (rPaintRegion.size() > 1 || rPaintRegion[0] != rPaintRegion.GetOrigin())
1766  {
1767  basegfx::B2DPolyPolygon const& maskRegion(rClipState.getClipPoly());
1768  primitives.resize(1);
1769  primitives[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
1770  maskRegion, rSequence);
1771  pPrimitives = &primitives;
1772  }
1773  assert(pPrimitives && pPrimitives->size());
1774 
1775  const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
1777  rOut.GetViewTransformation(),
1778  aPaintRange,
1779  nullptr,
1780  0.0,
1781  uno::Sequence< beans::PropertyValue >());
1782  std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1783  rOut,
1784  aViewInformation2D) );
1785  if(pProcessor)
1786  {
1787  pProcessor->process(*pPrimitives);
1788  return true;
1789  }
1790  }
1791  }
1792  }
1793 
1794  return false;
1795 }
1796 
1798  const SvxBrushItem *pBrush,
1799  vcl::RenderContext *pOutDev,
1800  const SwRect &rOrg,
1801  const SwRect &rOut,
1802  const sal_uInt8 nGrfNum,
1803  const bool bConsiderBackgroundTransparency )
1804  // Add 6th parameter to indicate that method should
1805  // consider background transparency, saved in the color of the brush item
1806 {
1807  SwViewShell &rSh = *gProp.pSGlobalShell;
1808  bool bReplaceGrfNum = GRFNUM_REPLACE == nGrfNum;
1809  bool bGrfNum = GRFNUM_NO != nGrfNum;
1810  Size aGrfSize;
1812  if( pBrush && !bReplaceGrfNum )
1813  {
1814  if( rSh.GetViewOptions()->IsGraphic() )
1815  {
1816  OUString referer;
1817  SfxObjectShell * sh = rSh.GetDoc()->GetPersist();
1818  if (sh != nullptr && sh->HasName()) {
1819  referer = sh->GetMedium()->GetName();
1820  }
1821  const Graphic* pGrf = pBrush->GetGraphic(referer);
1822  if( pGrf && GraphicType::NONE != pGrf->GetType() )
1823  {
1824  ePos = pBrush->GetGraphicPos();
1825  if( pGrf->IsSupportedGraphic() )
1826  // don't the use the specific output device! Bug 94802
1827  aGrfSize = ::GetGraphicSizeTwip( *pGrf, nullptr );
1828  }
1829  }
1830  else
1831  bReplaceGrfNum = bGrfNum;
1832  }
1833 
1834  SwRect aGrf;
1835  aGrf.SSize( aGrfSize );
1836  bool bDraw = true;
1837  bool bRetouche = true;
1838  switch ( ePos )
1839  {
1840  case GPOS_LT:
1841  aGrf.Pos() = rOrg.Pos();
1842  break;
1843 
1844  case GPOS_MT:
1845  aGrf.Pos().setY( rOrg.Top() );
1846  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1847  break;
1848 
1849  case GPOS_RT:
1850  aGrf.Pos().setY( rOrg.Top() );
1851  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1852  break;
1853 
1854  case GPOS_LM:
1855  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1856  aGrf.Pos().setX( rOrg.Left() );
1857  break;
1858 
1859  case GPOS_MM:
1860  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1861  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1862  break;
1863 
1864  case GPOS_RM:
1865  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1866  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1867  break;
1868 
1869  case GPOS_LB:
1870  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1871  aGrf.Pos().setX( rOrg.Left() );
1872  break;
1873 
1874  case GPOS_MB:
1875  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1876  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1877  break;
1878 
1879  case GPOS_RB:
1880  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1881  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1882  break;
1883 
1884  case GPOS_AREA:
1885  aGrf = rOrg;
1886  // Despite the fact that the background graphic has to fill the complete
1887  // area, we already checked, whether the graphic will completely fill out
1888  // the region the <rOut> that is to be painted. Thus, nothing has to be
1889  // touched again.
1890  // E.g. this is the case for a Fly Frame without a background
1891  // brush positioned on the border of the page which inherited the background
1892  // brush from the page.
1893  bRetouche = !rOut.IsInside( aGrf );
1894  break;
1895 
1896  case GPOS_TILED:
1897  {
1898  // draw background of tiled graphic before drawing tiled graphic in loop
1899  // determine graphic object
1900  GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject());
1901  // calculate aligned paint rectangle
1902  SwRect aAlignedPaintRect = rOut;
1903  ::SwAlignRect( aAlignedPaintRect, &rSh, pOutDev );
1904  // draw background color for aligned paint rectangle
1905  lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum, gProp );
1906 
1907  // set left-top-corner of background graphic to left-top-corner of the
1908  // area, from which the background brush is determined.
1909  aGrf.Pos() = rOrg.Pos();
1910  // setup clipping at output device
1911  pOutDev->Push( PushFlags::CLIPREGION );
1912  pOutDev->IntersectClipRegion( rOut.SVRect() );
1913  // use new method <GraphicObject::DrawTiled(::)>
1914  {
1915  // calculate paint offset
1916  Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() );
1917  // draw background graphic tiled for aligned paint rectangle
1918  // #i42643#
1919  // For PDF export, every draw operation for bitmaps takes a
1920  // noticeable amount of place (~50 characters). Thus, optimize
1921  // between tile bitmap size and number of drawing operations here.
1922 
1923  // A_out
1924  // n_chars = k1 * ---------- + k2 * A_bitmap
1925  // A_bitmap
1926 
1927  // minimum n_chars is obtained for (derive for A_bitmap,
1928  // set to 0, take positive solution):
1929  // k1
1930  // A_bitmap = Sqrt( ---- A_out )
1931  // k2
1932 
1933  // where k1 is the number of chars per draw operation, and
1934  // k2 is the number of chars per bitmap pixel.
1935  // This is approximately 50 and 7 for current PDF writer, respectively.
1936 
1937  const double k1( 50 );
1938  const double k2( 7 );
1939  const Size aSize( aAlignedPaintRect.SSize() );
1940  const double Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() );
1941 
1942  pGraphicObj->DrawTiled( pOutDev,
1943  aAlignedPaintRect.SVRect(),
1944  aGrf.SSize(),
1945  Size( aPaintOffset.X(), aPaintOffset.Y() ),
1946  std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
1947  }
1948  // reset clipping at output device
1949  pOutDev->Pop();
1950  // set <bDraw> and <bRetouche> to false, indicating that background
1951  // graphic and background are already drawn.
1952  bDraw = bRetouche = false;
1953  }
1954  break;
1955 
1956  case GPOS_NONE:
1957  bDraw = false;
1958  break;
1959 
1960  default: OSL_ENSURE( !pOutDev, "new Graphic position?" );
1961  }
1962 
1965  bool bGrfBackgrdAlreadyDrawn = false;
1966  if ( bRetouche )
1967  {
1968  pOutDev->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
1969  pOutDev->SetLineColor();
1970 
1971  // check, if an existing background graphic (not filling the complete
1972  // background) is transparent drawn and the background color is
1973  // "no fill" respectively "auto fill", if background transparency
1974  // has to be considered.
1975  // If YES, memorize transparency of background graphic.
1976  // check also, if background graphic bitmap is transparent.
1977  bool bTransparentGrfWithNoFillBackgrd = false;
1978  sal_Int32 nGrfTransparency = 0;
1979  bool bGrfIsTransparent = false;
1980  if ( (ePos != GPOS_NONE) &&
1981  (ePos != GPOS_TILED) && (ePos != GPOS_AREA)
1982  )
1983  {
1984  GraphicObject *pGrf = const_cast<GraphicObject*>(pBrush->GetGraphicObject());
1985  if ( bConsiderBackgroundTransparency )
1986  {
1987  GraphicAttr aGrfAttr = pGrf->GetAttr();
1988  if ( (aGrfAttr.GetTransparency() != 0) &&
1989  (pBrush->GetColor() == COL_TRANSPARENT)
1990  )
1991  {
1992  bTransparentGrfWithNoFillBackgrd = true;
1993  nGrfTransparency = aGrfAttr.GetTransparency();
1994  }
1995  }
1996  if ( pGrf->IsTransparent() )
1997  {
1998  bGrfIsTransparent = true;
1999  }
2000  }
2001 
2002  // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
2003  // instead of checking, if transparency is not set.
2004  const Color aColor( pBrush &&
2005  ( (pBrush->GetColor() != COL_TRANSPARENT) ||
2006  gProp.bSFlyMetafile )
2007  ? pBrush->GetColor()
2009 
2010  // determine, if background region have to be
2011  // drawn transparent.
2012  // background region has to be drawn transparent, if
2013  // background transparency have to be considered
2014  // AND
2015  // ( background color is transparent OR
2016  // background graphic is transparent and background color is "no fill"
2017  // )
2018 
2019  enum DrawStyle {
2020  Default,
2021  Transparent,
2022  } eDrawStyle = Default;
2023 
2024  if (bConsiderBackgroundTransparency &&
2025  ( ( aColor.GetTransparency() != 0) ||
2026  bTransparentGrfWithNoFillBackgrd ) )
2027  {
2028  eDrawStyle = Transparent;
2029  }
2030 
2031  // #i75614# reset draw mode in high contrast mode in order to get fill color set
2032  const DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
2033  if ( gProp.pSGlobalShell->GetWin() &&
2035  {
2036  pOutDev->SetDrawMode( DrawModeFlags::Default );
2037  }
2038 
2039  // OD 06.08.2002 #99657# - if background region has to be drawn
2040  // transparent, set only the RGB values of the background color as
2041  // the fill color for the output device.
2042  switch (eDrawStyle)
2043  {
2044  case Transparent:
2045  {
2046  if( pOutDev->GetFillColor() != aColor.GetRGBColor() )
2047  pOutDev->SetFillColor( aColor.GetRGBColor() );
2048  break;
2049  }
2050  default:
2051  {
2052  if( pOutDev->GetFillColor() != aColor )
2053  pOutDev->SetFillColor( aColor );
2054  break;
2055  }
2056  }
2057 
2058  // #i75614#
2059  // restore draw mode
2060  pOutDev->SetDrawMode( nOldDrawMode );
2061 
2062  // OD 02.09.2002 #99657#
2063  switch (eDrawStyle)
2064  {
2065  case Transparent:
2066  {
2067  // background region have to be drawn transparent.
2068  // Thus, create a poly-polygon from the region and draw it with
2069  // the corresponding transparency percent.
2070  tools::PolyPolygon aDrawPoly( rOut.SVRect() );
2071  if ( aGrf.HasArea() )
2072  {
2073  if ( !bGrfIsTransparent )
2074  {
2075  // subtract area of background graphic from draw area
2076  // OD 08.10.2002 #103898# - consider only that part of the
2077  // graphic area that is overlapping with draw area.
2078  SwRect aTmpGrf = aGrf;
2079  aTmpGrf.Intersection( rOut );
2080  if ( aTmpGrf.HasArea() )
2081  {
2082  tools::Polygon aGrfPoly( aTmpGrf.SVRect() );
2083  aDrawPoly.Insert( aGrfPoly );
2084  }
2085  }
2086  else
2087  bGrfBackgrdAlreadyDrawn = true;
2088  }
2089  // calculate transparency percent:
2090  // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
2091  // If there is a background graphic with a background color "no fill"/"auto fill",
2092  // the transparency value is taken from the background graphic,
2093  // otherwise take the transparency value from the color.
2094  sal_Int8 nTransparencyPercent = static_cast<sal_Int8>(
2095  (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency()
2096  )*100 + 0x7F)/0xFF);
2097  // draw poly-polygon transparent
2098  pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent );
2099 
2100  break;
2101  }
2102  case Default:
2103  default:
2104  {
2105  SwRegionRects aRegion( rOut, 4 );
2106  if ( !bGrfIsTransparent )
2107  aRegion -= aGrf;
2108  else
2109  bGrfBackgrdAlreadyDrawn = true;
2110  // loop rectangles of background region, which has to be drawn
2111  for( size_t i = 0; i < aRegion.size(); ++i )
2112  {
2113  pOutDev->DrawRect( aRegion[i].SVRect() );
2114  }
2115  }
2116  }
2117  pOutDev ->Pop();
2118  }
2119 
2120  if( bDraw && aGrf.IsOver( rOut ) )
2121  // OD 02.09.2002 #99657#
2122  // add parameter <bGrfBackgrdAlreadyDrawn>
2123  lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, bGrfNum, gProp,
2124  bGrfBackgrdAlreadyDrawn );
2125 
2126  if( bReplaceGrfNum )
2127  {
2128  const BitmapEx& rBmp = rSh.GetReplacementBitmap(false);
2129  vcl::Font aTmp( pOutDev->GetFont() );
2130  Graphic::DrawEx(pOutDev, OUString(), aTmp, rBmp, rOrg.Pos(), rOrg.SSize());
2131  }
2132 }
2133 
2142 static void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const vcl::RenderContext &aOut )
2143 {
2144  // local constant object of class <Size> to determine number of Twips
2145  // representing a pixel.
2146  const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) );
2147 
2148  // local object of class <Rectangle> in Twip coordinates
2149  // calculated from given rectangle aligned to pixel centers.
2150  const tools::Rectangle aPxCenterRect = aOut.PixelToLogic(
2151  aOut.LogicToPixel( io_aSwRect.SVRect() ) );
2152 
2153  // local constant object of class <Rectangle> representing given rectangle
2154  // in pixel.
2155  const tools::Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2156 
2157  // calculate adjusted rectangle from pixel centered rectangle.
2158  // Due to rounding differences <aPxCenterRect> doesn't exactly represents
2159  // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
2160  // Afterwards, adjust calculated Twip-positions of the all borders.
2161  tools::Rectangle aSizedRect = aPxCenterRect;
2162  aSizedRect.AdjustLeft( -(aTwipToPxSize.Width()/2 + 1) );
2163  aSizedRect.AdjustRight( aTwipToPxSize.Width()/2 + 1 );
2164  aSizedRect.AdjustTop( -(aTwipToPxSize.Height()/2 + 1) );
2165  aSizedRect.AdjustBottom(aTwipToPxSize.Height()/2 + 1);
2166 
2167  // adjust left()
2168  while ( aOut.LogicToPixel(aSizedRect).Left() < aOrgPxRect.Left() )
2169  {
2170  aSizedRect.AdjustLeft( 1 );
2171  }
2172  // adjust right()
2173  while ( aOut.LogicToPixel(aSizedRect).Right() > aOrgPxRect.Right() )
2174  {
2175  aSizedRect.AdjustRight( -1 );
2176  }
2177  // adjust top()
2178  while ( aOut.LogicToPixel(aSizedRect).Top() < aOrgPxRect.Top() )
2179  {
2180  aSizedRect.AdjustTop( 1 );
2181  }
2182  // adjust bottom()
2183  while ( aOut.LogicToPixel(aSizedRect).Bottom() > aOrgPxRect.Bottom() )
2184  {
2185  aSizedRect.AdjustBottom( -1 );
2186  }
2187 
2188  io_aSwRect = SwRect( aSizedRect );
2189 
2190 #if OSL_DEBUG_LEVEL > 0
2191  tools::Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2192  tools::Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2193  OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect,
2194  "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
2195  // check Left()
2196  aSizedRect.AdjustLeft( -1 );
2197  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2198  OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1),
2199  "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
2200  aSizedRect.AdjustLeft( 1 );
2201  // check Right()
2202  aSizedRect.AdjustRight( 1 );
2203  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2204  OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1),
2205  "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
2206  aSizedRect.AdjustRight( -1 );
2207  // check Top()
2208  aSizedRect.AdjustTop( -1 );
2209  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2210  OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1),
2211  "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
2212  aSizedRect.AdjustTop( 1 );
2213  // check Bottom()
2214  aSizedRect.AdjustBottom( 1 );
2215  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2216  OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1),
2217  "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
2218  aSizedRect.AdjustBottom( -1 );
2219 #endif
2220 }
2221 
2222 // FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
2223 
2225 {
2229 
2231 
2233 
2234 public:
2235  SwLineEntry( SwTwips nKey,
2236  SwTwips nStartPos,
2237  SwTwips nEndPos,
2238  const svx::frame::Style& rAttribute );
2239 
2240  OverlapType Overlaps( const SwLineEntry& rComp ) const;
2241 };
2242 
2244  SwTwips nStartPos,
2245  SwTwips nEndPos,
2246  const svx::frame::Style& rAttribute )
2247  : mnKey( nKey ),
2248  mnStartPos( nStartPos ),
2249  mnEndPos( nEndPos ),
2250  maAttribute( rAttribute )
2251 {
2252 }
2253 
2254 /*
2255 
2256  1. ---------- rOld
2257  ---------- rNew
2258 
2259  2. ---------- rOld
2260  ------------- rNew
2261 
2262  3. ------- rOld
2263  ------------- rNew
2264 
2265  4. ------------- rOld
2266  ---------- rNew
2267 
2268  5. ---------- rOld
2269  ---- rNew
2270 
2271  6. ---------- rOld
2272  ---------- rNew
2273 
2274  7. ------------- rOld
2275  ---------- rNew
2276 
2277  8. ---------- rOld
2278  ------------- rNew
2279 
2280  9. ---------- rOld
2281  ---------- rNew
2282 */
2283 
2285 {
2287 
2288  if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos )
2289  eRet = NO_OVERLAP;
2290 
2291  // 1, 2, 3
2292  else if ( mnEndPos < rNew.mnEndPos )
2293  eRet = OVERLAP1;
2294 
2295  // 4, 5, 6, 7
2296  else if (mnStartPos <= rNew.mnStartPos)
2297  eRet = OVERLAP2;
2298 
2299  // 8, 9
2300  return eRet;
2301 }
2302 
2304 {
2305  bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const
2306  {
2307  return e1.mnStartPos < e2.mnStartPos;
2308  }
2309 };
2310 
2311 typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet;
2312 typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap;
2313 
2315 {
2316  SwLineEntryMap maVertLines;
2317  SwLineEntryMap maHoriLines;
2319 
2320  void Insert( SwLineEntry&, bool bHori );
2321  void Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect &rPaintArea);
2322  void HandleFrame(const SwLayoutFrame& rFrame, const SwRect& rPaintArea);
2323  void FindStylesForLine( const Point&,
2324  const Point&,
2326  bool bHori ) const;
2327 
2328 public:
2329  explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
2330 
2331  void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const;
2332 };
2333 
2335  : mrTabFrame( rTabFrame )
2336 {
2337  SwRect aPaintArea = rTabFrame.GetUpper()->GetPaintArea();
2338  HandleFrame(rTabFrame, aPaintArea);
2339 }
2340 
2341 void SwTabFramePainter::HandleFrame(const SwLayoutFrame& rLayoutFrame, const SwRect& rPaintArea)
2342 {
2343  // Add border lines of cell frames. Skip covered cells. Skip cells
2344  // in special row span row, which do not have a negative row span:
2345  if ( rLayoutFrame.IsCellFrame() && !rLayoutFrame.IsCoveredCell() )
2346  {
2347  const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rLayoutFrame);
2348  const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pThisCell->GetUpper());
2349  const long nRowSpan = pThisCell->GetTabBox()->getRowSpan();
2350  if ( !pRowFrame->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 )
2351  {
2352  SwBorderAttrAccess aAccess( SwFrame::GetCache(), &rLayoutFrame );
2353  const SwBorderAttrs& rAttrs = *aAccess.Get();
2354  const SvxBoxItem& rBox = rAttrs.GetBox();
2355  Insert(rLayoutFrame, rBox, rPaintArea);
2356  }
2357  }
2358 
2359  // Recurse into lower layout frames, but do not recurse into lower tabframes.
2360  const SwFrame* pLower = rLayoutFrame.Lower();
2361  while ( pLower )
2362  {
2363  const SwLayoutFrame* pLowerLayFrame = dynamic_cast<const SwLayoutFrame*>(pLower);
2364  if ( pLowerLayFrame && !pLowerLayFrame->IsTabFrame() )
2365  HandleFrame(*pLowerLayFrame, rPaintArea);
2366 
2367  pLower = pLower->GetNext();
2368  }
2369 }
2370 
2371 void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) const
2372 {
2373  // #i16816# tagged pdf support
2374  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev );
2375 
2376  SwLineEntryMap::const_iterator aIter = maHoriLines.begin();
2377  bool bHori = true;
2378 
2379  // color for subsidiary lines:
2381 
2382  // high contrast mode:
2383  // overrides the color of non-subsidiary lines.
2384  const Color* pHCColor = nullptr;
2385  DrawModeFlags nOldDrawMode = rDev.GetDrawMode();
2386  if( gProp.pSGlobalShell->GetWin() &&
2388  {
2389  pHCColor = &SwViewOption::GetFontColor();
2390  rDev.SetDrawMode( DrawModeFlags::Default );
2391  }
2392 
2393  const SwFrame* pUpper = mrTabFrame.GetUpper();
2394  SwRect aUpper( pUpper->getFramePrintArea() );
2395  aUpper.Pos() += pUpper->getFrameArea().Pos();
2396  SwRect aUpperAligned( aUpper );
2397  ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
2398 
2399  // prepare SdrFrameBorderDataVector
2400  std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
2401  std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
2402 
2403  while ( true )
2404  {
2405  if ( bHori && aIter == maHoriLines.end() )
2406  {
2407  aIter = maVertLines.begin();
2408  bHori = false;
2409  }
2410 
2411  if ( !bHori && aIter == maVertLines.end() )
2412  break;
2413 
2414  const SwLineEntrySet& rEntrySet = (*aIter).second;
2415  for (const SwLineEntry& rEntry : rEntrySet)
2416  {
2417  const svx::frame::Style& rEntryStyle( rEntry.maAttribute );
2418 
2419  Point aStart, aEnd;
2420  if ( bHori )
2421  {
2422  aStart.setX( rEntry.mnStartPos );
2423  aStart.setY( rEntry.mnKey );
2424  aEnd.setX( rEntry.mnEndPos );
2425  aEnd.setY( rEntry.mnKey );
2426  }
2427  else
2428  {
2429  aStart.setX( rEntry.mnKey );
2430  aStart.setY( rEntry.mnStartPos );
2431  aEnd.setX( rEntry.mnKey );
2432  aEnd.setY( rEntry.mnEndPos );
2433  }
2434 
2435  svx::frame::Style aStyles[ 7 ];
2436  aStyles[ 0 ] = rEntryStyle;
2437  FindStylesForLine( aStart, aEnd, aStyles, bHori );
2438  SwRect aRepaintRect( aStart, aEnd );
2439 
2440  // the repaint rectangle has to be moved a bit for the centered lines:
2441  SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth();
2442  if ( bHori )
2443  {
2444  aRepaintRect.Height( 2 * nRepaintRectSize );
2445  aRepaintRect.Pos().AdjustY( -nRepaintRectSize );
2446 
2447  // To decide on visibility it is also necessary to expand the RepaintRect
2448  // to left/right according existing BorderLine overlap matchings, else there
2449  // will be repaint errors when scrolling in e.t TripleLine BorderLines.
2450  // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB
2451  if(aStyles[1].IsUsed() || aStyles[3].IsUsed() || aStyles[4].IsUsed() || aStyles[6].IsUsed())
2452  {
2453  const double fLineWidthMaxLeft(std::max(aStyles[1].GetWidth(), aStyles[3].GetWidth()));
2454  const double fLineWidthMaxRight(std::max(aStyles[4].GetWidth(), aStyles[6].GetWidth()));
2455  aRepaintRect.Width(aRepaintRect.Width() + (fLineWidthMaxLeft + fLineWidthMaxRight));
2456  aRepaintRect.Pos().AdjustX( -fLineWidthMaxLeft );
2457  }
2458  }
2459  else
2460  {
2461  aRepaintRect.Width( 2 * nRepaintRectSize );
2462  aRepaintRect.Pos().AdjustX( -nRepaintRectSize );
2463 
2464  // Accordingly to horizontal case, but for top/bottom
2465  // aStyles[3] == aTFromR, aStyles[1] == aTFromL, aStyles[6] == aBFromR, aStyles[4] == aBFromL
2466  if(aStyles[3].IsUsed() || aStyles[1].IsUsed() || aStyles[6].IsUsed() || aStyles[4].IsUsed())
2467  {
2468  const double fLineWidthMaxTop(std::max(aStyles[3].GetWidth(), aStyles[1].GetWidth()));
2469  const double fLineWidthMaxBottom(std::max(aStyles[6].GetWidth(), aStyles[4].GetWidth()));
2470  aRepaintRect.Height(aRepaintRect.Height() + (fLineWidthMaxTop + fLineWidthMaxBottom));
2471  aRepaintRect.Pos().AdjustY( -fLineWidthMaxTop );
2472  }
2473  }
2474 
2475  if (!rRect.IsOver(aRepaintRect))
2476  {
2477  continue;
2478  }
2479 
2480  // subsidiary lines
2481  const Color* pTmpColor = nullptr;
2482  if (0 == aStyles[ 0 ].GetWidth())
2483  {
2484  if (isTableBoundariesEnabled() && gProp.pSGlobalShell->GetWin())
2485  aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 );
2486  else
2487  aStyles[0].SetType(SvxBorderLineStyle::NONE);
2488  }
2489  else
2490  pTmpColor = pHCColor;
2491 
2492  // The (twip) positions will be adjusted to meet these requirements:
2493  // 1. The y coordinates are located in the middle of the pixel grid
2494  // 2. The x coordinated are located at the beginning of the pixel grid
2495  // This is done, because the horizontal lines are painted "at
2496  // beginning", whereas the vertical lines are painted "centered".
2497  // By making the line sizes a multiple of one pixel size, we can
2498  // assure that all lines having the same twip size have the same
2499  // pixel size, independent of their position on the screen.
2500  Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel(aStart) );
2501  Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel(aEnd) );
2502 
2503  if (gProp.pSGlobalShell->GetWin())
2504  {
2505  // The table borders do not use SwAlignRect, but all the other frames do.
2506  // Therefore we tweak the outer borders a bit to achieve that the outer
2507  // borders match the subsidiary lines of the upper:
2508  if (aStart.X() == aUpper.Left())
2509  aPaintStart.setX( aUpperAligned.Left() );
2510  else if (aStart.X() == aUpper.Right_())
2511  aPaintStart.setX( aUpperAligned.Right_() );
2512  if (aStart.Y() == aUpper.Top())
2513  aPaintStart.setY( aUpperAligned.Top() );
2514  else if (aStart.Y() == aUpper.Bottom_())
2515  aPaintStart.setY( aUpperAligned.Bottom_() );
2516 
2517  if (aEnd.X() == aUpper.Left())
2518  aPaintEnd.setX( aUpperAligned.Left() );
2519  else if (aEnd.X() == aUpper.Right_())
2520  aPaintEnd.setX( aUpperAligned.Right_() );
2521  if (aEnd.Y() == aUpper.Top())
2522  aPaintEnd.setY( aUpperAligned.Top() );
2523  else if (aEnd.Y() == aUpper.Bottom_())
2524  aPaintEnd.setY( aUpperAligned.Bottom_() );
2525  }
2526 
2527  if(aStyles[0].IsUsed())
2528  {
2529  if (bHori)
2530  {
2531  const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2532  const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2533 
2534  if(!aX.equalZero())
2535  {
2537  aData->emplace_back(
2538  aOrigin,
2539  aX,
2540  aStyles[0],
2541  pTmpColor);
2542  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
2543 
2544  rInstance.addSdrConnectStyleData(true, aStyles[1], -aY, true); // aLFromT
2545  rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aLFromL
2546  rInstance.addSdrConnectStyleData(true, aStyles[3], aY, false); // aLFromB
2547 
2548  rInstance.addSdrConnectStyleData(false, aStyles[4], -aY, true); // aRFromT
2549  rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aRFromR
2550  rInstance.addSdrConnectStyleData(false, aStyles[6], aY, false); // aRFromB
2551  }
2552  }
2553  else // vertical
2554  {
2555  const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2556  const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2557 
2558  if(!aX.equalZero())
2559  {
2561  aData->emplace_back(
2562  aOrigin,
2563  aX,
2564  aStyles[0],
2565  pTmpColor);
2566  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
2567 
2568  rInstance.addSdrConnectStyleData(true, aStyles[3], -aY, false); // aTFromR
2569  rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aTFromT
2570  rInstance.addSdrConnectStyleData(true, aStyles[1], aY, true); // aTFromL
2571 
2572  rInstance.addSdrConnectStyleData(false, aStyles[6], -aY, false); // aBFromR
2573  rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aBFromB
2574  rInstance.addSdrConnectStyleData(false, aStyles[4], aY, true); // aBFromL
2575  }
2576  }
2577  }
2578  }
2579  ++aIter;
2580  }
2581 
2582  // create instance of SdrFrameBorderPrimitive2D if
2583  // SdrFrameBorderDataVector is used
2584  if(!aData->empty())
2585  {
2587  aSequence.append(
2590  aData,
2591  true, // try to merge results to have less primitivbes
2592  true))); // force visualization to minimal one discrete unit (pixel)
2593  // paint
2594  mrTabFrame.ProcessPrimitives(aSequence);
2595  }
2596 
2597  // restore output device:
2598  rDev.SetDrawMode( nOldDrawMode );
2599 }
2600 
2607  const Point& rEndPoint,
2608  svx::frame::Style* pStyles,
2609  bool bHori ) const
2610 {
2611  // pStyles[ 1 ] = bHori ? aLFromT : TFromL
2612  // pStyles[ 2 ] = bHori ? aLFromL : TFromT,
2613  // pStyles[ 3 ] = bHori ? aLFromB : TFromR,
2614  // pStyles[ 4 ] = bHori ? aRFromT : BFromL,
2615  // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
2616  // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
2617 
2618  SwLineEntryMap::const_iterator aMapIter = maVertLines.find( rStartPoint.X() );
2619  OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" );
2620  const SwLineEntrySet& rVertSet = (*aMapIter).second;
2621 
2622  for ( const SwLineEntry& rEntry : rVertSet )
2623  {
2624  if ( bHori )
2625  {
2626  if ( rStartPoint.Y() == rEntry.mnStartPos )
2627  pStyles[ 3 ] = rEntry.maAttribute;
2628  else if ( rStartPoint.Y() == rEntry.mnEndPos )
2629  pStyles[ 1 ] = rEntry.maAttribute;
2630  }
2631  else
2632  {
2633  if ( rStartPoint.Y() == rEntry.mnEndPos )
2634  pStyles[ 2 ] = rEntry.maAttribute;
2635  else if ( rEndPoint.Y() == rEntry.mnStartPos )
2636  pStyles[ 5 ] = rEntry.maAttribute;
2637  }
2638  }
2639 
2640  aMapIter = maHoriLines.find( rStartPoint.Y() );
2641  OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" );
2642  const SwLineEntrySet& rHoriSet = (*aMapIter).second;
2643 
2644  for ( const SwLineEntry& rEntry : rHoriSet )
2645  {
2646  if ( bHori )
2647  {
2648  if ( rStartPoint.X() == rEntry.mnEndPos )
2649  pStyles[ 2 ] = rEntry.maAttribute;
2650  else if ( rEndPoint.X() == rEntry.mnStartPos )
2651  pStyles[ 5 ] = rEntry.maAttribute;
2652  }
2653  else
2654  {
2655  if ( rStartPoint.X() == rEntry.mnEndPos )
2656  pStyles[ 1 ] = rEntry.maAttribute;
2657  else if ( rStartPoint.X() == rEntry.mnStartPos )
2658  pStyles[ 3 ] = rEntry.maAttribute;
2659  }
2660  }
2661 
2662  if ( bHori )
2663  {
2664  aMapIter = maVertLines.find( rEndPoint.X() );
2665  OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" );
2666  const SwLineEntrySet& rVertSet2 = (*aMapIter).second;
2667 
2668  for ( const SwLineEntry& rEntry : rVertSet2 )
2669  {
2670  if ( rEndPoint.Y() == rEntry.mnStartPos )
2671  pStyles[ 6 ] = rEntry.maAttribute;
2672  else if ( rEndPoint.Y() == rEntry.mnEndPos )
2673  pStyles[ 4 ] = rEntry.maAttribute;
2674  }
2675  }
2676  else
2677  {
2678  aMapIter = maHoriLines.find( rEndPoint.Y() );
2679  OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" );
2680  const SwLineEntrySet& rHoriSet2 = (*aMapIter).second;
2681 
2682  for ( const SwLineEntry& rEntry : rHoriSet2 )
2683  {
2684  if ( rEndPoint.X() == rEntry.mnEndPos )
2685  pStyles[ 4 ] = rEntry.maAttribute;
2686  else if ( rEndPoint.X() == rEntry.mnStartPos )
2687  pStyles[ 6 ] = rEntry.maAttribute;
2688  }
2689  }
2690 }
2691 
2697  SwTabFrame const& rTabFrame, SwFrame const& rFrame, SvxBoxItem const& rBoxItem)
2698 {
2699  SwRowFrame const*const pThisRowFrame =
2700  dynamic_cast<const SwRowFrame*>(rFrame.GetUpper());
2701  return (pThisRowFrame
2702  && (pThisRowFrame->GetUpper() == &rTabFrame)
2703  && rTabFrame.IsFollow()
2704  && !rTabFrame.GetTable()->GetRowsToRepeat()
2705  && ( !pThisRowFrame->GetPrev()
2706  || static_cast<const SwRowFrame*>(pThisRowFrame->GetPrev())
2707  ->IsRowSpanLine())
2708  && !rBoxItem.GetTop()
2709  && rBoxItem.GetBottom());
2710 }
2711 
2712 void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect& rPaintArea)
2713 {
2714  // build 4 line entries for the 4 borders:
2715  SwRect aBorderRect = rFrame.getFrameArea();
2716 
2717  aBorderRect.Intersection(rPaintArea);
2718 
2720  mrTabFrame, rFrame, rBoxItem));
2721  bool const bVert = mrTabFrame.IsVertical();
2722  bool const bR2L = mrTabFrame.IsRightToLeft();
2723 
2724  // no scaling needed, it's all in the primitives and the target device
2725  svx::frame::Style aL(rBoxItem.GetLeft(), 1.0);
2726  svx::frame::Style aR(rBoxItem.GetRight(), 1.0);
2727  svx::frame::Style aT(rBoxItem.GetTop(), 1.0);
2728  svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
2729 
2730  aR.MirrorSelf();
2731  aB.MirrorSelf();
2732 
2733  const SwTwips nLeft = aBorderRect.Left_();
2734  const SwTwips nRight = aBorderRect.Right_();
2735  const SwTwips nTop = aBorderRect.Top_();
2736  const SwTwips nBottom = aBorderRect.Bottom_();
2737 
2741  aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : svx::frame::RefMode::End );
2742 
2743  SwLineEntry aLeft (nLeft, nTop, nBottom,
2744  bVert ? aB : (bR2L ? aR : aL));
2745  SwLineEntry aRight (nRight, nTop, nBottom,
2746  bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
2747  SwLineEntry aTop (nTop, nLeft, nRight,
2748  bVert ? aL : (bBottomAsTop ? aB : aT));
2749  SwLineEntry aBottom(nBottom, nLeft, nRight,
2750  bVert ? aR : aB);
2751 
2752  Insert( aLeft, false );
2753  Insert( aRight, false );
2754  Insert( aTop, true );
2755  Insert( aBottom, true );
2756 }
2757 
2758 void SwTabFramePainter::Insert( SwLineEntry& rNew, bool bHori )
2759 {
2760  // get all lines from structure, that have key entry of pLE
2761  SwLineEntryMap* pLine2 = bHori ? &maHoriLines : &maVertLines;
2762  const SwTwips nKey = rNew.mnKey;
2763  SwLineEntryMap::iterator aMapIter = pLine2->find( nKey );
2764 
2765  SwLineEntrySet* pLineSet = aMapIter != pLine2->end() ? &((*aMapIter).second) : nullptr;
2766  if ( !pLineSet )
2767  {
2768  SwLineEntrySet aNewSet;
2769  (*pLine2)[ nKey ] = aNewSet;
2770  pLineSet = &(*pLine2)[ nKey ];
2771  }
2772  SwLineEntrySet::iterator aIter = pLineSet->begin();
2773 
2774  while ( aIter != pLineSet->end() && rNew.mnStartPos < rNew.mnEndPos )
2775  {
2776  const SwLineEntry& rOld = *aIter;
2777  const SwLineEntry::OverlapType nOverlapType = rOld.Overlaps( rNew );
2778 
2779  const svx::frame::Style& rOldAttr = rOld.maAttribute;
2780  const svx::frame::Style& rNewAttr = rNew.maAttribute;
2781  const svx::frame::Style& rCmpAttr = std::max(rNewAttr, rOldAttr);
2782 
2783  if ( SwLineEntry::OVERLAP1 == nOverlapType )
2784  {
2785  OSL_ENSURE( rNew.mnStartPos >= rOld.mnStartPos, "Overlap type 3? How this?" );
2786 
2787  // new left segment
2788  const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2789 
2790  // new middle segment
2791  const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rOld.mnEndPos, rCmpAttr );
2792 
2793  // new right segment
2794  rNew.mnStartPos = rOld.mnEndPos;
2795 
2796  // update current lines set
2797  pLineSet->erase( aIter );
2798  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2799  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2800 
2801  aIter = pLineSet->begin();
2802 
2803  continue; // start over
2804  }
2805  else if ( SwLineEntry::OVERLAP2 == nOverlapType )
2806  {
2807  // new left segment
2808  const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2809 
2810  // new middle segment
2811  const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rNew.mnEndPos, rCmpAttr );
2812 
2813  // new right segment
2814  const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2815 
2816  // update current lines set
2817  pLineSet->erase( aIter );
2818  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2819  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2820  if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2821 
2822  rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2823 
2824  break; // we are finished
2825  }
2826  else if ( SwLineEntry::OVERLAP3 == nOverlapType )
2827  {
2828  // new left segment
2829  const SwLineEntry aLeft( nKey, rNew.mnStartPos, rOld.mnStartPos, rNewAttr );
2830 
2831  // new middle segment
2832  const SwLineEntry aMiddle( nKey, rOld.mnStartPos, rNew.mnEndPos, rCmpAttr );
2833 
2834  // new right segment
2835  const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2836 
2837  // update current lines set
2838  pLineSet->erase( aIter );
2839  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2840  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2841  if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2842 
2843  rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2844 
2845  break; // we are finished
2846  }
2847 
2848  ++aIter;
2849  }
2850 
2851  if ( rNew.mnStartPos < rNew.mnEndPos ) // insert rest
2852  pLineSet->insert( rNew );
2853 }
2854 
2859 namespace
2860 {
2861  class SwViewObjectContactRedirector : public sdr::contact::ViewObjectContactRedirector
2862  {
2863  private:
2864  const SwViewShell& mrViewShell;
2865 
2866  public:
2867  explicit SwViewObjectContactRedirector( const SwViewShell& rSh )
2868  : mrViewShell( rSh )
2869  {};
2870 
2872  const sdr::contact::ViewObjectContact& rOriginal,
2873  const sdr::contact::DisplayInfo& rDisplayInfo) override
2874  {
2875  bool bPaint( true );
2876 
2877  SdrObject* pObj = rOriginal.GetViewContact().TryToGetSdrObject();
2878  if ( pObj )
2879  {
2880  bPaint = SwFlyFrame::IsPaint( pObj, &mrViewShell );
2881  }
2882 
2883  if ( !bPaint )
2884  {
2886  }
2887 
2889  rOriginal, rDisplayInfo );
2890  }
2891  };
2892 
2893 } // end of anonymous namespace
2894 // <--
2895 
2905 void SwRootFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const pPrintData) const
2906 {
2907  OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." );
2908 
2909  PROTOCOL( this, PROT::FileInit, DbgAction::NONE, nullptr)
2910 
2911  bool bResetRootPaint = false;
2912  SwViewShell *pSh = mpCurrShell;
2913 
2914  if ( pSh->GetWin() )
2915  {
2916  if ( pSh->GetOut() == pSh->GetWin() && !pSh->GetWin()->IsVisible() )
2917  {
2918  return;
2919  }
2921  {
2922  SwPaintQueue::Add( pSh, rRect );
2923  return;
2924  }
2925  }
2926  else
2927  SwRootFrame::s_isInPaint = bResetRootPaint = true;
2928 
2929  std::unique_ptr<SwSavePaintStatics> pStatics;
2930  if ( gProp.pSGlobalShell )
2931  pStatics.reset(new SwSavePaintStatics());
2932  gProp.pSGlobalShell = pSh;
2933 
2934  if( !pSh->GetWin() )
2935  gProp.pSProgress = SfxProgress::GetActiveProgress( static_cast<SfxObjectShell*>(pSh->GetDoc()->GetDocShell()) );
2936 
2937  ::SwCalcPixStatics( pSh->GetOut() );
2938  aGlobalRetoucheColor = pSh->Imp()->GetRetoucheColor();
2939 
2940  // Copy rRect; for one, rRect could become dangling during the below action, and for another it
2941  // needs to be copied to aRect anyway as that is modified further down below:
2942  SwRect aRect( rRect );
2943 
2944  //Trigger an action to clear things up if needed.
2945  //Using this trick we can ensure that all values are valid in all paints -
2946  //no problems, no special case(s).
2947  // #i92745#
2948  // Extend check on certain states of the 'current' <SwViewShell> instance to
2949  // all existing <SwViewShell> instances.
2950  bool bPerformLayoutAction( true );
2951  {
2952  for(SwViewShell& rTmpViewShell : pSh->GetRingContainer())
2953  {
2954  if ( rTmpViewShell.IsInEndAction() ||
2955  rTmpViewShell.IsPaintInProgress() ||
2956  ( rTmpViewShell.Imp()->IsAction() &&
2957  rTmpViewShell.Imp()->GetLayAction().IsActionInProgress() ) )
2958  {
2959  bPerformLayoutAction = false;
2960  }
2961 
2962  if(!bPerformLayoutAction)
2963  break;
2964  }
2965  }
2966  if ( bPerformLayoutAction )
2967  {
2968  const_cast<SwRootFrame*>(this)->ResetTurbo();
2969  SwLayAction aAction( const_cast<SwRootFrame*>(this), pSh->Imp() );
2970  aAction.SetPaint( false );
2971  aAction.SetComplete( false );
2972  aAction.SetReschedule( gProp.pSProgress != nullptr );
2973  aAction.Action(&rRenderContext);
2974  ResetTurboFlag();
2975  if ( !pSh->ActionPend() )
2976  pSh->Imp()->DelRegion();
2977  }
2978 
2979  aRect.Intersection( pSh->VisArea() );
2980 
2981  const bool bExtraData = ::IsExtraData( GetFormat()->GetDoc() );
2982 
2983  gProp.pSLines.reset(new SwLineRects); // Container for borders.
2984 
2985  // #104289#. During painting, something (OLE) can
2986  // load the linguistic, which in turn can cause a reformat
2987  // of the document. Dangerous! We better set this flag to
2988  // avoid the reformat.
2989  const bool bOldAction = IsCallbackActionEnabled();
2990  const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( false );
2991 
2992  const SwPageFrame *pPage = pSh->Imp()->GetFirstVisPage(&rRenderContext);
2993 
2994  // #126222. The positions of headers and footers of the previous
2995  // pages have to be updated, else these headers and footers could
2996  // get visible at a wrong position.
2997  const SwPageFrame *pPageDeco = static_cast<const SwPageFrame*>(pPage->GetPrev());
2998  while (pPageDeco)
2999  {
3000  pPageDeco->PaintDecorators();
3001  OSL_ENSURE(!pPageDeco->GetPrev() || pPageDeco->GetPrev()->IsPageFrame(),
3002  "Neighbour of page is not a page.");
3003  pPageDeco = static_cast<const SwPageFrame*>(pPageDeco->GetPrev());
3004  }
3005 
3006  const bool bBookMode = gProp.pSGlobalShell->GetViewOptions()->IsViewLayoutBookMode();
3007  if ( bBookMode && pPage->GetPrev() && static_cast<const SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
3008  pPage = static_cast<const SwPageFrame*>(pPage->GetPrev());
3009 
3010  // #i68597#
3011  const bool bGridPainting(pSh->GetWin() && pSh->Imp()->HasDrawView() && pSh->Imp()->GetDrawView()->IsGridVisible());
3012 
3013  // Hide all page break controls before showing them again
3014  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3015  if ( pWrtSh )
3016  {
3017  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3018  SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3019  const SwPageFrame* pHiddenPage = pPage;
3020  while ( pHiddenPage->GetPrev() != nullptr )
3021  {
3022  pHiddenPage = static_cast< const SwPageFrame* >( pHiddenPage->GetPrev() );
3023  SwFrameControlPtr pControl = rMngr.GetControl( PageBreak, pHiddenPage );
3024  if ( pControl.get() )
3025  pControl->ShowAll( false );
3026  }
3027  }
3028 
3029  // #i76669#
3030  SwViewObjectContactRedirector aSwRedirector( *pSh );
3031 
3032  while ( pPage )
3033  {
3034  const bool bPaintRightShadow = pPage->IsRightShadowNeeded();
3035  const bool bPaintLeftShadow = pPage->IsLeftShadowNeeded();
3036  const bool bRightSidebar = pPage->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
3037 
3038  if ( !pPage->IsEmptyPage() )
3039  {
3040  SwRect aPaintRect;
3041  SwPageFrame::GetBorderAndShadowBoundRect( pPage->getFrameArea(), pSh, &rRenderContext, aPaintRect,
3042  bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3043 
3044  if ( aRect.IsOver( aPaintRect ) )
3045  {
3046  if ( pSh->GetWin() )
3047  {
3048  gProp.pSSubsLines.reset(new SwSubsRects);
3049  gProp.pSSpecSubsLines.reset(new SwSubsRects);
3050  }
3051  gProp.pBLines.reset(new BorderLines);
3052 
3053  aPaintRect.Intersection_( aRect );
3054 
3055  if ( bExtraData &&
3056  pSh->GetWin() && pSh->IsInEndAction() )
3057  {
3058  // enlarge paint rectangle to complete page width, subtract
3059  // current paint area and invalidate the resulting region.
3060  SwRectFnSet aRectFnSet(pPage);
3061  SwRect aPageRectTemp( aPaintRect );
3062  aRectFnSet.SetLeftAndWidth( aPageRectTemp,
3063  aRectFnSet.GetLeft(pPage->getFrameArea()),
3064  aRectFnSet.GetWidth(pPage->getFrameArea()) );
3065  aPageRectTemp.Intersection_( pSh->VisArea() );
3066  vcl::Region aPageRectRegion( aPageRectTemp.SVRect() );
3067  aPageRectRegion.Exclude( aPaintRect.SVRect() );
3068  pSh->GetWin()->Invalidate( aPageRectRegion, InvalidateFlags::Children );
3069  }
3070 
3071  // #i80793#
3072  // enlarge paint rectangle for objects overlapping the same pixel
3073  // in all cases and before the DrawingLayer overlay is initialized.
3074  lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3075 
3076  // #i68597#
3077  // moved paint pre-process for DrawingLayer overlay here since the above
3078  // code dependent from bExtraData may expand the PaintRect
3079  {
3080  // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3081  // really be used but handled by SwViewShell::ImplEndAction already
3082  const vcl::Region aDLRegion(aPaintRect.SVRect());
3083  pSh->DLPrePaint2(aDLRegion);
3084  }
3085 
3086  if(OUTDEV_WINDOW == gProp.pSGlobalShell->GetOut()->GetOutDevType())
3087  {
3088  // OD 27.09.2002 #103636# - changed method SwLayVout::Enter(..)
3089  // 2nd parameter is no longer <const> and will be set to the
3090  // rectangle the virtual output device is calculated from <aPaintRect>,
3091  // if the virtual output is used.
3092  s_pVout->Enter(pSh, aPaintRect, !s_isNoVirDev);
3093 
3094  // OD 27.09.2002 #103636# - adjust paint rectangle to pixel size
3095  // Thus, all objects overlapping on pixel level with the unadjusted
3096  // paint rectangle will be considered in the paint.
3097  lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3098  }
3099 
3100  // maybe this can be put in the above scope. Since we are not sure, just leave it ATM
3101  s_pVout->SetOrgRect( aPaintRect );
3102 
3103  // OD 29.08.2002 #102450#
3104  // determine background color of page for <PaintLayer> method
3105  // calls, paint <hell> or <heaven>
3106  const Color aPageBackgrdColor(pPage->GetDrawBackgrdColor());
3107 
3108  pPage->PaintBaBo( aPaintRect, pPage );
3109 
3110  if ( pSh->Imp()->HasDrawView() )
3111  {
3112  gProp.pSLines->LockLines( true );
3114  pSh->Imp()->PaintLayer( rIDDMA.GetHellId(),
3115  pPrintData,
3116  *pPage, pPage->getFrameArea(),
3117  &aPageBackgrdColor,
3118  pPage->IsRightToLeft(),
3119  &aSwRedirector );
3120  gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3121  gProp.pSLines->LockLines( false );
3122  }
3123 
3125  pPage->PaintBaBo( aPaintRect, pPage, /*bOnlyTextBackground=*/true );
3126 
3127  if( pSh->GetWin() )
3128  {
3129  // collect sub-lines
3130  pPage->RefreshSubsidiary( aPaintRect );
3131  // paint special sub-lines
3132  gProp.pSSpecSubsLines->PaintSubsidiary( pSh->GetOut(), nullptr, gProp );
3133  }
3134 
3135  pPage->PaintSwFrame( rRenderContext, aPaintRect );
3136 
3137  // no paint of page border and shadow, if writer is in place mode.
3138  if( pSh->GetWin() && pSh->GetDoc()->GetDocShell() &&
3139  !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3140  {
3141  SwPageFrame::PaintBorderAndShadow( pPage->getFrameArea(), pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3142  SwPageFrame::PaintNotesSidebar( pPage->getFrameArea(), pSh, pPage->GetPhyPageNum(), bRightSidebar);
3143  }
3144 
3145  gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3146  if ( pSh->GetWin() )
3147  {
3148  gProp.pSSubsLines->PaintSubsidiary( pSh->GetOut(), gProp.pSLines.get(), gProp );
3149  gProp.pSSubsLines.reset();
3150  gProp.pSSpecSubsLines.reset();
3151  }
3152  // fdo#42750: delay painting these until after subsidiary lines
3153  // fdo#45562: delay painting these until after hell layer
3154  // fdo#47717: but do it before heaven layer
3155  ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
3156 
3157  if ( pSh->Imp()->HasDrawView() )
3158  {
3159  // OD 29.08.2002 #102450# - add 3rd parameter
3160  // OD 09.12.2002 #103045# - add 4th parameter for horizontal text direction.
3162  pPrintData,
3163  *pPage, pPage->getFrameArea(),
3164  &aPageBackgrdColor,
3165  pPage->IsRightToLeft(),
3166  &aSwRedirector );
3167  }
3168 
3169  if ( bExtraData )
3170  pPage->RefreshExtraData( aPaintRect );
3171 
3172  gProp.pBLines.reset();
3173  s_pVout->Leave();
3174 
3175  // #i68597#
3176  // needed to move grid painting inside Begin/EndDrawLayer bounds and to change
3177  // output rect for it accordingly
3178  if(bGridPainting)
3179  {
3180  SdrPaintView* pPaintView = pSh->Imp()->GetDrawView();
3181  SdrPageView* pPageView = pPaintView->GetSdrPageView();
3182  pPageView->DrawPageViewGrid(*pSh->GetOut(), aPaintRect.SVRect(), SwViewOption::GetTextGridColor() );
3183  }
3184 
3185  // #i68597#
3186  // moved paint post-process for DrawingLayer overlay here, see above
3187  {
3188  pSh->DLPostPaint2(true);
3189  }
3190  }
3191 
3192  pPage->PaintDecorators( );
3193  pPage->PaintBreak();
3194  }
3195  else if ( bBookMode && pSh->GetWin() && !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3196  {
3197  // paint empty page
3198  SwRect aPaintRect;
3199  SwRect aEmptyPageRect( pPage->getFrameArea() );
3200 
3201  // code from vprint.cxx
3202  const SwPageFrame& rFormatPage = pPage->GetFormatPage();
3203  aEmptyPageRect.SSize() = rFormatPage.getFrameArea().SSize();
3204 
3205  SwPageFrame::GetBorderAndShadowBoundRect( aEmptyPageRect, pSh, &rRenderContext, aPaintRect,
3206  bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3207  aPaintRect.Intersection_( aRect );
3208 
3209  if ( aRect.IsOver( aEmptyPageRect ) )
3210  {
3211  // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3212  // really be used but handled by SwViewShell::ImplEndAction already
3213  {
3214  const vcl::Region aDLRegion(aPaintRect.SVRect());
3215  pSh->DLPrePaint2(aDLRegion);
3216  }
3217 
3218  if( pSh->GetOut()->GetFillColor() != aGlobalRetoucheColor )
3219  pSh->GetOut()->SetFillColor( aGlobalRetoucheColor );
3220 
3221  pSh->GetOut()->SetLineColor(); // OD 20.02.2003 #107369# - no line color
3222  // OD 20.02.2003 #107369# - use aligned page rectangle
3223  {
3224  SwRect aTmpPageRect( aEmptyPageRect );
3225  ::SwAlignRect( aTmpPageRect, pSh, &rRenderContext );
3226  aEmptyPageRect = aTmpPageRect;
3227  }
3228 
3229  pSh->GetOut()->DrawRect( aEmptyPageRect.SVRect() );
3230 
3231  // paint empty page text
3232  const vcl::Font& rEmptyPageFont = SwPageFrame::GetEmptyPageFont();
3233  const vcl::Font aOldFont( pSh->GetOut()->GetFont() );
3234 
3235  pSh->GetOut()->SetFont( rEmptyPageFont );
3236  pSh->GetOut()->DrawText( aEmptyPageRect.SVRect(), SwResId( STR_EMPTYPAGE ),
3237  DrawTextFlags::VCenter |
3238  DrawTextFlags::Center |
3239  DrawTextFlags::Clip );
3240 
3241  pSh->GetOut()->SetFont( aOldFont );
3242  // paint shadow and border for empty page
3243  // OD 19.02.2003 #107369# - use new method to paint page border and
3244  // shadow
3245  SwPageFrame::PaintBorderAndShadow( aEmptyPageRect, pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3246  SwPageFrame::PaintNotesSidebar( aEmptyPageRect, pSh, pPage->GetPhyPageNum(), bRightSidebar);
3247 
3248  {
3249  pSh->DLPostPaint2(true);
3250  }
3251  }
3252  }
3253 
3254  OSL_ENSURE( !pPage->GetNext() || pPage->GetNext()->IsPageFrame(),
3255  "Neighbour of page is not a page." );
3256  pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
3257  }
3258 
3259  gProp.pSLines.reset();
3260 
3261  if ( bResetRootPaint )
3262  SwRootFrame::s_isInPaint = false;
3263  if ( pStatics )
3264  pStatics.reset();
3265  else
3266  {
3267  gProp.pSProgress = nullptr;
3268  gProp.pSGlobalShell = nullptr;
3269  }
3270 
3271  const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( bOldAction );
3272 }
3273 
3275 {
3276  vcl::RenderContext* pRenderContext = pCont->getRootFrame()->GetCurrShell()->GetOut();
3277 
3278  //It's possible that the Cont will get destroyed.
3279  SwContentFrame *pCnt = pCont->ContainsContent();
3280  while ( pCnt && pCnt->IsInFootnote() )
3281  {
3282  pCnt->Calc(pRenderContext);
3283  pCnt = pCnt->GetNextContentFrame();
3284  }
3285 }
3286 
3288 {
3290  long nLimit;
3291 public:
3292  SwShortCut( const SwFrame& rFrame, const SwRect& rRect );
3293  bool Stop( const SwRect& rRect ) const
3294  { return (rRect.*fnCheck)( nLimit ) > 0; }
3295 };
3296 
3297 SwShortCut::SwShortCut( const SwFrame& rFrame, const SwRect& rRect )
3298 {
3299  bool bVert = rFrame.IsVertical();
3300  bool bR2L = rFrame.IsRightToLeft();
3301  if( rFrame.IsNeighbourFrame() && bVert == bR2L )
3302  {
3303  if( bVert )
3304  {
3306  nLimit = rRect.Top();
3307  }
3308  else
3309  {
3311  nLimit = rRect.Left() + rRect.Width();
3312  }
3313  }
3314  else if( bVert == rFrame.IsNeighbourFrame() )
3315  {
3317  nLimit = rRect.Top() + rRect.Height();
3318  }
3319  else
3320  {
3321  if ( rFrame.IsVertLR() )
3322  {
3324  nLimit = rRect.Right();
3325  }
3326  else
3327  {
3329  nLimit = rRect.Left();
3330  }
3331  }
3332 }
3333 
3334 void SwLayoutFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3335 {
3336  // #i16816# tagged pdf support
3337  Frame_Info aFrameInfo( *this );
3338  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, &aFrameInfo, nullptr, rRenderContext );
3339 
3340  const SwFrame *pFrame = Lower();
3341  if ( !pFrame )
3342  return;
3343 
3344  SwFrameDeleteGuard g(const_cast<SwLayoutFrame*>(this)); // lock because Calc() and recursion
3345  SwShortCut aShortCut( *pFrame, rRect );
3346  bool bCnt = pFrame->IsContentFrame();
3347  if ( bCnt )
3348  pFrame->Calc(&rRenderContext);
3349 
3350  if ( pFrame->IsFootnoteContFrame() )
3351  {
3352  ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame)) );
3353  pFrame = Lower();
3354  }
3355 
3356  const SwPageFrame *pPage = nullptr;
3357  bool bWin = gProp.pSGlobalShell->GetWin() != nullptr;
3359  // Tiled rendering is similar to printing in this case: painting transparently multiple
3360  // times will result in darker colors: avoid that.
3361  bWin = false;
3362 
3363  while ( IsAnLower( pFrame ) )
3364  {
3365  SwRect aPaintRect( pFrame->GetPaintArea() );
3366  if( aShortCut.Stop( aPaintRect ) )
3367  break;
3368  if ( bCnt && gProp.pSProgress )
3370 
3371  //We need to retouch if a frame explicitly requests it.
3372  //First do the retouch, because this could flatten the borders.
3373  if ( pFrame->IsRetouche() )
3374  {
3375  if ( pFrame->IsRetoucheFrame() && bWin && !pFrame->GetNext() )
3376  {
3377  if ( !pPage )
3378  pPage = FindPageFrame();
3379  pFrame->Retouch( pPage, rRect );
3380  }
3381  pFrame->ResetRetouche();
3382  }
3383 
3384  if ( rRect.IsOver( aPaintRect ) )
3385  {
3386  if ( bCnt && pFrame->IsCompletePaint() &&
3387  !rRect.IsInside( aPaintRect ) && Application::AnyInput( VclInputFlags::KEYBOARD ) )
3388  {
3389  //fix(8104): It may happen, that the processing wasn't complete
3390  //but some parts of the paragraph were still repainted.
3391  //This could lead to the situation, that other parts of the
3392  //paragraph won't be repainted at all. The only solution seems
3393  //to be an invalidation of the window.
3394  //To not make it too severe the rectangle is limited by
3395  //painting the desired part and only invalidating the
3396  //remaining paragraph parts.
3397  if ( aPaintRect.Left() == rRect.Left() &&
3398  aPaintRect.Right() == rRect.Right() )
3399  {
3400  aPaintRect.Bottom( rRect.Top() - 1 );
3401  if ( aPaintRect.Height() > 0 )
3402  gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3403  aPaintRect.Top( rRect.Bottom() + 1 );
3404  aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3405  if ( aPaintRect.Height() > 0 )
3406  gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3407  aPaintRect.Top( pFrame->getFrameArea().Top() );
3408  aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3409  }
3410  else
3411  {
3412  gProp.pSGlobalShell->InvalidateWindows( aPaintRect );
3413  pFrame = pFrame->GetNext();
3414  if ( pFrame )
3415  {
3416  bCnt = pFrame->IsContentFrame();
3417  if ( bCnt )
3418  pFrame->Calc(&rRenderContext);
3419  }
3420  continue;
3421  }
3422  }
3423  pFrame->ResetCompletePaint();
3424  aPaintRect.Intersection_( rRect );
3425 
3426  pFrame->PaintSwFrame( rRenderContext, aPaintRect );
3427 
3428  if ( Lower() && Lower()->IsColumnFrame() )
3429  {
3430  //Paint the column separator line if needed. The page is
3431  //responsible for the page frame - not the upper.
3432  const SwFrameFormat *pFormat = GetUpper() && GetUpper()->IsPageFrame()
3433  ? GetUpper()->GetFormat()
3434  : GetFormat();
3435  const SwFormatCol &rCol = pFormat->GetCol();
3436  if ( rCol.GetLineAdj() != COLADJ_NONE )
3437  {
3438  if ( !pPage )
3439  pPage = pFrame->FindPageFrame();
3440 
3441  PaintColLines( aPaintRect, rCol, pPage );
3442  }
3443  }
3444  }
3445  if ( !bCnt && pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame() )
3446  ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame->GetNext())) );
3447 
3448  pFrame = pFrame->GetNext();
3449 
3450  if ( pFrame )
3451  {
3452  bCnt = pFrame->IsContentFrame();
3453  if ( bCnt )
3454  pFrame->Calc(&rRenderContext);
3455  }
3456  }
3457 }
3458 
3460  const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
3461  basegfx::BColor aColor )
3462 {
3464 
3465  std::vector< double > aStrokePattern;
3466  basegfx::B2DPolygon aLinePolygon;
3467  aLinePolygon.append(rStart);
3468  aLinePolygon.append(rEnd);
3469 
3471  if ( rSettings.GetHighContrastMode( ) )
3472  {
3473  // Only a solid line in high contrast mode
3474  aColor = rSettings.GetDialogTextColor().getBColor();
3475  }
3476  else
3477  {
3478  // Get a color for the contrast
3479  basegfx::BColor aHslLine = basegfx::utils::rgb2hsl( aColor );
3480  double nLuminance = aHslLine.getZ() * 2.5;
3481  if ( nLuminance == 0 )
3482  nLuminance = 0.5;
3483  else if ( nLuminance >= 1.0 )
3484  nLuminance = aHslLine.getZ() * 0.4;
3485  aHslLine.setZ( nLuminance );
3486  const basegfx::BColor aOtherColor = basegfx::utils::hsl2rgb( aHslLine );
3487 
3488  // Compute the plain line
3491  aLinePolygon, aOtherColor );
3492 
3493  aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( pPlainLine );
3494 
3495  // Dashed line in twips
3496  aStrokePattern.push_back( 40 );
3497  aStrokePattern.push_back( 40 );
3498 
3499  aSeq.resize( 2 );
3500  }
3501 
3502  // Compute the dashed line primitive
3505  basegfx::B2DPolyPolygon( aLinePolygon ),
3507  drawinglayer::attribute::StrokeAttribute( aStrokePattern ) );
3508 
3509  aSeq[ aSeq.size( ) - 1 ] = drawinglayer::primitive2d::Primitive2DReference( pLine );
3510 
3511  return aSeq;
3512 }
3513 
3515 {
3516  if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() != OUTDEV_PRINTER &&
3517  !gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() &&
3518  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
3519  !gProp.pSGlobalShell->IsPreview() )
3520  {
3521  const SwFrame* pBodyFrame = Lower();
3522  while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3523  pBodyFrame = pBodyFrame->GetNext();
3524 
3525  if ( pBodyFrame )
3526  {
3527  const SwLayoutFrame* pLayBody = static_cast< const SwLayoutFrame* >( pBodyFrame );
3528  const SwFlowFrame *pFlowFrame = pLayBody->ContainsContent();
3529 
3530  // Test if the first node is a table
3531  const SwFrame* pFirstFrame = pLayBody->Lower();
3532  if ( pFirstFrame && pFirstFrame->IsTabFrame() )
3533  pFlowFrame = static_cast< const SwTabFrame* >( pFirstFrame );
3534 
3535  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3536  if ( pWrtSh )
3537  {
3538  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3539  SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3540 
3541  if ( pFlowFrame && pFlowFrame->IsPageBreak( true ) )
3542  rMngr.SetPageBreakControl( this );
3543  else
3544  rMngr.RemoveControlsByType( PageBreak, this );
3545  }
3546  }
3548  }
3549 }
3550 
3552 {
3553  if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() != OUTDEV_PRINTER &&
3554  !gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() &&
3555  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
3556  !gProp.pSGlobalShell->IsPreview() )
3557  {
3558  const SwFrame* pBodyFrame = Lower();
3559  while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3560  pBodyFrame = pBodyFrame->GetNext();
3561 
3562  if ( pBodyFrame )
3563  {
3564  const SwContentFrame *pCnt = static_cast< const SwLayoutFrame* >( pBodyFrame )->ContainsContent();
3565  if ( pCnt && pCnt->IsColBreak( true ) )
3566  {
3567  // Paint the break only if:
3568  // * Not in header footer edition, to avoid conflicts with the
3569  // header/footer marker
3570  // * Non-printing characters are shown, as this is more consistent
3571  // with other formatting marks
3575  {
3576  SwRect aRect( pCnt->getFramePrintArea() );
3577  aRect.Pos() += pCnt->getFrameArea().Pos();
3578 
3579  // Draw the line
3580  basegfx::B2DPoint aStart( double( aRect.Left() ), aRect.Top() );
3581  basegfx::B2DPoint aEnd( double( aRect.Right() ), aRect.Top() );
3582  double nWidth = aRect.Width();
3583  if ( IsVertical( ) )
3584  {
3585  aStart = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Top() ) );
3586  aEnd = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Bottom() ) );
3587  nWidth = aRect.Height();
3588  }
3589 
3591 
3593  lcl_CreateDashedIndicatorPrimitive( aStart, aEnd, aLineColor );
3594 
3595  // Add the text above
3596  OUString aBreakText = SwResId(STR_COLUMN_BREAK);
3597 
3598  basegfx::B2DVector aFontSize;
3599  OutputDevice* pOut = gProp.pSGlobalShell->GetOut();
3600  vcl::Font aFont = pOut->GetSettings().GetStyleSettings().GetToolFont();
3601  aFont.SetFontHeight( 8 * 20 );
3602  pOut->SetFont( aFont );
3604  aFontSize, aFont, IsRightToLeft(), false );
3605 
3606  tools::Rectangle aTextRect;
3607  pOut->GetTextBoundRect( aTextRect, aBreakText );
3608  long nTextOff = ( nWidth - aTextRect.GetWidth() ) / 2;
3609 
3611  aFontSize.getX(), aFontSize.getY(),
3612  aRect.Left() + nTextOff, aRect.Top() ) );
3613  if ( IsVertical() )
3614  {
3616  aFontSize.getX(), aFontSize.getY(), 0.0, M_PI_2,
3617  aRect.Right(), aRect.Top() + nTextOff );
3618  }
3619 
3622  aTextMatrix,
3623  aBreakText, 0, aBreakText.getLength(),
3624  std::vector< double >(),
3625  aFontAttr,
3626  lang::Locale(),
3627  aLineColor );
3628  aSeq.push_back( drawinglayer::primitive2d::Primitive2DReference( pText ) );
3629 
3630  ProcessPrimitives( aSeq );
3631  }
3632  }
3633  }
3634  }
3635 }
3636 
3638 {
3639  const SwFrame* pFrame = Lower();
3640  while ( pFrame )
3641  {
3642  if ( pFrame->IsLayoutFrame() )
3643  static_cast< const SwLayoutFrame*>( pFrame )->PaintBreak( );
3644  pFrame = pFrame->GetNext();
3645  }
3646 }
3647 
3649 {
3650  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3651  if ( pWrtSh )
3652  {
3653  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3654 
3655  const SwLayoutFrame* pBody = FindBodyCont();
3656  if ( pBody )
3657  {
3658  SwRect aBodyRect( pBody->getFrameArea() );
3659 
3660  if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() != OUTDEV_PRINTER &&
3661  !gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() &&
3662  !gProp.pSGlobalShell->IsPreview() &&
3663  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
3667  {
3668  bool bRtl = AllSettings::GetLayoutRTL();
3669  const SwRect& rVisArea = gProp.pSGlobalShell->VisArea();
3670  long nXOff = std::min( aBodyRect.Right(), rVisArea.Right() );
3671  if ( bRtl )
3672  nXOff = std::max( aBodyRect.Left(), rVisArea.Left() );
3673 
3674  // Header
3676  {
3677  const SwFrame* pHeaderFrame = Lower();
3678  if ( !pHeaderFrame->IsHeaderFrame() )
3679  pHeaderFrame = nullptr;
3680 
3681  long nHeaderYOff = aBodyRect.Top();
3682  Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nHeaderYOff ) );
3683  rEditWin.GetFrameControlsManager().SetHeaderFooterControl( this, Header, nOutputOff );
3684  }
3685 
3686  // Footer
3688  {
3689  const SwFrame* pFootnoteContFrame = Lower();
3690  while ( pFootnoteContFrame )
3691  {
3692  if ( pFootnoteContFrame->IsFootnoteContFrame() )
3693  aBodyRect.AddBottom( pFootnoteContFrame->getFrameArea().Bottom() - aBodyRect.Bottom() );
3694  pFootnoteContFrame = pFootnoteContFrame->GetNext();
3695  }
3696 
3697  long nFooterYOff = aBodyRect.Bottom();
3698  Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nFooterYOff ) );
3699  rEditWin.GetFrameControlsManager().SetHeaderFooterControl( this, Footer, nOutputOff );
3700  }
3701  }
3702  }
3703  }
3704 }
3705 
3720 {
3721  bool bBackgroundTransparent = GetFormat()->IsBackgroundTransparent();
3722  if ( !bBackgroundTransparent &&
3723  GetFormat()->IsBackgroundBrushInherited() )
3724  {
3725  const SvxBrushItem* pBackgrdBrush = nullptr;
3726  const Color* pSectionTOXColor = nullptr;
3727  SwRect aDummyRect;
3729 
3730  if ( GetBackgroundBrush( aFillAttributes, pBackgrdBrush, pSectionTOXColor, aDummyRect, false, /*bConsiderTextBox=*/false) )
3731  {
3732  if ( pSectionTOXColor &&
3733  (pSectionTOXColor->GetTransparency() != 0) &&
3734  (*pSectionTOXColor != COL_TRANSPARENT) )
3735  {
3736  bBackgroundTransparent = true;
3737  }
3738  else if(aFillAttributes.get() && aFillAttributes->isUsed())
3739  {
3740  bBackgroundTransparent = aFillAttributes->isTransparent();
3741  }
3742  else if ( pBackgrdBrush )
3743  {
3744  if ( (pBackgrdBrush->GetColor().GetTransparency() != 0) &&
3745  (pBackgrdBrush->GetColor() != COL_TRANSPARENT) )
3746  {
3747  bBackgroundTransparent = true;
3748  }
3749  else
3750  {
3751  const GraphicObject *pTmpGrf =
3752  pBackgrdBrush->GetGraphicObject();
3753  if ( pTmpGrf &&
3754  (pTmpGrf->GetAttr().GetTransparency() != 0)
3755  )
3756  {
3757  bBackgroundTransparent = true;
3758  }
3759  }
3760  }
3761  }
3762  }
3763 
3764  return bBackgroundTransparent;
3765 };
3766 
3767 bool SwFlyFrame::IsPaint( SdrObject *pObj, const SwViewShell *pSh )
3768 {
3769  SdrObjUserCall *pUserCall;
3770 
3771  if ( nullptr == ( pUserCall = GetUserCall(pObj) ) )
3772  return true;
3773 
3774  //Attribute dependent, don't paint for printer or Preview
3775  bool bPaint = gProp.pSFlyOnlyDraw ||
3776  static_cast<SwContact*>(pUserCall)->GetFormat()->GetPrint().GetValue();
3777  if ( !bPaint )
3778  bPaint = pSh->GetWin() && !pSh->IsPreview();
3779 
3780  if ( bPaint )
3781  {
3782  //The paint may be prevented by the superior Flys.
3783  SwFrame *pAnch = nullptr;
3784  if ( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr ) // i#117962#
3785  {
3786  bPaint = false;
3787  }
3788  if ( dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) != nullptr )
3789  {
3790  SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
3791  if ( gProp.pSFlyOnlyDraw && gProp.pSFlyOnlyDraw == pFly )
3792  return true;
3793 
3794  //Try to avoid displaying the intermediate stage, Flys which don't
3795  //overlap with the page on which they are anchored won't be
3796  //painted.
3797  //HACK: exception: printing of frames in tables, those can overlap
3798  //a page once in a while when dealing with oversized tables (HTML).
3799  SwPageFrame *pPage = pFly->FindPageFrame();
3800  if ( pPage && pPage->getFrameArea().IsOver( pFly->getFrameArea() ) )
3801  {
3802  pAnch = pFly->AnchorFrame();
3803  }
3804 
3805  }
3806  else
3807  {
3808  // OD 13.10.2003 #i19919# - consider 'virtual' drawing objects
3809  // OD 2004-03-29 #i26791#
3810  SwDrawContact* pDrawContact = dynamic_cast<SwDrawContact*>(pUserCall);
3811  pAnch = pDrawContact ? pDrawContact->GetAnchorFrame(pObj) : nullptr;
3812  if ( pAnch )
3813  {
3814  if ( !pAnch->isFrameAreaPositionValid() )
3815  pAnch = nullptr;
3816  else if ( sal_IntPtr(pSh->GetOut()) == sal_IntPtr(pSh->getIDocumentDeviceAccess().getPrinter( false )))
3817  {
3818  //HACK: we have to omit some of the objects for printing,
3819  //otherwise they would be printed twice.
3820  //The objects should get printed if the TableHack is active
3821  //right now. Afterwards they must not be printed if the
3822  //page over which they float position wise gets printed.
3823  const SwPageFrame *pPage = pAnch->FindPageFrame();
3824  if ( !pPage->getFrameArea().IsOver( pObj->GetCurrentBoundRect() ) )
3825  pAnch = nullptr;
3826  }
3827  }
3828  else
3829  {
3830  // OD 02.07.2003 #108784# - debug assert
3831  if ( dynamic_cast< const SdrObjGroup *>( pObj ) == nullptr )
3832  {
3833  OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" );
3834  }
3835  }
3836  }
3837  if ( pAnch )
3838  {
3839  if ( pAnch->IsInFly() )
3840  bPaint = SwFlyFrame::IsPaint( pAnch->FindFlyFrame()->GetVirtDrawObj(),
3841  pSh );
3842  else if ( gProp.pSFlyOnlyDraw )
3843  bPaint = false;
3844  }
3845  else
3846  bPaint = false;
3847  }
3848  return bPaint;
3849 }
3850 
3851 void SwCellFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3852 {
3853  if ( GetLayoutRowSpan() >= 1 )
3854  SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
3855 }
3856 
3858 {
3859  explicit BorderLinesGuard() : m_pBorderLines(std::move(gProp.pBLines))
3860  {
3861  gProp.pBLines.reset(new BorderLines);
3862  }
3864  {
3865  gProp.pBLines = std::move(m_pBorderLines);
3866  }
3867 private:
3868  std::unique_ptr<BorderLines> m_pBorderLines;
3869 };
3870 
3871 void SwFlyFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3872 {
3873  //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
3874  SwViewShell *pShell = getRootFrame()->GetCurrShell();
3875  if (pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocShell())
3876  {
3877  bool bInGenerateThumbnail = pShell->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail();
3878  if (bInGenerateThumbnail)
3879  {
3880  const SwRect& aVisRect = pShell->VisArea();
3881  if (!aVisRect.IsOver(getFrameArea()))
3882  return;
3883  }
3884  }
3885 
3886  //because of the overlapping of frames and drawing objects the flys have to
3887  //paint their borders (and those of the internal ones) directly.
3888  //e.g. #33066#
3889  gProp.pSLines->LockLines(true);
3890  BorderLinesGuard blg; // this should not paint borders added from PaintBaBo
3891 
3892  SwRect aRect( rRect );
3893  aRect.Intersection_( getFrameArea() );
3894 
3895  rRenderContext.Push( PushFlags::CLIPREGION );
3896  rRenderContext.SetClipRegion();
3897  const SwPageFrame* pPage = FindPageFrame();
3898 
3899  const SwNoTextFrame *pNoText = Lower() && Lower()->IsNoTextFrame()
3900  ? static_cast<const SwNoTextFrame*>(Lower()) : nullptr;
3901 
3902  bool bIsChart = false; //#i102950# don't paint additional borders for charts
3903  //check whether we have a chart
3904  if(pNoText)
3905  {
3906  const SwNoTextNode* pNoTNd = dynamic_cast<const SwNoTextNode*>(pNoText->GetNode());
3907  if( pNoTNd )
3908  {
3909  SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTNd->GetOLENode());
3910  if( pOLENd && pOLENd->GetOLEObj().GetObject().IsChart() )
3911  bIsChart = true;
3912  }
3913  }
3914 
3915  {
3916  bool bContour = GetFormat()->GetSurround().IsContour();
3917  tools::PolyPolygon aPoly;
3918  if ( bContour )
3919  {
3920  // OD 16.04.2003 #i13147# - add 2nd parameter with value <true>
3921  // to indicate that method is called for paint in order to avoid
3922  // load of the intrinsic graphic.
3923  bContour = GetContour( aPoly, true );
3924  }
3925 
3926  // #i47804# - distinguish complete background paint
3927  // and margin paint.
3928  // paint complete background for Writer text fly frames
3929  bool bPaintCompleteBack( !pNoText );
3930  // paint complete background for transparent graphic and contour,
3931  // if own background color exists.
3932  const bool bIsGraphicTransparent = pNoText && pNoText->IsTransparent();
3933  if ( !bPaintCompleteBack &&
3934  ( bIsGraphicTransparent|| bContour ) )
3935  {
3936  const SwFrameFormat* pSwFrameFormat = dynamic_cast< const SwFrameFormat* >(GetFormat());
3937 
3938  if (pSwFrameFormat && pSwFrameFormat->supportsFullDrawingLayerFillAttributeSet())
3939  {
3940  // check for transparency
3942 
3943  // check if the new fill attributes are used
3944  if(aFillAttributes.get() && aFillAttributes->isUsed())
3945  {
3946  bPaintCompleteBack = true;
3947  }
3948  }
3949  else
3950  {
3951  std::shared_ptr<SvxBrushItem> aBack = GetFormat()->makeBackgroundBrushItem();
3952  // OD 07.08.2002 #99657# #GetTransChg#
3953  // to determine, if background has to be painted, by checking, if
3954  // background color is not COL_TRANSPARENT ("no fill"/"auto fill")
3955  // or a background graphic exists.
3956  bPaintCompleteBack = aBack &&
3957  ((aBack->GetColor() != COL_TRANSPARENT) ||
3958  aBack->GetGraphicPos() != GPOS_NONE);
3959  }
3960  }
3961  // paint of margin needed.
3962  const bool bPaintMarginOnly( !bPaintCompleteBack &&
3964 
3965  // #i47804# - paint background of parent fly frame
3966  // for transparent graphics in layer Hell, if parent fly frame isn't
3967  // in layer Hell. It's only painted the intersection between the
3968  // parent fly frame area and the paint area <aRect>
3970 
3971  if (bIsGraphicTransparent &&
3972  GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS) &&
3973  GetVirtDrawObj()->GetLayer() == rIDDMA.GetHellId() &&
3975  {
3976  const SwFlyFrame* pParentFlyFrame = GetAnchorFrame()->FindFlyFrame();
3977  if ( pParentFlyFrame->GetDrawObj()->GetLayer() !=
3978  rIDDMA.GetHellId() )
3979  {
3980  SwFlyFrame* pOldRet = gProp.pSRetoucheFly2;
3981  gProp.pSRetoucheFly2 = const_cast<SwFlyFrame*>(this);
3982 
3983  SwBorderAttrAccess aAccess( SwFrame::GetCache(), pParentFlyFrame );
3984  const SwBorderAttrs &rAttrs = *aAccess.Get();
3985  SwRect aPaintRect( aRect );
3986  aPaintRect.Intersection_( pParentFlyFrame->getFrameArea() );
3987  pParentFlyFrame->PaintSwFrameBackground( aPaintRect, pPage, rAttrs );
3988 
3989  gProp.pSRetoucheFly2 = pOldRet;
3990  }
3991  }
3992 
3993  if ( bPaintCompleteBack || bPaintMarginOnly )
3994  {
3995  //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder
3996  //receives the original Rect but PaintSwFrameBackground only the limited
3997  //one.
3998 
3999  // OD 2004-04-23 #116347#
4000  rRenderContext.Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
4001  rRenderContext.SetLineColor();
4002 
4003  pPage = FindPageFrame();
4004 
4005  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4006  const SwBorderAttrs &rAttrs = *aAccess.Get();
4007 
4008  // paint background
4009  {
4010  SwRegionRects aRegion( aRect );
4011  // #i80822#
4012  // suppress painting of background in printing area for
4013  // non-transparent graphics.
4014  if ( bPaintMarginOnly ||
4015  ( pNoText && !bIsGraphicTransparent ) )
4016  {
4017  //What we actually want to paint is the small stripe between
4018  //PrtArea and outer border.
4019  SwRect aTmp( getFramePrintArea() ); aTmp += getFrameArea().Pos();
4020  aRegion -= aTmp;
4021  }
4022  if ( bContour )
4023  {
4024  rRenderContext.Push();
4025  // #i80822#
4026  // apply clip region under the same conditions, which are
4027  // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region
4028  // for painting the graphic/OLE. Thus, the clip region is
4029  // also applied for the PDF export.
4031 
4032  if ( !rRenderContext.GetConnectMetaFile() || !pSh || !pSh->GetWin() )
4033  {
4034  rRenderContext.SetClipRegion(vcl::Region(aPoly));
4035  }
4036 
4037  for ( size_t i = 0; i < aRegion.size(); ++i )
4038  {
4039  PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4040  }
4041 
4042  rRenderContext.Pop();
4043  }
4044  else
4045  {
4046  for ( size_t i = 0; i < aRegion.size(); ++i )
4047  {
4048  PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4049  }
4050  }
4051  }
4052 
4053  // OD 06.08.2002 #99657# - paint border before painting background
4054  // paint border
4055  PaintSwFrameShadowAndBorder(rRect, pPage, rAttrs);
4056 
4057  rRenderContext.Pop();
4058  }
4059  }
4060 
4061  // OD 19.12.2002 #106318# - fly frame will paint it's subsidiary lines and
4062  // the subsidiary lines of its lowers on its own, due to overlapping with
4063  // other fly frames or other objects.
4064  if( gProp.pSGlobalShell->GetWin()
4065  && !bIsChart ) //#i102950# don't paint additional borders for charts
4066  {
4067  bool bSubsLineRectsCreated;
4068  if ( gProp.pSSubsLines )
4069  {
4070  // Lock already existing subsidiary lines
4071  gProp.pSSubsLines->LockLines( true );
4072  bSubsLineRectsCreated = false;
4073  }
4074  else
4075  {
4076  // create new subsidiary lines
4077  gProp.pSSubsLines.reset(new SwSubsRects);
4078  bSubsLineRectsCreated = true;
4079  }
4080 
4081  bool bSpecSubsLineRectsCreated;
4082  if ( gProp.pSSpecSubsLines )
4083  {
4084  // Lock already existing special subsidiary lines
4085  gProp.pSSpecSubsLines->LockLines( true );
4086  bSpecSubsLineRectsCreated = false;
4087  }
4088  else
4089  {
4090  // create new special subsidiary lines
4091  gProp.pSSpecSubsLines.reset(new SwSubsRects);
4092  bSpecSubsLineRectsCreated = true;
4093  }
4094  // Add subsidiary lines of fly frame and its lowers
4095  RefreshLaySubsidiary( pPage, aRect );
4096  // paint subsidiary lines of fly frame and its lowers
4097  gProp.pSSpecSubsLines->PaintSubsidiary( &rRenderContext, nullptr, gProp );
4098  gProp.pSSubsLines->PaintSubsidiary(&rRenderContext, gProp.pSLines.get(), gProp);
4099  if ( !bSubsLineRectsCreated )
4100  // unlock subsidiary lines
4101  gProp.pSSubsLines->LockLines( false );
4102  else
4103  {
4104  // delete created subsidiary lines container
4105  gProp.pSSubsLines.reset();
4106  }
4107 
4108  if ( !bSpecSubsLineRectsCreated )
4109  // unlock special subsidiary lines
4110  gProp.pSSpecSubsLines->LockLines( false );
4111  else
4112  {
4113  // delete created special subsidiary lines container
4114  gProp.pSSpecSubsLines.reset();
4115  }
4116  }
4117 
4118  SwLayoutFrame::PaintSwFrame( rRenderContext, aRect );
4119 
4120  Validate();
4121 
4122  // OD 19.12.2002 #106318# - first paint lines added by fly frame paint
4123  // and then unlock other lines.
4124  gProp.pSLines->PaintLines( &rRenderContext, gProp );
4125  gProp.pSLines->LockLines( false );
4126  // have to paint frame borders added in heaven layer here...
4127  ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
4128 
4129  PaintDecorators();
4130 
4131  rRenderContext.Pop();
4132 
4133  if ( gProp.pSProgress && pNoText )
4135 }
4136 
4138 {
4139  // Show the un-float button
4140  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
4141  if ( pWrtSh )
4142  {
4143  UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
4144  }
4145 }
4146 
4147 void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
4148 {
4149  const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions();
4150  if (pViewOption->IsTable())
4151  {
4152  // #i29550#
4153  if ( IsCollapsingBorders() )
4154  {
4155  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4156  const SwBorderAttrs &rAttrs = *aAccess.Get();
4157 
4158  // paint shadow
4159  if ( rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
4160  {
4161  SwRect aRect;
4162  ::lcl_CalcBorderRect( aRect, this, rAttrs, true, gProp );
4163  PaintShadow( rRect, aRect, rAttrs );
4164  }
4165 
4166  SwTabFramePainter aHelper(*this);
4167  aHelper.PaintLines(rRenderContext, rRect);
4168  }
4169 
4170  SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
4171  }
4172  // OD 10.01.2003 #i6467# - no light grey rectangle for page preview
4173  else if ( gProp.pSGlobalShell->GetWin() && !gProp.pSGlobalShell->IsPreview() )
4174  {
4175  // OD 10.01.2003 #i6467# - intersect output rectangle with table frame
4176  SwRect aTabRect( getFramePrintArea() );
4177  aTabRect.Pos() += getFrameArea().Pos();
4178  SwRect aTabOutRect( rRect );
4179  aTabOutRect.Intersection( aTabRect );
4180  SwViewOption::DrawRect( &rRenderContext, aTabOutRect, COL_LIGHTGRAY );
4181  }
4182  const_cast<SwTabFrame*>(this)->ResetComplete();
4183 }
4184 
4198 static void lcl_PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4199  const SvxShadowItem& rShadow, const bool bDrawFullShadowRectangle,
4200  const bool bTop, const bool bBottom,
4201  const bool bLeft, const bool bRight,
4202  SwPaintProperties const & properties)
4203 {
4204  const long nWidth = ::lcl_AlignWidth ( rShadow.GetWidth(), properties );
4205  const long nHeight = ::lcl_AlignHeight( rShadow.GetWidth(), properties );
4206 
4207  SwRects aRegion;
4208  SwRect aOut( rOutRect );
4209 
4210  switch ( rShadow.GetLocation() )
4211  {
4212  case SvxShadowLocation::BottomRight:
4213  {
4214  if ( bDrawFullShadowRectangle )
4215  {
4216  // OD 06.08.2002 #99657# - draw full shadow rectangle
4217  aOut.Top( rOutRect.Top() + nHeight );
4218  aOut.Left( rOutRect.Left() + nWidth );
4219  aRegion.push_back( aOut );
4220  }
4221  else
4222  {
4223  if( bBottom )
4224  {
4225  aOut.Top( rOutRect.Bottom() - nHeight );
4226  if( bLeft )
4227  aOut.Left( rOutRect.Left() + nWidth );
4228  aRegion.push_back( aOut );
4229  }
4230  if( bRight )
4231  {
4232  aOut.Left( rOutRect.Right() - nWidth );
4233  if( bTop )
4234  aOut.Top( rOutRect.Top() + nHeight );
4235  else
4236  aOut.Top( rOutRect.Top() );
4237  if( bBottom )
4238  aOut.Bottom( rOutRect.Bottom() - nHeight );
4239  aRegion.push_back( aOut );
4240  }
4241  }
4242 
4243  if( bRight )
4244  rOutRect.Right( rOutRect.Right() - nWidth );
4245  if( bBottom )
4246  rOutRect.Bottom( rOutRect.Bottom()- nHeight );
4247  }
4248  break;
4249  case SvxShadowLocation::TopLeft:
4250  {
4251  if ( bDrawFullShadowRectangle )
4252  {
4253  // OD 06.08.2002 #99657# - draw full shadow rectangle
4254  aOut.Bottom( rOutRect.Bottom() - nHeight );
4255  aOut.Right( rOutRect.Right() - nWidth );
4256  aRegion.push_back( aOut );
4257  }
4258  else
4259  {
4260  if( bTop )
4261  {
4262  aOut.Bottom( rOutRect.Top() + nHeight );
4263  if( bRight )
4264  aOut.Right( rOutRect.Right() - nWidth );
4265  aRegion.push_back( aOut );
4266  }
4267  if( bLeft )
4268  {
4269  aOut.Right( rOutRect.Left() + nWidth );
4270  if( bBottom )
4271  aOut.Bottom( rOutRect.Bottom() - nHeight );
4272  else
4273  aOut.Bottom( rOutRect.Bottom() );
4274  if( bTop )
4275  aOut.Top( rOutRect.Top() + nHeight );
4276  aRegion.push_back( aOut );
4277  }
4278  }
4279 
4280  if( bLeft )
4281  rOutRect.Left( rOutRect.Left() + nWidth );
4282  if( bTop )
4283  rOutRect.Top( rOutRect.Top() + nHeight );
4284  }
4285  break;
4286  case SvxShadowLocation::TopRight:
4287  {
4288  if ( bDrawFullShadowRectangle )
4289  {
4290  // OD 06.08.2002 #99657# - draw full shadow rectangle
4291  aOut.Bottom( rOutRect.Bottom() - nHeight);
4292  aOut.Left( rOutRect.Left() + nWidth );
4293  aRegion.push_back( aOut );
4294  }
4295  else
4296  {
4297  if( bTop )
4298  {
4299  aOut.Bottom( rOutRect.Top() + nHeight );
4300  if( bLeft )
4301  aOut.Left( rOutRect.Left() + nWidth );
4302  aRegion.push_back( aOut );
4303  }
4304  if( bRight )
4305  {
4306  aOut.Left( rOutRect.Right() - nWidth );
4307  if( bBottom )
4308  aOut.Bottom( rOutRect.Bottom() - nHeight );
4309  else
4310  aOut.Bottom( rOutRect.Bottom() );
4311  if( bTop )
4312  aOut.Top( rOutRect.Top() + nHeight );
4313  aRegion.push_back( aOut );
4314  }
4315  }
4316 
4317  if( bRight )
4318  rOutRect.Right( rOutRect.Right() - nWidth );
4319  if( bTop )
4320  rOutRect.Top( rOutRect.Top() + nHeight );
4321  }
4322  break;
4323  case SvxShadowLocation::BottomLeft:
4324  {
4325  if ( bDrawFullShadowRectangle )
4326  {
4327  // OD 06.08.2002 #99657# - draw full shadow rectangle
4328  aOut.Top( rOutRect.Top() + nHeight );
4329  aOut.Right( rOutRect.Right() - nWidth );
4330  aRegion.push_back( aOut );
4331  }
4332  else
4333  {
4334  if( bBottom )
4335  {
4336  aOut.Top( rOutRect.Bottom()- nHeight );
4337  if( bRight )
4338  aOut.Right( rOutRect.Right() - nWidth );
4339  aRegion.push_back( aOut );
4340  }
4341  if( bLeft )
4342  {
4343  aOut.Right( rOutRect.Left() + nWidth );
4344  if( bTop )
4345  aOut.Top( rOutRect.Top() + nHeight );
4346  else
4347  aOut.Top( rOutRect.Top() );
4348  if( bBottom )
4349  aOut.Bottom( rOutRect.Bottom() - nHeight );
4350  aRegion.push_back( aOut );
4351  }
4352  }
4353 
4354  if( bLeft )
4355  rOutRect.Left( rOutRect.Left() + nWidth );
4356  if( bBottom )
4357  rOutRect.Bottom( rOutRect.Bottom() - nHeight );
4358  }
4359  break;
4360  default:
4361  assert(false);
4362  break;
4363  }
4364 
4365  vcl::RenderContext *pOut = properties.pSGlobalShell->GetOut();
4366 
4367  DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
4368  Color aShadowColor( rShadow.GetColor().GetRGBColor() );
4369  if( !aRegion.empty() && properties.pSGlobalShell->GetWin() &&
4371  {
4372  // In high contrast mode, the output device has already set the
4373  // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function
4374  // to ignore the setting of a new color. Therefore we have to reset
4375  // the drawing mode
4376  pOut->SetDrawMode( DrawModeFlags::Default );
4377  aShadowColor = SwViewOption::GetFontColor();
4378  }
4379 
4380  if ( pOut->GetFillColor() != aShadowColor )
4381  pOut->SetFillColor( aShadowColor );
4382 
4383  pOut->SetLineColor();
4384 
4385  pOut->SetDrawMode( nOldDrawMode );
4386 
4387  for (const SwRect & rOut : aRegion)
4388  {
4389  aOut = rOut;
4390  if ( rRect.IsOver( aOut ) && aOut.Height() > 0 && aOut.Width() > 0 )
4391  {
4392  aOut.Intersection_( rRect );
4393  pOut->DrawRect( aOut.SVRect() );
4394  }
4395  }
4396 }
4397 
4407 void SwFrame::PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4408  const SwBorderAttrs &rAttrs ) const
4409 {
4410  SvxShadowItem rShadow = rAttrs.GetShadow();
4411 
4412  const bool bCnt = IsContentFrame();
4413  const bool bTop = !bCnt || rAttrs.GetTopLine ( *(this) );
4414  const bool bBottom = !bCnt || rAttrs.GetBottomLine( *(this) );
4415 
4416  if( IsVertical() )
4417  {
4418  switch( rShadow.GetLocation() )
4419  {
4420  case SvxShadowLocation::BottomRight: rShadow.SetLocation(SvxShadowLocation::BottomLeft); break;
4421  case SvxShadowLocation::TopLeft: rShadow.SetLocation(SvxShadowLocation::TopRight); break;
4422  case SvxShadowLocation::TopRight: rShadow.SetLocation(SvxShadowLocation::BottomRight); break;
4423  case SvxShadowLocation::BottomLeft: rShadow.SetLocation(SvxShadowLocation::TopLeft); break;
4424  default: break;
4425  }
4426  }
4427 
4428  // OD 23.08.2002 #99657# - determine, if full shadow rectangle have to
4429  // be drawn or only two shadow rectangles beside the frame.
4430  // draw full shadow rectangle, if frame background is drawn transparent.
4431  // Status Quo:
4432  // SwLayoutFrame can have transparent drawn backgrounds. Thus,
4433  // "asked" their frame format.
4434  const bool bDrawFullShadowRectangle =
4435  ( IsLayoutFrame() &&
4436  static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent()
4437  );
4438 
4439  SwRectFnSet aRectFnSet(this);
4440  ::lcl_ExtendLeftAndRight( rOutRect, *(this), rAttrs, aRectFnSet.FnRect() );
4441 
4442  lcl_PaintShadow(rRect, rOutRect, rShadow, bDrawFullShadowRectangle, bTop, bBottom, true, true, gProp);
4443 }
4444 
4446  const SwRect& rOutRect,
4447  const SwPageFrame * pPage,
4448  const Color *pColor,
4449  const SvxBorderLineStyle nStyle ) const
4450 {
4451  if ( !rOutRect.IsOver( rRect ) )
4452  return;
4453 
4454  SwRect aOut( rOutRect );
4455  aOut.Intersection_( rRect );
4456 
4457  const SwTabFrame *pTab = IsCellFrame() ? FindTabFrame() : nullptr;
4458  SubColFlags nSubCol = ( IsCellFrame() || IsRowFrame() )
4459  ? SubColFlags::Tab
4460  : ( IsInSct()
4461  ? SubColFlags::Sect
4462  : ( IsInFly() ? SubColFlags::Fly : SubColFlags::Page ) );
4463  if( pColor && gProp.pSGlobalShell->GetWin() &&
4465  {
4466  pColor = &SwViewOption::GetFontColor();
4467  }
4468 
4469  if (pPage->GetSortedObjs() &&
4471  {
4472  SwRegionRects aRegion( aOut, 4 );
4473  basegfx::utils::B2DClipState aClipState;
4474  ::lcl_SubtractFlys( this, pPage, aOut, aRegion, aClipState, gProp );
4475  for ( size_t i = 0; i < aRegion.size(); ++i )
4476  gProp.pSLines->AddLineRect( aRegion[i], pColor, nStyle, pTab, nSubCol, gProp );
4477  }
4478  else
4479  gProp.pSLines->AddLineRect( aOut, pColor, nStyle, pTab, nSubCol, gProp );
4480 }
4481 
4482 namespace drawinglayer
4483 {
4484  namespace primitive2d
4485  {
4487  {
4488  private:
4491 
4497 
4498  protected:
4500  virtual void create2DDecomposition(
4501  Primitive2DContainer& rContainer,
4502  const geometry::ViewInformation2D& rViewInformation) const override;
4503 
4504  public:
4507  const basegfx::B2DHomMatrix& rB2DHomMatrix,
4508  const svx::frame::Style& rStyleTop,
4509  const svx::frame::Style& rStyleRight,
4510  const svx::frame::Style& rStyleBottom,
4511  const svx::frame::Style& rStyleLeft);
4512 
4515  const svx::frame::Style& getStyleTop() const { return maStyleTop; }
4516  const svx::frame::Style& getStyleRight() const { return maStyleRight; }
4518  const svx::frame::Style& getStyleLeft() const { return maStyleLeft; }
4519 
4521  virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
4522 
4524  virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
4525 
4528  };
4529 
4531  Primitive2DContainer& rContainer,
4532  const geometry::ViewInformation2D& /*rViewInformation*/) const
4533  {
4534  basegfx::B2DPoint aTopLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 0.0));
4535  basegfx::B2DPoint aTopRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 0.0));
4536  basegfx::B2DPoint aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0));
4537  basegfx::B2DPoint aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0));
4538 
4539  // prepare SdrFrameBorderDataVector
4540  std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
4541  std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
4542 
4543  if(getStyleTop().IsUsed())
4544  {
4545  // move top left/right inwards half border width
4547  aDown.setLength(getStyleTop().GetWidth() * 0.5);
4548  aTopLeft += aDown;
4549  aTopRight += aDown;
4550  }
4551 
4552  if(getStyleBottom().IsUsed())
4553  {
4554  // move bottom left/right inwards half border width
4556  aUp.setLength(getStyleBottom().GetWidth() * 0.5);
4557  aBottomLeft += aUp;
4558  aBottomRight += aUp;
4559  }
4560 
4561  if(getStyleLeft().IsUsed())
4562  {
4563  // move left top/bottom inwards half border width
4565  aRight.setLength(getStyleLeft().GetWidth() * 0.5);
4566  aTopLeft += aRight;
4567  aBottomLeft += aRight;
4568  }
4569 
4570  if(getStyleRight().IsUsed())
4571  {
4572  // move right top/bottom inwards half border width
4574  aLeft.setLength(getStyleRight().GetWidth() * 0.5);
4575  aTopRight += aLeft;
4576  aBottomRight += aLeft;
4577  }
4578 
4579  // go round-robin, from TopLeft to TopRight, down, left and back up. That
4580  // way, the borders will not need to be mirrored in any way
4581  if(getStyleTop().IsUsed())
4582  {
4583  // create BorderPrimitive(s) for top border
4584  const basegfx::B2DVector aVector(aTopRight - aTopLeft);
4585  aData->emplace_back(
4586  aTopLeft,
4587  aVector,
4588  getStyleTop(),
4589  nullptr);
4590  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4591 
4592  if(getStyleLeft().IsUsed())
4593  {
4594  rInstance.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft - aTopLeft), false);
4595  }
4596 
4597  if(getStyleRight().IsUsed())
4598  {
4599  rInstance.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight - aTopRight), false);
4600  }
4601  }
4602 
4603  if(getStyleRight().IsUsed())
4604  {
4605  // create BorderPrimitive(s) for right border
4606  const basegfx::B2DVector aVector(aBottomRight - aTopRight);
4607  aData->emplace_back(
4608  aTopRight,
4609  aVector,
4610  getStyleRight(),
4611  nullptr);
4612  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4613 
4614  if(getStyleTop().IsUsed())
4615  {
4616  rInstance.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft - aTopRight), false);
4617  }
4618 
4619  if(getStyleBottom().IsUsed())
4620  {
4621  rInstance.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft - aBottomRight), false);
4622  }
4623  }
4624 
4625  if(getStyleBottom().IsUsed())
4626  {
4627  // create BorderPrimitive(s) for bottom border
4628  const basegfx::B2DVector aVector(aBottomLeft - aBottomRight);
4629  aData->emplace_back(
4630  aBottomRight,
4631  aVector,
4632  getStyleBottom(),
4633  nullptr);
4634  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4635 
4636  if(getStyleRight().IsUsed())
4637  {
4638  rInstance.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight - aBottomRight), false);
4639  }
4640 
4641  if(getStyleLeft().IsUsed())
4642  {
4643  rInstance.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft - aBottomLeft), false);
4644  }
4645  }
4646 
4647  if(getStyleLeft().IsUsed())
4648  {
4649  // create BorderPrimitive(s) for left border
4650  const basegfx::B2DVector aVector(aTopLeft - aBottomLeft);
4651  aData->emplace_back(
4652  aBottomLeft,
4653  aVector,
4654  getStyleLeft(),
4655  nullptr);
4656  drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4657 
4658  if(getStyleBottom().IsUsed())
4659  {
4660  rInstance.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight - aBottomLeft), false);
4661  }
4662 
4663  if(getStyleTop().IsUsed())
4664  {
4665  rInstance.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight - aTopLeft), false);
4666  }
4667  }
4668 
4669  // create instance of SdrFrameBorderPrimitive2D if
4670  // SdrFrameBorderDataVector is used
4671  if(!aData->empty())
4672  {
4673  rContainer.append(
4676  aData,
4677  true, // try to merge results to have less primitivbes
4678  true))); // force visualization to minimal one discrete unit (pixel)
4679  }
4680  }
4681 
4683  const basegfx::B2DHomMatrix& rB2DHomMatrix,
4684  const svx::frame::Style& rStyleTop,
4685  const svx::frame::Style& rStyleRight,
4686  const svx::frame::Style& rStyleBottom,
4687  const svx::frame::Style& rStyleLeft)
4689  maB2DHomMatrix(rB2DHomMatrix),
4690  maStyleTop(rStyleTop),
4691  maStyleRight(rStyleRight),
4692  maStyleBottom(rStyleBottom),
4693  maStyleLeft(rStyleLeft)
4694  {
4695  }
4696 
4698  {
4699  if(BasePrimitive2D::operator==(rPrimitive))
4700  {
4701  const SwBorderRectanglePrimitive2D& rCompare = static_cast<const SwBorderRectanglePrimitive2D&>(rPrimitive);
4702 
4703  return (getB2DHomMatrix() == rCompare.getB2DHomMatrix() &&
4704  getStyleTop() == rCompare.getStyleTop() &&
4705  getStyleRight() == rCompare.getStyleRight() &&
4706  getStyleBottom() == rCompare.getStyleBottom() &&
4707  getStyleLeft() == rCompare.getStyleLeft());
4708  }
4709 
4710  return false;
4711  }
4712 
4714  {
4715  basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
4716 
4717  aRetval.transform(getB2DHomMatrix());
4718  return aRetval;
4719  }
4720 
4721  // provide unique ID
4723 
4724  } // end of namespace primitive2d
4725 } // end of namespace drawinglayer
4726 
4728  const SwFont& rFont,
4729  const SwRect& rPaintArea,
4730  const bool bVerticalLayout,
4731  const bool bVerticalLayoutLRBT,
4732  const bool bJoinWithPrev,
4733  const bool bJoinWithNext )
4734 {
4735  SwRect aAlignedRect(rPaintArea);
4736  SwAlignRect(aAlignedRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut());
4737 
4738  bool bTop = true;
4739  bool bBottom = true;
4740  bool bLeft = true;
4741  bool bRight = true;
4742 
4743  switch (rFont.GetOrientation(bVerticalLayout, bVerticalLayoutLRBT))
4744  {
4745  case 0 :
4746  bLeft = !bJoinWithPrev;
4747  bRight = !bJoinWithNext;
4748  break;
4749  case 900 :
4750  bBottom = !bJoinWithPrev;
4751  bTop = !bJoinWithNext;
4752  break;
4753  case 1800 :
4754  bRight = !bJoinWithPrev;
4755  bLeft = !bJoinWithNext;
4756  break;
4757  case 2700 :
4758  bTop = !bJoinWithPrev;
4759  bBottom = !bJoinWithNext;
4760  break;
4761  }
4762 
4763  // Paint shadow (reduce painting rect)
4764  {
4765  const SvxShadowItem aShadow(
4766  0, &rFont.GetShadowColor(), rFont.GetShadowWidth(),
4767  rFont.GetAbsShadowLocation(bVerticalLayout, bVerticalLayoutLRBT));
4768 
4769  if( aShadow.GetLocation() != SvxShadowLocation::NONE )
4770  {
4771  lcl_PaintShadow( rPaintArea, aAlignedRect, aShadow,
4772  false, bTop, bBottom, bLeft, bRight, gProp);
4773  }
4774  }
4775 
4776  const basegfx::B2DHomMatrix aBorderTransform(
4778  aAlignedRect.Width(), aAlignedRect.Height(),
4779  aAlignedRect.Left(), aAlignedRect.Top()));
4780  const svx::frame::Style aStyleTop(
4781  bTop ? rFont.GetAbsTopBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
4782  1.0);
4783  const svx::frame::Style aStyleRight(
4784  bRight ? rFont.GetAbsRightBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
4785  1.0);
4786  const svx::frame::Style aStyleBottom(
4787  bBottom ? rFont.GetAbsBottomBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr()
4788  : nullptr,
4789  1.0);
4790  const svx::frame::Style aStyleLeft(
4791  bLeft ? rFont.GetAbsLeftBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
4792  1.0);
4794 
4795  aBorderLineTarget.append(
4798  aBorderTransform,
4799  aStyleTop,
4800  aStyleRight,
4801  aStyleBottom,
4802  aStyleLeft)));
4803  gProp.pBLines->AddBorderLines(aBorderLineTarget);
4804 }
4805 
4807 static const SwFrame* lcl_HasNextCell( const SwFrame& rFrame )
4808 {
4809  OSL_ENSURE( rFrame.IsCellFrame(),
4810  "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame" );
4811 
4812  const SwFrame* pTmpFrame = &rFrame;
4813  do
4814  {
4815  if ( pTmpFrame->GetNext() )
4816  return pTmpFrame->GetNext();
4817 
4818  pTmpFrame = pTmpFrame->GetUpper()->GetUpper();
4819  }
4820  while ( pTmpFrame->IsCellFrame() );
4821 
4822  return nullptr;
4823 }
4824 
4846 static const SwFrame* lcl_GetCellFrameForBorderAttrs( const SwFrame* _pCellFrame,
4847  const SwBorderAttrs& _rCellBorderAttrs,
4848  const bool _bTop )
4849 {
4850  OSL_ENSURE( _pCellFrame, "No cell frame available, dying soon" );
4851 
4852  // determine, if cell frame is at bottom/top border of a table frame and
4853  // the table frame has/is a follow.
4854  const SwFrame* pTmpFrame = _pCellFrame;
4855  bool bCellAtBorder = true;
4856  bool bCellAtLeftBorder = !_pCellFrame->GetPrev();
4857  bool bCellAtRightBorder = !_pCellFrame->GetNext();
4858  while( !pTmpFrame->IsRowFrame() || !pTmpFrame->GetUpper()->IsTabFrame() )
4859  {
4860  pTmpFrame = pTmpFrame->GetUpper();
4861  if ( pTmpFrame->IsRowFrame() &&
4862  (_bTop ? pTmpFrame->GetPrev() : pTmpFrame->GetNext())
4863  )
4864  {
4865  bCellAtBorder = false;
4866  }
4867  if ( pTmpFrame->IsCellFrame() )
4868  {
4869  if ( pTmpFrame->GetPrev() )
4870  {
4871  bCellAtLeftBorder = false;
4872  }
4873  if ( pTmpFrame->GetNext() )
4874  {
4875  bCellAtRightBorder = false;
4876  }
4877  }
4878  }
4879  OSL_ENSURE( pTmpFrame && pTmpFrame->IsRowFrame(), "No RowFrame available" );
4880 
4881  const SwLayoutFrame* pParentRowFrame = static_cast<const SwLayoutFrame*>(pTmpFrame);
4882  const SwTabFrame* pParentTabFrame =
4883  static_cast<const SwTabFrame*>(pParentRowFrame->GetUpper());
4884 
4885  const bool bCellNeedsAttribute = bCellAtBorder &&
4886  ( _bTop ?
4887  // bCellInFirstRowWithMaster
4888  ( !pParentRowFrame->GetPrev() &&
4889  pParentTabFrame->IsFollow() &&
4890  0 == pParentTabFrame->GetTable()->GetRowsToRepeat() ) :
4891  // bCellInLastRowWithFollow
4892  ( !pParentRowFrame->GetNext() &&
4893  pParentTabFrame->GetFollow() )
4894  );
4895 
4896  const SwFrame* pRet = _pCellFrame;
4897  if ( bCellNeedsAttribute )
4898  {
4899  // determine, if cell frame has no borders inside the table.
4900  const SwFrame* pNextCell = nullptr;
4901  bool bNoBordersInside = false;
4902 
4903  if ( bCellAtLeftBorder && ( nullptr != ( pNextCell = lcl_HasNextCell( *_pCellFrame ) ) ) )
4904  {
4905  SwBorderAttrAccess aAccess( SwFrame::GetCache(), pNextCell );
4906  const SwBorderAttrs &rBorderAttrs = *aAccess.Get();
4907  const SvxBoxItem& rBorderBox = rBorderAttrs.GetBox();
4908  bCellAtRightBorder = !lcl_HasNextCell( *pNextCell );
4909  bNoBordersInside =
4910  ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4911  !rBorderBox.GetLeft() &&
4912  ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4913  ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4914  }
4915  else
4916  {
4917  const SvxBoxItem& rBorderBox = _rCellBorderAttrs.GetBox();
4918  bNoBordersInside =
4919  ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4920  ( !rBorderBox.GetLeft() || bCellAtLeftBorder ) &&
4921  ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4922  ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4923  }
4924 
4925  if ( bNoBordersInside )
4926  {
4927  if ( _bTop && !_rCellBorderAttrs.GetBox().GetTop() )
4928  {
4929  //-hack
4930  // Cell frame has no top border and no border inside the table, but
4931  // it is at the top border of a table frame, which is a follow.
4932  // Thus, use border attributes of cell frame in first row of complete table.
4933  // First, determine first table frame of complete table.
4934  SwTabFrame* pMasterTabFrame = pParentTabFrame->FindMaster( true );
4935  // determine first row of complete table.
4936  const SwFrame* pFirstRow = pMasterTabFrame->GetLower();
4937  // return first cell in first row
4938  SwFrame* pLowerCell = const_cast<SwFrame*>(pFirstRow->GetLower());
4939  while ( !pLowerCell->IsCellFrame() ||
4940  ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
4941  )
4942  {
4943  pLowerCell = pLowerCell->GetLower();
4944  }
4945  OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
4946  pRet = pLowerCell;
4947  }
4948  else if ( !_bTop && !_rCellBorderAttrs.GetBox().GetBottom() )
4949  {
4950  //-hack
4951  // Cell frame has no bottom border and no border inside the table,
4952  // but it is at the bottom border of a table frame, which has a follow.
4953  // Thus, use border attributes of cell frame in last row of complete table.
4954  // First, determine last table frame of complete table.
4955  SwTabFrame* pLastTabFrame = const_cast<SwTabFrame*>(pParentTabFrame->GetFollow());
4956  while ( pLastTabFrame->GetFollow() )
4957  {
4958  pLastTabFrame = pLastTabFrame->GetFollow();
4959  }
4960  // determine last row of complete table.
4961  SwFrame* pLastRow = pLastTabFrame->GetLastLower();
4962  // return first bottom border cell in last row
4963  SwFrame* pLowerCell = pLastRow->GetLower();
4964  while ( !pLowerCell->IsCellFrame() ||
4965  ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
4966  )
4967  {
4968  if ( pLowerCell->IsRowFrame() )
4969  {
4970  while ( pLowerCell->GetNext() )
4971  {
4972  pLowerCell = pLowerCell->GetNext();
4973  }
4974  }
4975  pLowerCell = pLowerCell->GetLower();
4976  }
4977  OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
4978  pRet = pLowerCell;
4979  }
4980  }
4981  }
4982 
4983  return pRet;
4984 }
4985 
4986 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> SwFrame::CreateProcessor2D( ) const
4987 {
4988  basegfx::B2DRange aViewRange;
4989 
4990  SdrPage *pDrawPage = getRootFrame()->GetCurrShell()->Imp()->GetPageView()->