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