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