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