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