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