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