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