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  tools::Long nSPixelSzW;
289  tools::Long nSPixelSzH;
290  tools::Long nSHalfPixelSzW;
291  tools::Long nSHalfPixelSzH;
292  tools::Long nSMinDistPixelW;
293  tools::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 tools::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 tools::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 tools::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  tools::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  tools::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  tools::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  tools::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  tools::Long startX = rLRect.Left( ), endX;
863  tools::Long startY = rLRect.Top( ), endY;
864 
865  // Discriminate vertically stretched rect from horizontally stretched
866  // and restrict minimum nHalfLWidth to 1
867  tools::Long nHalfLWidth = std::max( static_cast<tools::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  tools::Long nLi = rLi.Right();
1032  tools::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  tools::Long nLi = rLi.Bottom();
1047  tools::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 tools::Long lcl_AlignWidth( const tools::Long nWidth, SwPaintProperties const & properties )
1234 {
1235  if ( nWidth )
1236  {
1237  const tools::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 tools::Long lcl_AlignHeight( const tools::Long nHeight, SwPaintProperties const & properties )
1246 {
1247  if ( nHeight )
1248  {
1249  const tools::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  const SwFlyFrame *pFly = dynamic_cast<const SwFlyFrame*>(pAnchoredObj);
1399  if (!pFly)
1400  continue;
1401 
1402  if (pSelfFly == pFly || gProp.pSRetoucheFly == pFly || !rRect.IsOver(pFly->getFrameArea()))
1403  continue;
1404 
1405  if (!pFly->GetFormat()->GetPrint().GetValue() &&
1406  (OUTDEV_PRINTER == gProp.pSGlobalShell->GetOut()->GetOutDevType() ||
1407  gProp.pSGlobalShell->IsPreview()))
1408  continue;
1409 
1410  const bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly );
1411 
1412  //For character bound Flys only examine those Flys in which it is not
1413  //anchored itself.
1414  //Why only for character bound ones you may ask? It never makes sense to
1415  //subtract frames in which it is anchored itself right?
1416  if (pSelfFly && pSelfFly->IsLowerOf(pFly))
1417  continue;
1418 
1419  //Any why does it not apply for the RetoucheFly too?
1420  if (gProp.pSRetoucheFly && gProp.pSRetoucheFly->IsLowerOf(pFly))
1421  continue;
1422 
1423 #if OSL_DEBUG_LEVEL > 0
1424  //Flys who are anchored inside their own one, must have a bigger OrdNum
1425  //or be character bound.
1426  if (pSelfFly && bLowerOfSelf)
1427  {
1428  OSL_ENSURE( pFly->IsFlyInContentFrame() ||
1429  pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(),
1430  "Fly with wrong z-Order" );
1431  }
1432 #endif
1433 
1434  bool bStopOnHell = true;
1435  if (pSelfFly)
1436  {
1437  const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
1438  if (pSdrObj->GetLayer() == pTmp->GetLayer())
1439  {
1440  if (pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect())
1441  //In the same layer we only observe those that are above.
1442  continue;
1443  }
1444  else
1445  {
1446  if (!bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue())
1447  //From other layers we are only interested in non
1448  //transparent ones or those that are internal
1449  continue;
1450  bStopOnHell = false;
1451  }
1452  }
1453  if (gProp.pSRetoucheFly)
1454  {
1455  const SdrObject *pTmp = gProp.pSRetoucheFly->GetVirtDrawObj();
1456  if ( pSdrObj->GetLayer() == pTmp->GetLayer() )
1457  {
1458  if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
1459  //In the same layer we only observe those that are above.
1460  continue;
1461  }
1462  else
1463  {
1464  if (!pFly->IsLowerOf( gProp.pSRetoucheFly ) && !pFly->GetFormat()->GetOpaque().GetValue())
1465  //From other layers we are only interested in non
1466  //transparent ones or those that are internal
1467  continue;
1468  bStopOnHell = false;
1469  }
1470  }
1471 
1472  //If the content of the Fly is transparent, we subtract it only if it's
1473  //contained in the hell layer.
1475  bool bHell = pSdrObj->GetLayer() == rIDDMA.GetHellId();
1476  if ( (bStopOnHell && bHell) ||
1480  ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTextFrame() &&
1481  (static_cast<SwNoTextFrame const*>(pFly->Lower())->IsTransparent() ||
1482  static_cast<SwNoTextFrame const*>(pFly->Lower())->HasAnimation() ||
1483  pFly->GetFormat()->GetSurround().IsContour()
1484  )
1485  )
1486  )
1487  continue;
1488 
1489  // Own if-statements for transparent background/shadow of fly frames
1490  // in order to handle special conditions.
1491  if (pFly->IsBackgroundTransparent())
1492  {
1493  // Background <pFly> is transparent drawn. Thus normally, its region
1494  // have not to be subtracted from given region.
1495  // But, if method is called for a fly frame and
1496  // <pFly> is a direct lower of this fly frame and
1497  // <pFly> inherites its transparent background brush from its parent,
1498  // then <pFly> frame area have to be subtracted from given region.
1499  // NOTE: Because in Status Quo transparent backgrounds can only be
1500  // assigned to fly frames, the handle of this special case
1501  // avoids drawing of transparent areas more than once, if
1502  // a fly frame inherites a transparent background from its
1503  // parent fly frame.
1504  if (pFrame->IsFlyFrame() &&
1505  (pFly->GetAnchorFrame()->FindFlyFrame() == pFrame) &&
1507  )
1508  {
1509  SwRect aRect;
1510  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1511  const SwBorderAttrs &rAttrs = *aAccess.Get();
1512  ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1513  rRegion -= aRect;
1514  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1515  continue;
1516  }
1517  else
1518  {
1519  continue;
1520  }
1521  }
1522 
1523  if (bHell && pFly->GetAnchorFrame()->IsInFly())
1524  {
1525  //So the border won't get dismantled by the background of the other
1526  //Fly.
1527  SwRect aRect;
1528  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1529  const SwBorderAttrs &rAttrs = *aAccess.Get();
1530  ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1531  rRegion -= aRect;
1532  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1533  }
1534  else
1535  {
1536  SwRect aRect( pFly->getFramePrintArea() );
1537  aRect += pFly->getFrameArea().Pos();
1538  rRegion -= aRect;
1539  rClipState.subtractRange(lcl_ShrinkFly(aRect));
1540  }
1541  }
1542  if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
1543  gProp.pSRetoucheFly = nullptr;
1544 }
1545 
1546 static void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1547  vcl::RenderContext* _pOut,
1548  const SwRect& _rAlignedPaintRect,
1549  const GraphicObject& _rGraphicObj,
1550  SwPaintProperties const & properties)
1551 {
1556  const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || properties.bSFlyMetafile )
1557  ? _rBackgrdBrush.GetColor()
1559 
1562  sal_Int8 nTransparencyPercent = 0;
1563  bool bDrawTransparent = false;
1564  if ( aColor.GetTransparency() != 0 )
1566  {
1567  bDrawTransparent = true;
1568  nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF;
1569  }
1570  else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) &&
1571  (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) )
1574  {
1575  bDrawTransparent = true;
1576  nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF;
1577  }
1578 
1579  if ( bDrawTransparent )
1580  {
1582  if( _pOut->GetFillColor() != aColor.GetRGBColor() )
1583  _pOut->SetFillColor( aColor.GetRGBColor() );
1584  tools::PolyPolygon aPoly( _rAlignedPaintRect.SVRect() );
1585  _pOut->DrawTransparent( aPoly, nTransparencyPercent );
1586  }
1587  else
1588  {
1590  if ( _pOut->GetFillColor() != aColor )
1591  _pOut->SetFillColor( aColor );
1592  _pOut->DrawRect( _rAlignedPaintRect.SVRect() );
1593  }
1594 }
1595 
1628 static void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1629  OutputDevice* _pOut,
1630  const SwRect& _rAlignedPaintRect,
1631  const GraphicObject& _rGraphicObj,
1632  bool _bNumberingGraphic,
1633  SwPaintProperties const & properties,
1634  bool _bBackgrdAlreadyDrawn = false)
1635 {
1636  // draw background with background color, if
1637  // (1) graphic is not used as a numbering AND
1638  // (2) background is not already drawn AND
1639  // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
1640  if ( !_bNumberingGraphic &&
1641  !_bBackgrdAlreadyDrawn &&
1642  ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GraphicType::NONE )
1643  )
1644  {
1645  lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj, properties );
1646  }
1647 }
1648 
1664 static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext *pOut,
1665  SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut,
1666  bool bGrfNum,
1667  SwPaintProperties const & properties,
1668  bool bBackgrdAlreadyDrawn )
1669  // add parameter <bBackgrdAlreadyDrawn> to indicate
1670  // that the background is already drawn.
1671 {
1672  // Calculate align rectangle from parameter <rGrf> and use aligned
1673  // rectangle <aAlignedGrfRect> in the following code
1674  SwRect aAlignedGrfRect = rGrf;
1675  ::SwAlignRect( aAlignedGrfRect, &rSh, pOut );
1676 
1677  // Change type from <bool> to <bool>.
1678  const bool bNotInside = !rOut.IsInside( aAlignedGrfRect );
1679  if ( bNotInside )
1680  {
1681  pOut->Push( PushFlags::CLIPREGION );
1682  pOut->IntersectClipRegion( rOut.SVRect() );
1683  }
1684 
1685  GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
1686 
1687  // Outsource drawing of background with a background color
1688  ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, properties, bBackgrdAlreadyDrawn );
1689 
1690  // Because for drawing a graphic left-top-corner and size coordinates are
1691  // used, these coordinates have to be determined on pixel level.
1692  ::SwAlignGrfRect( &aAlignedGrfRect, *pOut );
1693 
1694  const basegfx::B2DHomMatrix aGraphicTransform(
1696  aAlignedGrfRect.Width(), aAlignedGrfRect.Height(),
1697  aAlignedGrfRect.Left(), aAlignedGrfRect.Top()));
1698 
1700  *pOut,
1701  *pGrf,
1702  pGrf->GetAttr(),
1703  aGraphicTransform,
1704  OUString(),
1705  OUString(),
1706  OUString());
1707 
1708  if ( bNotInside )
1709  pOut->Pop();
1710 }
1711 
1714  const SwRect& rOriginalLayoutRect,
1715  const SwRegionRects& rPaintRegion,
1716  const basegfx::utils::B2DClipState& rClipState,
1717  vcl::RenderContext& rOut)
1718 {
1719  if(rFillAttributes && rFillAttributes->isUsed())
1720  {
1721  basegfx::B2DRange aPaintRange(
1722  rPaintRegion.GetOrigin().Left(),
1723  rPaintRegion.GetOrigin().Top(),
1724  rPaintRegion.GetOrigin().Right(),
1725  rPaintRegion.GetOrigin().Bottom());
1726 
1727  if (!aPaintRange.isEmpty() &&
1728  !rPaintRegion.empty() &&
1729  !basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
1730  !basegfx::fTools::equalZero(aPaintRange.getHeight()))
1731  {
1732  const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1733 
1734  // need to expand for correct AAed and non-AAed visualization as primitive.
1735  // This must probably be removed again when we will be able to get all Writer visualization
1736  // as primitives and Writer prepares all it's stuff in high precision coordinates (also
1737  // needs to avoid moving boundaries around to better show overlapping stuff...)
1738  if(aSvtOptionsDrawinglayer.IsAntiAliasing())
1739  {
1740  // if AAed in principle expand by 0.5 in all directions. Since painting edges of
1741  // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
1742  // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
1743  // artifacts. Checked experimentally - a little bit more in Y is needed, probably
1744  // due to still existing integer alignment and crunching in writer.
1745  static const double fExpandX = 0.55;
1746  static const double fExpandY = 0.70;
1747  const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX, fExpandY));
1748 
1749  aPaintRange.expand(aPaintRange.getMinimum() - aSingleUnit);
1750  aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1751  }
1752  else
1753  {
1754  // if not AAed expand by one unit to bottom right due to the missing unit
1755  // from SwRect/Rectangle integer handling
1756  const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
1757 
1758  aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1759  }
1760 
1761  const basegfx::B2DRange aDefineRange(
1762  rOriginalLayoutRect.Left(),
1763  rOriginalLayoutRect.Top(),
1764  rOriginalLayoutRect.Right(),
1765  rOriginalLayoutRect.Bottom());
1766 
1767  const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rFillAttributes->getPrimitive2DSequence(
1768  aPaintRange,
1769  aDefineRange);
1770 
1771  if(rSequence.size())
1772  {
1774  pPrimitives(&rSequence);
1776  // tdf#86578 the awful lcl_SubtractFlys hack
1777  if (rPaintRegion.size() > 1 || rPaintRegion[0] != rPaintRegion.GetOrigin())
1778  {
1779  basegfx::B2DPolyPolygon const& maskRegion(rClipState.getClipPoly());
1780  primitives.resize(1);
1781  primitives[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
1782  maskRegion, rSequence);
1783  pPrimitives = &primitives;
1784  }
1785  assert(pPrimitives && pPrimitives->size());
1786 
1787  const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
1789  rOut.GetViewTransformation(),
1790  aPaintRange,
1791  nullptr,
1792  0.0,
1793  uno::Sequence< beans::PropertyValue >());
1794  std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1795  rOut,
1796  aViewInformation2D) );
1797  if(pProcessor)
1798  {
1799  pProcessor->process(*pPrimitives);
1800  return true;
1801  }
1802  }
1803  }
1804  }
1805 
1806  return false;
1807 }
1808 
1810  const SvxBrushItem *pBrush,
1811  vcl::RenderContext *pOutDev,
1812  const SwRect &rOrg,
1813  const SwRect &rOut,
1814  const sal_uInt8 nGrfNum,
1815  const bool bConsiderBackgroundTransparency )
1816  // Add 6th parameter to indicate that method should
1817  // consider background transparency, saved in the color of the brush item
1818 {
1819  SwViewShell &rSh = *gProp.pSGlobalShell;
1820  bool bReplaceGrfNum = GRFNUM_REPLACE == nGrfNum;
1821  bool bGrfNum = GRFNUM_NO != nGrfNum;
1822  Size aGrfSize;
1824  if( pBrush && !bReplaceGrfNum )
1825  {
1826  if( rSh.GetViewOptions()->IsGraphic() )
1827  {
1828  OUString referer;
1829  SfxObjectShell * sh = rSh.GetDoc()->GetPersist();
1830  if (sh != nullptr && sh->HasName()) {
1831  referer = sh->GetMedium()->GetName();
1832  }
1833  const Graphic* pGrf = pBrush->GetGraphic(referer);
1834  if( pGrf && GraphicType::NONE != pGrf->GetType() )
1835  {
1836  ePos = pBrush->GetGraphicPos();
1837  if( pGrf->IsSupportedGraphic() )
1838  // don't the use the specific output device! Bug 94802
1839  aGrfSize = ::GetGraphicSizeTwip( *pGrf, nullptr );
1840  }
1841  }
1842  else
1843  bReplaceGrfNum = bGrfNum;
1844  }
1845 
1846  SwRect aGrf;
1847  aGrf.SSize( aGrfSize );
1848  bool bDraw = true;
1849  bool bRetouche = true;
1850  switch ( ePos )
1851  {
1852  case GPOS_LT:
1853  aGrf.Pos() = rOrg.Pos();
1854  break;
1855 
1856  case GPOS_MT:
1857  aGrf.Pos().setY( rOrg.Top() );
1858  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1859  break;
1860 
1861  case GPOS_RT:
1862  aGrf.Pos().setY( rOrg.Top() );
1863  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1864  break;
1865 
1866  case GPOS_LM:
1867  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1868  aGrf.Pos().setX( rOrg.Left() );
1869  break;
1870 
1871  case GPOS_MM:
1872  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1873  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1874  break;
1875 
1876  case GPOS_RM:
1877  aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1878  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1879  break;
1880 
1881  case GPOS_LB:
1882  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1883  aGrf.Pos().setX( rOrg.Left() );
1884  break;
1885 
1886  case GPOS_MB:
1887  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1888  aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1889  break;
1890 
1891  case GPOS_RB:
1892  aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1893  aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1894  break;
1895 
1896  case GPOS_AREA:
1897  aGrf = rOrg;
1898  // Despite the fact that the background graphic has to fill the complete
1899  // area, we already checked, whether the graphic will completely fill out
1900  // the region the <rOut> that is to be painted. Thus, nothing has to be
1901  // touched again.
1902  // E.g. this is the case for a Fly Frame without a background
1903  // brush positioned on the border of the page which inherited the background
1904  // brush from the page.
1905  bRetouche = !rOut.IsInside( aGrf );
1906  break;
1907 
1908  case GPOS_TILED:
1909  {
1910  // draw background of tiled graphic before drawing tiled graphic in loop
1911  // determine graphic object
1912  GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject());
1913  // calculate aligned paint rectangle
1914  SwRect aAlignedPaintRect = rOut;
1915  ::SwAlignRect( aAlignedPaintRect, &rSh, pOutDev );
1916  // draw background color for aligned paint rectangle
1917  lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum, gProp );
1918 
1919  // set left-top-corner of background graphic to left-top-corner of the
1920  // area, from which the background brush is determined.
1921  aGrf.Pos() = rOrg.Pos();
1922  // setup clipping at output device
1923  pOutDev->Push( PushFlags::CLIPREGION );
1924  pOutDev->IntersectClipRegion( rOut.SVRect() );
1925  // use new method <GraphicObject::DrawTiled(::)>
1926  {
1927  // calculate paint offset
1928  Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() );
1929  // draw background graphic tiled for aligned paint rectangle
1930  // #i42643#
1931  // For PDF export, every draw operation for bitmaps takes a
1932  // noticeable amount of place (~50 characters). Thus, optimize
1933  // between tile bitmap size and number of drawing operations here.
1934 
1935  // A_out
1936  // n_chars = k1 * ---------- + k2 * A_bitmap
1937  // A_bitmap
1938 
1939  // minimum n_chars is obtained for (derive for A_bitmap,
1940  // set to 0, take positive solution):
1941  // k1
1942  // A_bitmap = Sqrt( ---- A_out )
1943  // k2
1944 
1945  // where k1 is the number of chars per draw operation, and
1946  // k2 is the number of chars per bitmap pixel.
1947  // This is approximately 50 and 7 for current PDF writer, respectively.
1948 
1949  const double k1( 50 );
1950  const double k2( 7 );
1951  const Size aSize( aAlignedPaintRect.SSize() );
1952  const double Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() );
1953 
1954  pGraphicObj->DrawTiled( pOutDev,
1955  aAlignedPaintRect.SVRect(),
1956  aGrf.SSize(),
1957  Size( aPaintOffset.X(), aPaintOffset.Y() ),
1958  std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
1959  }
1960  // reset clipping at output device
1961  pOutDev->Pop();
1962  // set <bDraw> and <bRetouche> to false, indicating that background
1963  // graphic and background are already drawn.
1964  bDraw = bRetouche = false;
1965  }
1966  break;
1967 
1968  case GPOS_NONE:
1969  bDraw = false;
1970  break;
1971 
1972  default: OSL_ENSURE( !pOutDev, "new Graphic position?" );
1973  }
1974 
1977  bool bGrfBackgrdAlreadyDrawn = false;
1978  if ( bRetouche )
1979  {
1980  pOutDev->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
1981  pOutDev->SetLineColor();
1982 
1983  // check, if an existing background graphic (not filling the complete
1984  // background) is transparent drawn and the background color is
1985  // "no fill" respectively "auto fill", if background transparency
1986  // has to be considered.
1987  // If YES, memorize transparency of background graphic.
1988  // check also, if background graphic bitmap is transparent.
1989  bool bTransparentGrfWithNoFillBackgrd = false;
1990  sal_Int32 nGrfTransparency = 0;
1991  bool bGrfIsTransparent = false;
1992  if ( (ePos != GPOS_NONE) &&
1993  (ePos != GPOS_TILED) && (ePos != GPOS_AREA)
1994  )
1995  {
1996  GraphicObject *pGrf = const_cast<GraphicObject*>(pBrush->GetGraphicObject());
1997  if ( bConsiderBackgroundTransparency )
1998  {
1999  GraphicAttr aGrfAttr = pGrf->GetAttr();
2000  if ( (aGrfAttr.GetTransparency() != 0) &&
2001  (pBrush->GetColor() == COL_TRANSPARENT)
2002  )
2003  {
2004  bTransparentGrfWithNoFillBackgrd = true;
2005  nGrfTransparency = aGrfAttr.GetTransparency();
2006  }
2007  }
2008  if ( pGrf->IsTransparent() )
2009  {
2010  bGrfIsTransparent = true;
2011  }
2012  }
2013 
2014  // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
2015  // instead of checking, if transparency is not set.
2016  const Color aColor( pBrush &&
2017  ( (pBrush->GetColor() != COL_TRANSPARENT) ||
2018  gProp.bSFlyMetafile )
2019  ? pBrush->GetColor()
2021 
2022  // determine, if background region have to be
2023  // drawn transparent.
2024  // background region has to be drawn transparent, if
2025  // background transparency have to be considered
2026  // AND
2027  // ( background color is transparent OR
2028  // background graphic is transparent and background color is "no fill"
2029  // )
2030 
2031  enum DrawStyle {
2032  Default,
2033  Transparent,
2034  } eDrawStyle = Default;
2035 
2036  if (bConsiderBackgroundTransparency &&
2037  ( ( aColor.GetTransparency() != 0) ||
2038  bTransparentGrfWithNoFillBackgrd ) )
2039  {
2040  eDrawStyle = Transparent;
2041  }
2042 
2043  // #i75614# reset draw mode in high contrast mode in order to get fill color set
2044  const DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
2045  if ( gProp.pSGlobalShell->GetWin() &&
2047  {
2048  pOutDev->SetDrawMode( DrawModeFlags::Default );
2049  }
2050 
2051  // If background region has to be drawn transparent, set only the RGB values of the background color as
2052  // the fill color for the output device.
2053  switch (eDrawStyle)
2054  {
2055  case Transparent:
2056  {
2057  if( pOutDev->GetFillColor() != aColor.GetRGBColor() )
2058  pOutDev->SetFillColor( aColor.GetRGBColor() );
2059  break;
2060  }
2061  default:
2062  {
2063  if( pOutDev->GetFillColor() != aColor )
2064  pOutDev->SetFillColor( aColor );
2065  break;
2066  }
2067  }
2068 
2069  // #i75614#
2070  // restore draw mode
2071  pOutDev->SetDrawMode( nOldDrawMode );
2072 
2073  switch (eDrawStyle)
2074  {
2075  case Transparent:
2076  {
2077  // background region have to be drawn transparent.
2078  // Thus, create a poly-polygon from the region and draw it with
2079  // the corresponding transparency percent.
2080  tools::PolyPolygon aDrawPoly( rOut.SVRect() );
2081  if ( aGrf.HasArea() )
2082  {
2083  if ( !bGrfIsTransparent )
2084  {
2085  // subtract area of background graphic from draw area
2086  // Consider only that part of the graphic area that is overlapping with draw area.
2087  SwRect aTmpGrf = aGrf;
2088  aTmpGrf.Intersection( rOut );
2089  if ( aTmpGrf.HasArea() )
2090  {
2091  tools::Polygon aGrfPoly( aTmpGrf.SVRect() );
2092  aDrawPoly.Insert( aGrfPoly );
2093  }
2094  }
2095  else
2096  bGrfBackgrdAlreadyDrawn = true;
2097  }
2098  // calculate transparency percent:
2099  // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
2100  // If there is a background graphic with a background color "no fill"/"auto fill",
2101  // the transparency value is taken from the background graphic,
2102  // otherwise take the transparency value from the color.
2103  sal_Int8 nTransparencyPercent = static_cast<sal_Int8>(
2104  (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency()
2105  )*100 + 0x7F)/0xFF);
2106  // draw poly-polygon transparent
2107  pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent );
2108 
2109  break;
2110  }
2111  case Default:
2112  default:
2113  {
2114  SwRegionRects aRegion( rOut, 4 );
2115  if ( !bGrfIsTransparent )
2116  aRegion -= aGrf;
2117  else
2118  bGrfBackgrdAlreadyDrawn = true;
2119  // loop rectangles of background region, which has to be drawn
2120  for( size_t i = 0; i < aRegion.size(); ++i )
2121  {
2122  pOutDev->DrawRect( aRegion[i].SVRect() );
2123  }
2124  }
2125  }
2126  pOutDev ->Pop();
2127  }
2128 
2129  if( bDraw && aGrf.IsOver( rOut ) )
2130  lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, bGrfNum, gProp,
2131  bGrfBackgrdAlreadyDrawn );
2132 
2133  if( bReplaceGrfNum )
2134  {
2135  const BitmapEx& rBmp = rSh.GetReplacementBitmap(false);
2136  vcl::Font aTmp( pOutDev->GetFont() );
2137  Graphic::DrawEx(pOutDev, OUString(), aTmp, rBmp, rOrg.Pos(), rOrg.SSize());
2138  }
2139 }
2140 
2149 static void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const vcl::RenderContext &aOut )
2150 {
2151  // local constant object of class <Size> to determine number of Twips
2152  // representing a pixel.
2153  const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) );
2154 
2155  // local object of class <Rectangle> in Twip coordinates
2156  // calculated from given rectangle aligned to pixel centers.
2157  const tools::Rectangle aPxCenterRect = aOut.PixelToLogic(
2158  aOut.LogicToPixel( io_aSwRect.SVRect() ) );
2159 
2160  // local constant object of class <Rectangle> representing given rectangle
2161  // in pixel.
2162  const tools::Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2163 
2164  // calculate adjusted rectangle from pixel centered rectangle.
2165  // Due to rounding differences <aPxCenterRect> doesn't exactly represents
2166  // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
2167  // Afterwards, adjust calculated Twip-positions of the all borders.
2168  tools::Rectangle aSizedRect = aPxCenterRect;
2169  aSizedRect.AdjustLeft( -(aTwipToPxSize.Width()/2 + 1) );
2170  aSizedRect.AdjustRight( aTwipToPxSize.Width()/2 + 1 );
2171  aSizedRect.AdjustTop( -(aTwipToPxSize.Height()/2 + 1) );
2172  aSizedRect.AdjustBottom(aTwipToPxSize.Height()/2 + 1);
2173 
2174  // adjust left()
2175  while ( aOut.LogicToPixel(aSizedRect).Left() < aOrgPxRect.Left() )
2176  {
2177  aSizedRect.AdjustLeft( 1 );
2178  }
2179  // adjust right()
2180  while ( aOut.LogicToPixel(aSizedRect).Right() > aOrgPxRect.Right() )
2181  {
2182  aSizedRect.AdjustRight( -1 );
2183  }
2184  // adjust top()
2185  while ( aOut.LogicToPixel(aSizedRect).Top() < aOrgPxRect.Top() )
2186  {
2187  aSizedRect.AdjustTop( 1 );
2188  }
2189  // adjust bottom()
2190  while ( aOut.LogicToPixel(aSizedRect).Bottom() > aOrgPxRect.Bottom() )
2191  {
2192  aSizedRect.AdjustBottom( -1 );
2193  }
2194 
2195  io_aSwRect = SwRect( aSizedRect );
2196 
2197 #if OSL_DEBUG_LEVEL > 0
2198  tools::Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2199  tools::Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2200  OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect,
2201  "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
2202  // check Left()
2203  aSizedRect.AdjustLeft( -1 );
2204  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2205  OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1),
2206  "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
2207  aSizedRect.AdjustLeft( 1 );
2208  // check Right()
2209  aSizedRect.AdjustRight( 1 );
2210  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2211  OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1),
2212  "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
2213  aSizedRect.AdjustRight( -1 );
2214  // check Top()
2215  aSizedRect.AdjustTop( -1 );
2216  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2217  OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1),
2218  "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
2219  aSizedRect.AdjustTop( 1 );
2220  // check Bottom()
2221  aSizedRect.AdjustBottom( 1 );
2222  aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2223  OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1),
2224  "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
2225  aSizedRect.AdjustBottom( -1 );
2226 #endif
2227 }
2228 
2229 // FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
2230 
2231 namespace {
2232 
2233 struct SwLineEntry
2234 {
2235  SwTwips mnKey;
2236  SwTwips mnStartPos;
2237  SwTwips mnEndPos;
2238 
2239  svx::frame::Style maAttribute;
2240 
2241  enum OverlapType { NO_OVERLAP, OVERLAP1, OVERLAP2, OVERLAP3 };
2242 
2243 public:
2244  SwLineEntry( SwTwips nKey,
2245  SwTwips nStartPos,
2246  SwTwips nEndPos,
2247  const svx::frame::Style& rAttribute );
2248 
2249  OverlapType Overlaps( const SwLineEntry& rComp ) const;
2250 };
2251 
2252 }
2253 
2254 SwLineEntry::SwLineEntry( SwTwips nKey,
2255  SwTwips nStartPos,
2256  SwTwips nEndPos,
2257  const svx::frame::Style& rAttribute )
2258  : mnKey( nKey ),
2259  mnStartPos( nStartPos ),
2260  mnEndPos( nEndPos ),
2261  maAttribute( rAttribute )
2262 {
2263 }
2264 
2265 /*
2266 
2267  1. ---------- rOld
2268  ---------- rNew
2269 
2270  2. ---------- rOld
2271  ------------- rNew
2272 
2273  3. ------- rOld
2274  ------------- rNew
2275 
2276  4. ------------- rOld
2277  ---------- rNew
2278 
2279  5. ---------- rOld
2280  ---- rNew
2281 
2282  6. ---------- rOld
2283  ---------- rNew
2284 
2285  7. ------------- rOld
2286  ---------- rNew
2287 
2288  8. ---------- rOld
2289  ------------- rNew
2290 
2291  9. ---------- rOld
2292  ---------- rNew
2293 */
2294 
2295 SwLineEntry::OverlapType SwLineEntry::Overlaps( const SwLineEntry& rNew ) const
2296 {
2297  SwLineEntry::OverlapType eRet = OVERLAP3;
2298 
2299  if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos )
2300  eRet = NO_OVERLAP;
2301 
2302  // 1, 2, 3
2303  else if ( mnEndPos < rNew.mnEndPos )
2304  eRet = OVERLAP1;
2305 
2306  // 4, 5, 6, 7
2307  else if (mnStartPos <= rNew.mnStartPos)
2308  eRet = OVERLAP2;
2309 
2310  // 8, 9
2311  return eRet;
2312 }
2313 
2314 namespace {
2315 
2316 struct lt_SwLineEntry
2317 {
2318  bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const
2319  {
2320  return e1.mnStartPos < e2.mnStartPos;
2321  }
2322 };
2323 
2324 }
2325 
2326 typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet;
2327 typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap;
2328 
2329 namespace {
2330 
2331 class SwTabFramePainter
2332 {
2333  SwLineEntryMap maVertLines;
2334  SwLineEntryMap maHoriLines;
2335  const SwTabFrame& mrTabFrame;
2336 
2337  void Insert( SwLineEntry&, bool bHori );
2338  void Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect &rPaintArea);
2339  void HandleFrame(const SwLayoutFrame& rFrame, const SwRect& rPaintArea);
2340  void FindStylesForLine( const Point&,
2341  const Point&,
2343  bool bHori ) const;
2344 
2345 public:
2346  explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
2347 
2348  void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const;
2349 };
2350 
2351 }
2352 
2353 SwTabFramePainter::SwTabFramePainter( const SwTabFrame& rTabFrame )
2354  : mrTabFrame( rTabFrame )
2355 {
2356  SwRect aPaintArea = rTabFrame.GetUpper()->GetPaintArea();
2357  HandleFrame(rTabFrame, aPaintArea);
2358 }
2359 
2360 void SwTabFramePainter::HandleFrame(const SwLayoutFrame& rLayoutFrame, const SwRect& rPaintArea)
2361 {
2362  // Add border lines of cell frames. Skip covered cells. Skip cells
2363  // in special row span row, which do not have a negative row span:
2364  if ( rLayoutFrame.IsCellFrame() && !rLayoutFrame.IsCoveredCell() )
2365  {
2366  const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rLayoutFrame);
2367  const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pThisCell->GetUpper());
2368  const tools::Long nRowSpan = pThisCell->GetTabBox()->getRowSpan();
2369  if ( !pRowFrame->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 )
2370  {
2371  SwBorderAttrAccess aAccess( SwFrame::GetCache(), &rLayoutFrame );
2372  const SwBorderAttrs& rAttrs = *aAccess.Get();
2373  const SvxBoxItem& rBox = rAttrs.GetBox();
2374  Insert(rLayoutFrame, rBox, rPaintArea);
2375  }
2376  }
2377 
2378  // Recurse into lower layout frames, but do not recurse into lower tabframes.
2379  const SwFrame* pLower = rLayoutFrame.Lower();
2380  while ( pLower )
2381  {
2382  const SwLayoutFrame* pLowerLayFrame = dynamic_cast<const SwLayoutFrame*>(pLower);
2383  if ( pLowerLayFrame && !pLowerLayFrame->IsTabFrame() )
2384  HandleFrame(*pLowerLayFrame, rPaintArea);
2385 
2386  pLower = pLower->GetNext();
2387  }
2388 }
2389 
2390 void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) const
2391 {
2392  // #i16816# tagged pdf support
2393  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev );
2394 
2395  SwLineEntryMap::const_iterator aIter = maHoriLines.begin();
2396  bool bHori = true;
2397 
2398  // color for subsidiary lines:
2400 
2401  // high contrast mode:
2402  // overrides the color of non-subsidiary lines.
2403  const Color* pHCColor = nullptr;
2404  DrawModeFlags nOldDrawMode = rDev.GetDrawMode();
2405  if( gProp.pSGlobalShell->GetWin() &&
2407  {
2408  pHCColor = &SwViewOption::GetFontColor();
2409  rDev.SetDrawMode( DrawModeFlags::Default );
2410  }
2411 
2412  const SwFrame* pUpper = mrTabFrame.GetUpper();
2413  SwRect aUpper( pUpper->getFramePrintArea() );
2414  aUpper.Pos() += pUpper->getFrameArea().Pos();
2415  SwRect aUpperAligned( aUpper );
2416  ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
2417 
2418  // prepare SdrFrameBorderDataVector
2419  std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
2420  std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
2421 
2422  while ( true )
2423  {
2424  if ( bHori && aIter == maHoriLines.end() )
2425  {
2426  aIter = maVertLines.begin();
2427  bHori = false;
2428  }
2429 
2430  if ( !bHori && aIter == maVertLines.end() )
2431  break;
2432 
2433  const SwLineEntrySet& rEntrySet = (*aIter).second;
2434  for (const SwLineEntry& rEntry : rEntrySet)
2435  {
2436  const svx::frame::Style& rEntryStyle( rEntry.maAttribute );
2437 
2438  Point aStart, aEnd;
2439  if ( bHori )
2440  {
2441  aStart.setX( rEntry.mnStartPos );
2442  aStart.setY( rEntry.mnKey );
2443  aEnd.setX( rEntry.mnEndPos );
2444  aEnd.setY( rEntry.mnKey );
2445  }
2446  else
2447  {
2448  aStart.setX( rEntry.mnKey );
2449  aStart.setY( rEntry.mnStartPos );
2450  aEnd.setX( rEntry.mnKey );
2451  aEnd.setY( rEntry.mnEndPos );
2452  }
2453 
2454  svx::frame::Style aStyles[ 7 ];
2455  aStyles[ 0 ] = rEntryStyle;
2456  FindStylesForLine( aStart, aEnd, aStyles, bHori );
2457  SwRect aRepaintRect( aStart, aEnd );
2458 
2459  // the repaint rectangle has to be moved a bit for the centered lines:
2460  SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth();
2461  if ( bHori )
2462  {
2463  aRepaintRect.Height( 2 * nRepaintRectSize );
2464  aRepaintRect.Pos().AdjustY( -nRepaintRectSize );
2465 
2466  // To decide on visibility it is also necessary to expand the RepaintRect
2467  // to left/right according existing BorderLine overlap matchings, else there
2468  // will be repaint errors when scrolling in e.t TripleLine BorderLines.
2469  // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB
2470  if(aStyles[1].IsUsed() || aStyles[3].IsUsed() || aStyles[4].IsUsed() || aStyles[6].IsUsed())
2471  {
2472  const double fLineWidthMaxLeft(std::max(aStyles[1].GetWidth(), aStyles[3].GetWidth()));
2473  const double fLineWidthMaxRight(std::max(aStyles[4].GetWidth(), aStyles[6].GetWidth()));
2474  aRepaintRect.Width(aRepaintRect.Width() + (fLineWidthMaxLeft + fLineWidthMaxRight));
2475  aRepaintRect.Pos().AdjustX( -fLineWidthMaxLeft );
2476  }
2477  }
2478  else
2479  {
2480  aRepaintRect.Width( 2 * nRepaintRectSize );
2481  aRepaintRect.Pos().AdjustX( -nRepaintRectSize );
2482 
2483  // Accordingly to horizontal case, but for top/bottom
2484  // aStyles[3] == aTFromR, aStyles[1] == aTFromL, aStyles[6] == aBFromR, aStyles[4] == aBFromL
2485  if(aStyles[3].IsUsed() || aStyles[1].IsUsed() || aStyles[6].IsUsed() || aStyles[4].IsUsed())
2486  {
2487  const double fLineWidthMaxTop(std::max(aStyles[3].GetWidth(), aStyles[1].GetWidth()));
2488  const double fLineWidthMaxBottom(std::max(aStyles[6].GetWidth(), aStyles[4].GetWidth()));
2489  aRepaintRect.Height(aRepaintRect.Height() + (fLineWidthMaxTop + fLineWidthMaxBottom));
2490  aRepaintRect.Pos().AdjustY( -fLineWidthMaxTop );
2491  }
2492  }
2493 
2494  if (!rRect.IsOver(aRepaintRect))
2495  {
2496  continue;
2497  }
2498 
2499  // subsidiary lines
2500  const Color* pTmpColor = nullptr;
2501  if (0 == aStyles[ 0 ].GetWidth())
2502  {
2503  if (isTableBoundariesEnabled() && gProp.pSGlobalShell->GetWin())
2504  aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 );
2505  else
2506  aStyles[0].SetType(SvxBorderLineStyle::NONE);
2507  }
2508  else
2509  pTmpColor = pHCColor;
2510 
2511  // The (twip) positions will be adjusted to meet these requirements:
2512  // 1. The y coordinates are located in the middle of the pixel grid
2513  // 2. The x coordinated are located at the beginning of the pixel grid
2514  // This is done, because the horizontal lines are painted "at
2515  // beginning", whereas the vertical lines are painted "centered".
2516  // By making the line sizes a multiple of one pixel size, we can
2517  // assure that all lines having the same twip size have the same
2518  // pixel size, independent of their position on the screen.
2519  Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel(aStart) );
2520  Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel(aEnd) );
2521 
2522  if (gProp.pSGlobalShell->GetWin())
2523  {
2524  // The table borders do not use SwAlignRect, but all the other frames do.
2525  // Therefore we tweak the outer borders a bit to achieve that the outer
2526  // borders match the subsidiary lines of the upper:
2527  if (aStart.X() == aUpper.Left())
2528  aPaintStart.setX( aUpperAligned.Left() );
2529  else if (aStart.X() == aUpper.Right_())
2530  aPaintStart.setX( aUpperAligned.Right_() );
2531  if (aStart.Y() == aUpper.Top())
2532  aPaintStart.setY( aUpperAligned.Top() );
2533  else if (aStart.Y() == aUpper.Bottom_())
2534  aPaintStart.setY( aUpperAligned.Bottom_() );
2535 
2536  if (aEnd.X() == aUpper.Left())
2537  aPaintEnd.setX( aUpperAligned.Left() );
2538  else if (aEnd.X() == aUpper.Right_())
2539  aPaintEnd.setX( aUpperAligned.Right_() );
2540  if (aEnd.Y() == aUpper.Top())
2541  aPaintEnd.setY( aUpperAligned.Top() );
2542  else if (aEnd.Y() == aUpper.Bottom_())
2543  aPaintEnd.setY( aUpperAligned.Bottom_() );
2544  }
2545 
2546  if(aStyles[0].IsUsed())
2547  {
2548  if (bHori)
2549  {
2550  const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2551  const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2552 
2553  if(!aX.equalZero())
2554  {
2556  aData->emplace_back(
2557  aOrigin,
2558  aX,
2559  aStyles[0],
2560  pTmpColor);
2562 
2563  rInstance.addSdrConnectStyleData(true, aStyles[1], -aY, true); // aLFromT
2564  rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aLFromL
2565  rInstance.addSdrConnectStyleData(true, aStyles[3], aY, false); // aLFromB
2566 
2567  rInstance.addSdrConnectStyleData(false, aStyles[4], -aY, true); // aRFromT
2568  rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aRFromR
2569  rInstance.addSdrConnectStyleData(false, aStyles[6], aY, false); // aRFromB
2570  }
2571  }
2572  else // vertical
2573  {
2574  const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2575  const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2576 
2577  if(!aX.equalZero())
2578  {
2580  aData->emplace_back(
2581  aOrigin,
2582  aX,
2583  aStyles[0],
2584  pTmpColor);
2586 
2587  rInstance.addSdrConnectStyleData(true, aStyles[3], -aY, false); // aTFromR
2588  rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aTFromT
2589  rInstance.addSdrConnectStyleData(true, aStyles[1], aY, true); // aTFromL
2590 
2591  rInstance.addSdrConnectStyleData(false, aStyles[6], -aY, false); // aBFromR
2592  rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aBFromB
2593  rInstance.addSdrConnectStyleData(false, aStyles[4], aY, true); // aBFromL
2594  }
2595  }
2596  }
2597  }
2598  ++aIter;
2599  }
2600 
2601  // create instance of SdrFrameBorderPrimitive2D if
2602  // SdrFrameBorderDataVector is used
2603  if(!aData->empty())
2604  {
2606  aSequence.append(
2609  aData,
2610  true))); // force visualization to minimal one discrete unit (pixel)
2611  // paint
2612  mrTabFrame.ProcessPrimitives(aSequence);
2613  }
2614 
2615  // restore output device:
2616  rDev.SetDrawMode( nOldDrawMode );
2617 }
2618 
2624 void SwTabFramePainter::FindStylesForLine( const Point& rStartPoint,
2625  const Point& rEndPoint,
2626  svx::frame::Style* pStyles,
2627  bool bHori ) const
2628 {
2629  // pStyles[ 1 ] = bHori ? aLFromT : TFromL
2630  // pStyles[ 2 ] = bHori ? aLFromL : TFromT,
2631  // pStyles[ 3 ] = bHori ? aLFromB : TFromR,
2632  // pStyles[ 4 ] = bHori ? aRFromT : BFromL,
2633  // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
2634  // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
2635 
2636  SwLineEntryMap::const_iterator aMapIter = maVertLines.find( rStartPoint.X() );
2637  OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" );
2638  const SwLineEntrySet& rVertSet = (*aMapIter).second;
2639 
2640  for ( const SwLineEntry& rEntry : rVertSet )
2641  {
2642  if ( bHori )
2643  {
2644  if ( rStartPoint.Y() == rEntry.mnStartPos )
2645  pStyles[ 3 ] = rEntry.maAttribute;
2646  else if ( rStartPoint.Y() == rEntry.mnEndPos )
2647  pStyles[ 1 ] = rEntry.maAttribute;
2648  }
2649  else
2650  {
2651  if ( rStartPoint.Y() == rEntry.mnEndPos )
2652  pStyles[ 2 ] = rEntry.maAttribute;
2653  else if ( rEndPoint.Y() == rEntry.mnStartPos )
2654  pStyles[ 5 ] = rEntry.maAttribute;
2655  }
2656  }
2657 
2658  aMapIter = maHoriLines.find( rStartPoint.Y() );
2659  OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" );
2660  const SwLineEntrySet& rHoriSet = (*aMapIter).second;
2661 
2662  for ( const SwLineEntry& rEntry : rHoriSet )
2663  {
2664  if ( bHori )
2665  {
2666  if ( rStartPoint.X() == rEntry.mnEndPos )
2667  pStyles[ 2 ] = rEntry.maAttribute;
2668  else if ( rEndPoint.X() == rEntry.mnStartPos )
2669  pStyles[ 5 ] = rEntry.maAttribute;
2670  }
2671  else
2672  {
2673  if ( rStartPoint.X() == rEntry.mnEndPos )
2674  pStyles[ 1 ] = rEntry.maAttribute;
2675  else if ( rStartPoint.X() == rEntry.mnStartPos )
2676  pStyles[ 3 ] = rEntry.maAttribute;
2677  }
2678  }
2679 
2680  if ( bHori )
2681  {
2682  aMapIter = maVertLines.find( rEndPoint.X() );
2683  OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" );
2684  const SwLineEntrySet& rVertSet2 = (*aMapIter).second;
2685 
2686  for ( const SwLineEntry& rEntry : rVertSet2 )
2687  {
2688  if ( rEndPoint.Y() == rEntry.mnStartPos )
2689  pStyles[ 6 ] = rEntry.maAttribute;
2690  else if ( rEndPoint.Y() == rEntry.mnEndPos )
2691  pStyles[ 4 ] = rEntry.maAttribute;
2692  }
2693  }
2694  else
2695  {
2696  aMapIter = maHoriLines.find( rEndPoint.Y() );
2697  OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" );
2698  const SwLineEntrySet& rHoriSet2 = (*aMapIter).second;
2699 
2700  for ( const SwLineEntry& rEntry : rHoriSet2 )
2701  {
2702  if ( rEndPoint.X() == rEntry.mnEndPos )
2703  pStyles[ 4 ] = rEntry.maAttribute;
2704  else if ( rEndPoint.X() == rEntry.mnStartPos )
2705  pStyles[ 6 ] = rEntry.maAttribute;
2706  }
2707  }
2708 }
2709 
2715  SwTabFrame const& rTabFrame, SwFrame const& rFrame, SvxBoxItem const& rBoxItem)
2716 {
2717  SwRowFrame const*const pThisRowFrame =
2718  dynamic_cast<const SwRowFrame*>(rFrame.GetUpper());
2719  return (pThisRowFrame
2720  && (pThisRowFrame->GetUpper() == &rTabFrame)
2721  && rTabFrame.IsFollow()
2722  && !rTabFrame.GetTable()->GetRowsToRepeat()
2723  && ( !pThisRowFrame->GetPrev()
2724  || static_cast<const SwRowFrame*>(pThisRowFrame->GetPrev())
2725  ->IsRowSpanLine())
2726  && !rBoxItem.GetTop()
2727  && rBoxItem.GetBottom());
2728 }
2729 
2730 void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect& rPaintArea)
2731 {
2732  // build 4 line entries for the 4 borders:
2733  SwRect aBorderRect = rFrame.getFrameArea();
2734 
2735  aBorderRect.Intersection(rPaintArea);
2736 
2738  mrTabFrame, rFrame, rBoxItem));
2739  bool const bVert = mrTabFrame.IsVertical();
2740  bool const bR2L = mrTabFrame.IsRightToLeft();
2741 
2742  bool bWordTableCell = false;
2743  SwViewShell* pShell = rFrame.getRootFrame()->GetCurrShell();
2744  if (pShell)
2745  {
2746  const IDocumentSettingAccess& rIDSA = pShell->GetDoc()->getIDocumentSettingAccess();
2747  bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
2748  }
2749 
2750  // no scaling needed, it's all in the primitives and the target device
2751  svx::frame::Style aL(rBoxItem.GetLeft(), 1.0);
2752  aL.SetWordTableCell(bWordTableCell);
2753  svx::frame::Style aR(rBoxItem.GetRight(), 1.0);
2754  aR.SetWordTableCell(bWordTableCell);
2755  svx::frame::Style aT(rBoxItem.GetTop(), 1.0);
2756  aT.SetWordTableCell(bWordTableCell);
2757  svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
2758  aB.SetWordTableCell(bWordTableCell);
2759 
2760  aR.MirrorSelf();
2761  aB.MirrorSelf();
2762 
2763  const SwTwips nLeft = aBorderRect.Left_();
2764  const SwTwips nRight = aBorderRect.Right_();
2765  const SwTwips nTop = aBorderRect.Top_();
2766  const SwTwips nBottom = aBorderRect.Bottom_();
2767 
2768  aL.SetRefMode( svx::frame::RefMode::Centered );
2769  aR.SetRefMode( svx::frame::RefMode::Centered );
2770  aT.SetRefMode( !bVert ? svx::frame::RefMode::Begin : svx::frame::RefMode::End );
2771  aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : svx::frame::RefMode::End );
2772 
2773  SwLineEntry aLeft (nLeft, nTop, nBottom,
2774  bVert ? aB : (bR2L ? aR : aL));
2775  SwLineEntry aRight (nRight, nTop, nBottom,
2776  bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
2777  SwLineEntry aTop (nTop, nLeft, nRight,
2778  bVert ? aL : (bBottomAsTop ? aB : aT));
2779  SwLineEntry aBottom(nBottom, nLeft, nRight,
2780  bVert ? aR : aB);
2781 
2782  Insert( aLeft, false );
2783  Insert( aRight, false );
2784  Insert( aTop, true );
2785  Insert( aBottom, true );
2786 }
2787 
2788 void SwTabFramePainter::Insert( SwLineEntry& rNew, bool bHori )
2789 {
2790  // get all lines from structure, that have key entry of pLE
2791  SwLineEntryMap* pLine2 = bHori ? &maHoriLines : &maVertLines;
2792  const SwTwips nKey = rNew.mnKey;
2793  SwLineEntryMap::iterator aMapIter = pLine2->find( nKey );
2794 
2795  SwLineEntrySet* pLineSet = aMapIter != pLine2->end() ? &((*aMapIter).second) : nullptr;
2796  if ( !pLineSet )
2797  {
2798  SwLineEntrySet aNewSet;
2799  (*pLine2)[ nKey ] = aNewSet;
2800  pLineSet = &(*pLine2)[ nKey ];
2801  }
2802  SwLineEntrySet::iterator aIter = pLineSet->begin();
2803 
2804  while ( aIter != pLineSet->end() && rNew.mnStartPos < rNew.mnEndPos )
2805  {
2806  const SwLineEntry& rOld = *aIter;
2807  const SwLineEntry::OverlapType nOverlapType = rOld.Overlaps( rNew );
2808 
2809  const svx::frame::Style& rOldAttr = rOld.maAttribute;
2810  const svx::frame::Style& rNewAttr = rNew.maAttribute;
2811  const svx::frame::Style& rCmpAttr = std::max(rNewAttr, rOldAttr);
2812 
2813  if ( SwLineEntry::OVERLAP1 == nOverlapType )
2814  {
2815  OSL_ENSURE( rNew.mnStartPos >= rOld.mnStartPos, "Overlap type 3? How this?" );
2816 
2817  // new left segment
2818  const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2819 
2820  // new middle segment
2821  const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rOld.mnEndPos, rCmpAttr );
2822 
2823  // new right segment
2824  rNew.mnStartPos = rOld.mnEndPos;
2825 
2826  // update current lines set
2827  pLineSet->erase( aIter );
2828  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2829  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2830 
2831  aIter = pLineSet->begin();
2832 
2833  continue; // start over
2834  }
2835  else if ( SwLineEntry::OVERLAP2 == nOverlapType )
2836  {
2837  // new left segment
2838  const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2839 
2840  // new middle segment
2841  const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rNew.mnEndPos, rCmpAttr );
2842 
2843  // new right segment
2844  const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2845 
2846  // update current lines set
2847  pLineSet->erase( aIter );
2848  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2849  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2850  if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2851 
2852  rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2853 
2854  break; // we are finished
2855  }
2856  else if ( SwLineEntry::OVERLAP3 == nOverlapType )
2857  {
2858  // new left segment
2859  const SwLineEntry aLeft( nKey, rNew.mnStartPos, rOld.mnStartPos, rNewAttr );
2860 
2861  // new middle segment
2862  const SwLineEntry aMiddle( nKey, rOld.mnStartPos, rNew.mnEndPos, rCmpAttr );
2863 
2864  // new right segment
2865  const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2866 
2867  // update current lines set
2868  pLineSet->erase( aIter );
2869  if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2870  if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2871  if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2872 
2873  rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2874 
2875  break; // we are finished
2876  }
2877 
2878  ++aIter;
2879  }
2880 
2881  if ( rNew.mnStartPos < rNew.mnEndPos ) // insert rest
2882  pLineSet->insert( rNew );
2883 }
2884 
2889 namespace
2890 {
2891  class SwViewObjectContactRedirector : public sdr::contact::ViewObjectContactRedirector
2892  {
2893  private:
2894  const SwViewShell& mrViewShell;
2895 
2896  public:
2897  explicit SwViewObjectContactRedirector( const SwViewShell& rSh )
2898  : mrViewShell( rSh )
2899  {};
2900 
2902  const sdr::contact::ViewObjectContact& rOriginal,
2903  const sdr::contact::DisplayInfo& rDisplayInfo) override
2904  {
2905  bool bPaint( true );
2906 
2907  SdrObject* pObj = rOriginal.GetViewContact().TryToGetSdrObject();
2908  if ( pObj )
2909  {
2910  bPaint = SwFlyFrame::IsPaint( pObj, &mrViewShell );
2911  }
2912 
2913  if ( !bPaint )
2914  {
2916  }
2917 
2919  rOriginal, rDisplayInfo );
2920  }
2921  };
2922 
2923 } // end of anonymous namespace
2924 // <--
2925 
2935 void SwRootFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const pPrintData) const
2936 {
2937  OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." );
2938 
2939  PROTOCOL( this, PROT::FileInit, DbgAction::NONE, nullptr)
2940 
2941  bool bResetRootPaint = false;
2942  SwViewShell *pSh = mpCurrShell;
2943 
2944  if ( pSh->GetWin() )
2945  {
2946  if ( pSh->GetOut() == pSh->GetWin() && !pSh->GetWin()->IsVisible() )
2947  {
2948  return;
2949  }
2951  {
2952  SwPaintQueue::Add( pSh, rRect );
2953  return;
2954  }
2955  }
2956  else
2957  SwRootFrame::s_isInPaint = bResetRootPaint = true;
2958 
2959  std::unique_ptr<SwSavePaintStatics> pStatics;
2960  if ( gProp.pSGlobalShell )
2961  pStatics.reset(new SwSavePaintStatics());
2962  gProp.pSGlobalShell = pSh;
2963 
2964  if( !pSh->GetWin() )
2965  gProp.pSProgress = SfxProgress::GetActiveProgress( static_cast<SfxObjectShell*>(pSh->GetDoc()->GetDocShell()) );
2966 
2967  ::SwCalcPixStatics( pSh->GetOut() );
2968  aGlobalRetoucheColor = pSh->Imp()->GetRetoucheColor();
2969 
2970  // Copy rRect; for one, rRect could become dangling during the below action, and for another it
2971  // needs to be copied to aRect anyway as that is modified further down below:
2972  SwRect aRect( rRect );
2973 
2974  //Trigger an action to clear things up if needed.
2975  //Using this trick we can ensure that all values are valid in all paints -
2976  //no problems, no special case(s).
2977  // #i92745#
2978  // Extend check on certain states of the 'current' <SwViewShell> instance to
2979  // all existing <SwViewShell> instances.
2980  bool bPerformLayoutAction( true );
2981  {
2982  for(SwViewShell& rTmpViewShell : pSh->GetRingContainer())
2983  {
2984  if ( rTmpViewShell.IsInEndAction() ||
2985  rTmpViewShell.IsPaintInProgress() ||
2986  ( rTmpViewShell.Imp()->IsAction() &&
2987  rTmpViewShell.Imp()->GetLayAction().IsActionInProgress() ) )
2988  {
2989  bPerformLayoutAction = false;
2990  }
2991 
2992  if(!bPerformLayoutAction)
2993  break;
2994  }
2995  }
2996  if ( bPerformLayoutAction )
2997  {
2998  const_cast<SwRootFrame*>(this)->ResetTurbo();
2999  SwLayAction aAction( const_cast<SwRootFrame*>(this), pSh->Imp() );
3000  aAction.SetPaint( false );
3001  aAction.SetComplete( false );
3002  aAction.SetReschedule( gProp.pSProgress != nullptr );
3003  aAction.Action(&rRenderContext);
3004  ResetTurboFlag();
3005  if ( !pSh->ActionPend() )
3006  pSh->Imp()->DelRegion();
3007  }
3008 
3009  aRect.Intersection( pSh->VisArea() );
3010 
3011  const bool bExtraData = ::IsExtraData( GetFormat()->GetDoc() );
3012 
3013  gProp.pSLines.reset(new SwLineRects); // Container for borders.
3014 
3015  // #104289#. During painting, something (OLE) can
3016  // load the linguistic, which in turn can cause a reformat
3017  // of the document. Dangerous! We better set this flag to
3018  // avoid the reformat.
3019  const bool bOldAction = IsCallbackActionEnabled();
3020  const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( false );
3021 
3022  const SwPageFrame *pPage = pSh->Imp()->GetFirstVisPage(&rRenderContext);
3023 
3024  // #126222. The positions of headers and footers of the previous
3025  // pages have to be updated, else these headers and footers could
3026  // get visible at a wrong position.
3027  const SwPageFrame *pPageDeco = static_cast<const SwPageFrame*>(pPage->GetPrev());
3028  while (pPageDeco)
3029  {
3030  pPageDeco->PaintDecorators();
3031  OSL_ENSURE(!pPageDeco->GetPrev() || pPageDeco->GetPrev()->IsPageFrame(),
3032  "Neighbour of page is not a page.");
3033  pPageDeco = static_cast<const SwPageFrame*>(pPageDeco->GetPrev());
3034  }
3035 
3036  const bool bBookMode = gProp.pSGlobalShell->GetViewOptions()->IsViewLayoutBookMode();
3037  if ( bBookMode && pPage->GetPrev() && static_cast<const SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
3038  pPage = static_cast<const SwPageFrame*>(pPage->GetPrev());
3039 
3040  // #i68597#
3041  const bool bGridPainting(pSh->GetWin() && pSh->Imp()->HasDrawView() && pSh->Imp()->GetDrawView()->IsGridVisible());
3042 
3043  // Hide all page break controls before showing them again
3044  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3045  if ( pWrtSh )
3046  {
3047  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3048  SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3049  const SwPageFrame* pHiddenPage = pPage;
3050  while ( pHiddenPage->GetPrev() != nullptr )
3051  {
3052  pHiddenPage = static_cast< const SwPageFrame* >( pHiddenPage->GetPrev() );
3053  SwFrameControlPtr pControl = rMngr.GetControl( FrameControlType::PageBreak, pHiddenPage );
3054  if ( pControl )
3055  pControl->ShowAll( false );
3056  }
3057  }
3058 
3059  // #i76669#
3060  SwViewObjectContactRedirector aSwRedirector( *pSh );
3061 
3062  while ( pPage )
3063  {
3064  const bool bPaintRightShadow = pPage->IsRightShadowNeeded();
3065  const bool bPaintLeftShadow = pPage->IsLeftShadowNeeded();
3066  const bool bRightSidebar = pPage->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
3067 
3068  if ( !pPage->IsEmptyPage() )
3069  {
3070  SwRect aPaintRect;
3071  SwPageFrame::GetBorderAndShadowBoundRect( pPage->getFrameArea(), pSh, &rRenderContext, aPaintRect,
3072  bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3073 
3074  if ( aRect.IsOver( aPaintRect ) )
3075  {
3076  if ( pSh->GetWin() )
3077  {
3078  gProp.pSSubsLines.reset(new SwSubsRects);
3079  gProp.pSSpecSubsLines.reset(new SwSubsRects);
3080  }
3081  gProp.pBLines.reset(new BorderLines);
3082 
3083  aPaintRect.Intersection_( aRect );
3084 
3085  if ( bExtraData &&
3086  pSh->GetWin() && pSh->IsInEndAction() )
3087  {
3088  // enlarge paint rectangle to complete page width, subtract
3089  // current paint area and invalidate the resulting region.
3090  SwRectFnSet aRectFnSet(pPage);
3091  SwRect aPageRectTemp( aPaintRect );
3092  aRectFnSet.SetLeftAndWidth( aPageRectTemp,
3093  aRectFnSet.GetLeft(pPage->getFrameArea()),
3094  aRectFnSet.GetWidth(pPage->getFrameArea()) );
3095  aPageRectTemp.Intersection_( pSh->VisArea() );
3096  vcl::Region aPageRectRegion( aPageRectTemp.SVRect() );
3097  aPageRectRegion.Exclude( aPaintRect.SVRect() );
3098  pSh->GetWin()->Invalidate( aPageRectRegion, InvalidateFlags::Children );
3099  }
3100 
3101  // #i80793#
3102  // enlarge paint rectangle for objects overlapping the same pixel
3103  // in all cases and before the DrawingLayer overlay is initialized.
3104  lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3105 
3106  // #i68597#
3107  // moved paint pre-process for DrawingLayer overlay here since the above
3108  // code dependent from bExtraData may expand the PaintRect
3109  {
3110  // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3111  // really be used but handled by SwViewShell::ImplEndAction already
3112  const vcl::Region aDLRegion(aPaintRect.SVRect());
3113  pSh->DLPrePaint2(aDLRegion);
3114  }
3115 
3116  if(OUTDEV_WINDOW == gProp.pSGlobalShell->GetOut()->GetOutDevType())
3117  {
3118  // changed method SwLayVout::Enter(..)
3119  // 2nd parameter is no longer <const> and will be set to the
3120  // rectangle the virtual output device is calculated from <aPaintRect>,
3121  // if the virtual output is used.
3122  s_pVout->Enter(pSh, aPaintRect, !s_isNoVirDev);
3123 
3124  // Adjust paint rectangle to pixel size
3125  // Thus, all objects overlapping on pixel level with the unadjusted
3126  // paint rectangle will be considered in the paint.
3127  lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3128  }
3129 
3130  // maybe this can be put in the above scope. Since we are not sure, just leave it ATM
3131  s_pVout->SetOrgRect( aPaintRect );
3132 
3133  // determine background color of page for <PaintLayer> method
3134  // calls, paint <hell> or <heaven>
3135  const Color aPageBackgrdColor(pPage->GetDrawBackgrdColor());
3136 
3137  pPage->PaintBaBo( aPaintRect, pPage );
3138 
3139  if ( pSh->Imp()->HasDrawView() )
3140  {
3141  gProp.pSLines->LockLines( true );
3143  pSh->Imp()->PaintLayer( rIDDMA.GetHellId(),
3144  pPrintData,
3145  *pPage, pPage->getFrameArea(),
3146  &aPageBackgrdColor,
3147  pPage->IsRightToLeft(),
3148  &aSwRedirector );
3149  gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3150  gProp.pSLines->LockLines( false );
3151  }
3152 
3154  pPage->PaintBaBo( aPaintRect, pPage, /*bOnlyTextBackground=*/true );
3155 
3156  if( pSh->GetWin() )
3157  {
3158  // collect sub-lines
3159  pPage->RefreshSubsidiary( aPaintRect );
3160  // paint special sub-lines
3161  gProp.pSSpecSubsLines->PaintSubsidiary( pSh->GetOut(), nullptr, gProp );
3162  }
3163 
3164  pPage->PaintSwFrame( rRenderContext, aPaintRect );
3165 
3166  // no paint of page border and shadow, if writer is in place mode.
3167  if( pSh->GetWin() && pSh->GetDoc()->GetDocShell() &&
3168  !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3169  {
3170  SwPageFrame::PaintBorderAndShadow( pPage->getFrameArea(), pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3171  SwPageFrame::PaintNotesSidebar( pPage->getFrameArea(), pSh, pPage->GetPhyPageNum(), bRightSidebar);
3172  }
3173 
3174  gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3175  if ( pSh->GetWin() )
3176  {
3177  gProp.pSSubsLines->PaintSubsidiary( pSh->GetOut(), gProp.pSLines.get(), gProp );
3178  gProp.pSSubsLines.reset();
3179  gProp.pSSpecSubsLines.reset();
3180  }
3181  // fdo#42750: delay painting these until after subsidiary lines
3182  // fdo#45562: delay painting these until after hell layer
3183  // fdo#47717: but do it before heaven layer
3184  ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
3185 
3186  if ( pSh->Imp()->HasDrawView() )
3187  {
3189  pPrintData,
3190  *pPage, pPage->getFrameArea(),
3191  &aPageBackgrdColor,
3192  pPage->IsRightToLeft(),
3193  &aSwRedirector );
3194  }
3195 
3196  if ( bExtraData )
3197  pPage->RefreshExtraData( aPaintRect );
3198 
3199  gProp.pBLines.reset();
3200  s_pVout->Leave();
3201 
3202  // #i68597#
3203  // needed to move grid painting inside Begin/EndDrawLayer bounds and to change
3204  // output rect for it accordingly
3205  if(bGridPainting)
3206  {
3207  SdrPaintView* pPaintView = pSh->Imp()->GetDrawView();
3208  SdrPageView* pPageView = pPaintView->GetSdrPageView();
3209  pPageView->DrawPageViewGrid(*pSh->GetOut(), aPaintRect.SVRect(), SwViewOption::GetTextGridColor() );
3210  }
3211 
3212  // #i68597#
3213  // moved paint post-process for DrawingLayer overlay here, see above
3214  {
3215  pSh->DLPostPaint2(true);
3216  }
3217  }
3218 
3219  pPage->PaintDecorators( );
3220  pPage->PaintBreak();
3221  }
3222  else if ( bBookMode && pSh->GetWin() && !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3223  {
3224  // paint empty page
3225  SwRect aPaintRect;
3226  SwRect aEmptyPageRect( pPage->getFrameArea() );
3227 
3228  // code from vprint.cxx
3229  const SwPageFrame& rFormatPage = pPage->GetFormatPage();
3230  aEmptyPageRect.SSize( rFormatPage.getFrameArea().SSize() );
3231 
3232  SwPageFrame::GetBorderAndShadowBoundRect( aEmptyPageRect, pSh, &rRenderContext, aPaintRect,
3233  bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3234  aPaintRect.Intersection_( aRect );
3235 
3236  if ( aRect.IsOver( aEmptyPageRect ) )
3237  {
3238  // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3239  // really be used but handled by SwViewShell::ImplEndAction already
3240  {
3241  const vcl::Region aDLRegion(aPaintRect.SVRect());
3242  pSh->DLPrePaint2(aDLRegion);
3243  }
3244 
3245  if( pSh->GetOut()->GetFillColor() != aGlobalRetoucheColor )
3246  pSh->GetOut()->SetFillColor( aGlobalRetoucheColor );
3247  // No line color
3248  pSh->GetOut()->SetLineColor();
3249  // Use aligned page rectangle
3250  {
3251  SwRect aTmpPageRect( aEmptyPageRect );
3252  ::SwAlignRect( aTmpPageRect, pSh, &rRenderContext );
3253  aEmptyPageRect = aTmpPageRect;
3254  }
3255 
3256  pSh->GetOut()->DrawRect( aEmptyPageRect.SVRect() );
3257 
3258  // paint empty page text
3259  const vcl::Font& rEmptyPageFont = SwPageFrame::GetEmptyPageFont();
3260  const vcl::Font aOldFont( pSh->GetOut()->GetFont() );
3261 
3262  pSh->GetOut()->SetFont( rEmptyPageFont );
3263  pSh->GetOut()->DrawText( aEmptyPageRect.SVRect(), SwResId( STR_EMPTYPAGE ),
3264  DrawTextFlags::VCenter |
3265  DrawTextFlags::Center |
3266  DrawTextFlags::Clip );
3267 
3268  pSh->GetOut()->SetFont( aOldFont );
3269  // paint shadow and border for empty page
3270  SwPageFrame::PaintBorderAndShadow( aEmptyPageRect, pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3271  SwPageFrame::PaintNotesSidebar( aEmptyPageRect, pSh, pPage->GetPhyPageNum(), bRightSidebar);
3272 
3273  {
3274  pSh->DLPostPaint2(true);
3275  }
3276  }
3277  }
3278 
3279  OSL_ENSURE( !pPage->GetNext() || pPage->GetNext()->IsPageFrame(),
3280  "Neighbour of page is not a page." );
3281  pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
3282  }
3283 
3284  gProp.pSLines.reset();
3285 
3286  if ( bResetRootPaint )
3287  SwRootFrame::s_isInPaint = false;
3288  if ( pStatics )
3289  pStatics.reset();
3290  else
3291  {
3292  gProp.pSProgress = nullptr;
3293  gProp.pSGlobalShell = nullptr;
3294  }
3295 
3296  const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( bOldAction );
3297 }
3298 
3300 {
3301  vcl::RenderContext* pRenderContext = pCont->getRootFrame()->GetCurrShell()->GetOut();
3302 
3303  //It's possible that the Cont will get destroyed.
3304  SwContentFrame *pCnt = pCont->ContainsContent();
3305  while ( pCnt && pCnt->IsInFootnote() )
3306  {
3307  pCnt->Calc(pRenderContext);
3308  pCnt = pCnt->GetNextContentFrame();
3309  }
3310 }
3311 
3312 namespace {
3313 
3314 class SwShortCut
3315 {
3316  SwRectDist fnCheck;
3317  tools::Long nLimit;
3318 public:
3319  SwShortCut( const SwFrame& rFrame, const SwRect& rRect );
3320  bool Stop( const SwRect& rRect ) const
3321  { return (rRect.*fnCheck)( nLimit ) > 0; }
3322 };
3323 
3324 }
3325 
3326 SwShortCut::SwShortCut( const SwFrame& rFrame, const SwRect& rRect )
3327 {
3328  bool bVert = rFrame.IsVertical();
3329  bool bR2L = rFrame.IsRightToLeft();
3330  if( rFrame.IsNeighbourFrame() && bVert == bR2L )
3331  {
3332  if( bVert )
3333  {
3334  fnCheck = &SwRect::GetBottomDistance;
3335  nLimit = rRect.Top();
3336  }
3337  else
3338  {
3339  fnCheck = &SwRect::GetLeftDistance;
3340  nLimit = rRect.Left() + rRect.Width();
3341  }
3342  }
3343  else if( bVert == rFrame.IsNeighbourFrame() )
3344  {
3345  fnCheck = &SwRect::GetTopDistance;
3346  nLimit = rRect.Top() + rRect.Height();
3347  }
3348  else
3349  {
3350  if ( rFrame.IsVertLR() )
3351  {
3352  fnCheck = &SwRect::GetLeftDistance;
3353  nLimit = rRect.Right();
3354  }
3355  else
3356  {
3357  fnCheck = &SwRect::GetRightDistance;
3358  nLimit = rRect.Left();
3359  }
3360  }
3361 }
3362 
3363 void SwLayoutFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3364 {
3365  // #i16816# tagged pdf support
3366  Frame_Info aFrameInfo( *this );
3367  SwTaggedPDFHelper aTaggedPDFHelper( nullptr, &aFrameInfo, nullptr, rRenderContext );
3368 
3369  const SwFrame *pFrame = Lower();
3370  if ( !pFrame )
3371  return;
3372 
3373  SwFrameDeleteGuard g(const_cast<SwLayoutFrame*>(this)); // lock because Calc() and recursion
3374  SwShortCut aShortCut( *pFrame, rRect );
3375  bool bCnt = pFrame->IsContentFrame();
3376  if ( bCnt )
3377  pFrame->Calc(&rRenderContext);
3378 
3379  if ( pFrame->IsFootnoteContFrame() )
3380  {
3381  ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame)) );
3382  pFrame = Lower();
3383  }
3384 
3385  const SwPageFrame *pPage = nullptr;
3386  bool bWin = gProp.pSGlobalShell->GetWin() != nullptr;
3388  // Tiled rendering is similar to printing in this case: painting transparently multiple
3389  // times will result in darker colors: avoid that.
3390  bWin = false;
3391 
3392  while ( IsAnLower( pFrame ) )
3393  {
3394  SwRect aPaintRect( pFrame->GetPaintArea() );
3395  if( aShortCut.Stop( aPaintRect ) )
3396  break;
3397  if ( bCnt && gProp.pSProgress )
3399 
3400  //We need to retouch if a frame explicitly requests it.
3401  //First do the retouch, because this could flatten the borders.
3402  if ( pFrame->IsRetouche() )
3403  {
3404  if ( pFrame->IsRetoucheFrame() && bWin && !pFrame->GetNext() )
3405  {
3406  if ( !pPage )
3407  pPage = FindPageFrame();
3408  pFrame->Retouch( pPage, rRect );
3409  }
3410  pFrame->ResetRetouche();
3411  }
3412 
3413  if ( rRect.IsOver( aPaintRect ) )
3414  {
3415  if ( bCnt && pFrame->IsCompletePaint() &&
3416  !rRect.IsInside( aPaintRect ) && Application::AnyInput( VclInputFlags::KEYBOARD ) )
3417  {
3418  //fix(8104): It may happen, that the processing wasn't complete
3419  //but some parts of the paragraph were still repainted.
3420  //This could lead to the situation, that other parts of the
3421  //paragraph won't be repainted at all. The only solution seems
3422  //to be an invalidation of the window.
3423  //To not make it too severe the rectangle is limited by
3424  //painting the desired part and only invalidating the
3425  //remaining paragraph parts.
3426  if ( aPaintRect.Left() == rRect.Left() &&
3427  aPaintRect.Right() == rRect.Right() )
3428  {
3429  aPaintRect.Bottom( rRect.Top() - 1 );
3430  if ( aPaintRect.Height() > 0 )
3431  gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3432  aPaintRect.Top( rRect.Bottom() + 1 );
3433  aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3434  if ( aPaintRect.Height() > 0 )
3435  gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3436  aPaintRect.Top( pFrame->getFrameArea().Top() );
3437  aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3438  }
3439  else
3440  {
3441  gProp.pSGlobalShell->InvalidateWindows( aPaintRect );
3442  pFrame = pFrame->GetNext();
3443  if ( pFrame )
3444  {
3445  bCnt = pFrame->IsContentFrame();
3446  if ( bCnt )
3447  pFrame->Calc(&rRenderContext);
3448  }
3449  continue;
3450  }
3451  }
3452  pFrame->ResetCompletePaint();
3453  aPaintRect.Intersection_( rRect );
3454 
3455  pFrame->PaintSwFrame( rRenderContext, aPaintRect );
3456 
3457  if ( Lower() && Lower()->IsColumnFrame() )
3458  {
3459  //Paint the column separator line if needed. The page is
3460  //responsible for the page frame - not the upper.
3461  const SwFrameFormat *pFormat = GetUpper() && GetUpper()->IsPageFrame()
3462  ? GetUpper()->GetFormat()
3463  : GetFormat();
3464  const SwFormatCol &rCol = pFormat->GetCol();
3465  if ( rCol.GetLineAdj() != COLADJ_NONE )
3466  {
3467  if ( !pPage )
3468  pPage = pFrame->FindPageFrame();
3469 
3470  PaintColLines( aPaintRect, rCol, pPage );
3471  }
3472  }
3473  }
3474  if ( !bCnt && pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame() )
3475  ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame->GetNext())) );
3476 
3477  pFrame = pFrame->GetNext();
3478 
3479  if ( pFrame )
3480  {
3481  bCnt = pFrame->IsContentFrame();
3482  if ( bCnt )
3483  pFrame->Calc(&rRenderContext);
3484  }
3485  }
3486 }
3487 
3489  const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
3490  basegfx::BColor aColor )
3491 {
3493 
3494  std::vector< double > aStrokePattern;
3495  basegfx::B2DPolygon aLinePolygon;
3496  aLinePolygon.append(rStart);
3497  aLinePolygon.append(rEnd);
3498 
3500  if ( rSettings.GetHighContrastMode( ) )
3501  {
3502  // Only a solid line in high contrast mode
3503  aColor = rSettings.GetDialogTextColor().getBColor();
3504  }
3505  else
3506  {
3507  // Get a color for the contrast
3508  basegfx::BColor aHslLine = basegfx::utils::rgb2hsl( aColor );
3509  double nLuminance = aHslLine.getZ() * 2.5;
3510  if ( nLuminance == 0 )
3511  nLuminance = 0.5;
3512  else if ( nLuminance >= 1.0 )
3513  nLuminance = aHslLine.getZ() * 0.4;
3514  aHslLine.setZ( nLuminance );
3515  const basegfx::BColor aOtherColor = basegfx::utils::hsl2rgb( aHslLine );
3516 
3517  // Compute the plain line
3520  aLinePolygon, aOtherColor );
3521 
3522  aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( pPlainLine );
3523 
3524  // Dashed line in twips
3525  aStrokePattern.push_back( 40 );
3526  aStrokePattern.push_back( 40 );
3527 
3528  aSeq.resize( 2 );
3529  }
3530 
3531  // Compute the dashed line primitive
3534  basegfx::B2DPolyPolygon( aLinePolygon ),
3536  drawinglayer::attribute::StrokeAttribute( aStrokePattern ) );
3537 
3538  aSeq[ aSeq.size( ) - 1 ] = drawinglayer::primitive2d::Primitive2DReference( pLine );
3539 
3540  return aSeq;
3541 }
3542 
3544 {
3545  if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
3546  gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() ||
3547  gProp.pSGlobalShell->GetViewOptions()->IsReadonly() ||
3548  gProp.pSGlobalShell->IsPreview() )
3549  return;
3550 
3551  const SwFrame* pBodyFrame = Lower();
3552  while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3553  pBodyFrame = pBodyFrame->GetNext();
3554 
3555  if ( pBodyFrame )
3556  {
3557  const SwLayoutFrame* pLayBody = static_cast< const SwLayoutFrame* >( pBodyFrame );
3558  const SwFlowFrame *pFlowFrame = pLayBody->ContainsContent();
3559 
3560  // Test if the first node is a table
3561  const SwFrame* pFirstFrame = pLayBody->Lower();
3562  if ( pFirstFrame && pFirstFrame->IsTabFrame() )
3563  pFlowFrame = static_cast< const SwTabFrame* >( pFirstFrame );
3564 
3565  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3566  if ( pWrtSh )
3567  {
3568  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3569  SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3570 
3571  if ( pFlowFrame && pFlowFrame->IsPageBreak( true ) )
3572  rMngr.SetPageBreakControl( this );
3573  else
3575  }
3576  }
3578 }
3579 
3581 {
3582  if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
3583  gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() ||
3584  gProp.pSGlobalShell->GetViewOptions()->IsReadonly() ||
3585  gProp.pSGlobalShell->IsPreview() )
3586  return;
3587 
3588  const SwFrame* pBodyFrame = Lower();
3589  while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3590  pBodyFrame = pBodyFrame->GetNext();
3591 
3592  if ( !pBodyFrame )
3593  return;
3594 
3595  const SwContentFrame *pCnt = static_cast< const SwLayoutFrame* >( pBodyFrame )->ContainsContent();
3596  if ( !(pCnt && pCnt->IsColBreak( true )) )
3597  return;
3598 
3599  // Paint the break only if:
3600  // * Not in header footer edition, to avoid conflicts with the
3601  // header/footer marker
3602  // * Non-printing characters are shown, as this is more consistent
3603  // with other formatting marks
3604  if ( !(!gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
3605  !gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) &&
3606  gProp.pSGlobalShell->GetViewOptions()->IsLineBreak()) )
3607  return;
3608 
3609  SwRect aRect( pCnt->getFramePrintArea() );
3610  aRect.Pos() += pCnt->getFrameArea().Pos();
3611 
3612  // Draw the line
3613  basegfx::B2DPoint aStart( double( aRect.Left() ), aRect.Top() );
3614  basegfx::B2DPoint aEnd( double( aRect.Right() ), aRect.Top() );
3615  double nWidth = aRect.Width();
3616  if ( IsVertical( ) )
3617  {
3618  aStart = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Top() ) );
3619  aEnd = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Bottom() ) );
3620  nWidth = aRect.Height();
3621  }
3622 
3624 
3626  lcl_CreateDashedIndicatorPrimitive( aStart, aEnd, aLineColor );
3627 
3628  // Add the text above
3629  OUString aBreakText = SwResId(STR_COLUMN_BREAK);
3630 
3631  basegfx::B2DVector aFontSize;
3632  OutputDevice* pOut = gProp.pSGlobalShell->GetOut();
3633  vcl::Font aFont = pOut->GetSettings().GetStyleSettings().GetToolFont();
3634  aFont.SetFontHeight( 8 * 20 );
3635  pOut->SetFont( aFont );
3637  aFontSize, aFont, IsRightToLeft(), false );
3638 
3639  tools::Rectangle aTextRect;
3640  pOut->GetTextBoundRect( aTextRect, aBreakText );
3641  tools::Long nTextOff = ( nWidth - aTextRect.GetWidth() ) / 2;
3642 
3644  aFontSize.getX(), aFontSize.getY(),
3645  aRect.Left() + nTextOff, aRect.Top() ) );
3646  if ( IsVertical() )
3647  {
3649  aFontSize.getX(), aFontSize.getY(), 0.0, M_PI_2,
3650  aRect.Right(), aRect.Top() + nTextOff );
3651  }
3652 
3655  aTextMatrix,
3656  aBreakText, 0, aBreakText.getLength(),
3657  std::vector< double >(),
3658  aFontAttr,
3659  lang::Locale(),
3660  aLineColor );
3661  aSeq.push_back( drawinglayer::primitive2d::Primitive2DReference( pText ) );
3662 
3663  ProcessPrimitives( aSeq );
3664 }
3665 
3667 {
3668  const SwFrame* pFrame = Lower();
3669  while ( pFrame )
3670  {
3671  if ( pFrame->IsLayoutFrame() )
3672  static_cast< const SwLayoutFrame*>( pFrame )->PaintBreak( );
3673  pFrame = pFrame->GetNext();
3674  }
3675 }
3676 
3678 {
3679  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3680  if ( !pWrtSh )
3681  return;
3682 
3683  SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3684 
3685  const SwLayoutFrame* pBody = FindBodyCont();
3686  if ( !pBody )
3687  return;
3688 
3689  SwRect aBodyRect( pBody->getFrameArea() );
3690 
3691  if ( !(gProp.pSGlobalShell->GetOut()->GetOutDevType() != OUTDEV_PRINTER &&
3692  !gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() &&
3693  !gProp.pSGlobalShell->IsPreview() &&
3694  !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
3695  !gProp.pSGlobalShell->GetViewOptions()->getBrowseMode() &&
3696  ( gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) ||
3697  gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) )) )
3698  return;
3699 
3700  bool bRtl = AllSettings::GetLayoutRTL();
3701  const SwRect& rVisArea = gProp.pSGlobalShell->VisArea();
3702  tools::Long nXOff = std::min( aBodyRect.Right(), rVisArea.Right() );
3703  if ( bRtl )
3704  nXOff = std::max( aBodyRect.Left(), rVisArea.Left() );
3705 
3706  // Header
3707  if ( gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) )
3708  {
3709  const SwFrame* pHeaderFrame = Lower();
3710  if ( !pHeaderFrame->IsHeaderFrame() )
3711  pHeaderFrame = nullptr;
3712 
3713  tools::Long nHeaderYOff = aBodyRect.Top();
3714  Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nHeaderYOff ) );
3716  }
3717 
3718  // Footer
3719  if ( !gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
3720  return;
3721 
3722  const SwFrame* pFootnoteContFrame = Lower();
3723  while ( pFootnoteContFrame )
3724  {
3725  if ( pFootnoteContFrame->IsFootnoteContFrame() )
3726  aBodyRect.AddBottom( pFootnoteContFrame->getFrameArea().Bottom() - aBodyRect.Bottom() );
3727  pFootnoteContFrame = pFootnoteContFrame->GetNext();
3728  }
3729 
3730  tools::Long nFooterYOff = aBodyRect.Bottom();
3731  Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nFooterYOff ) );
3733 }
3734 
3749 {
3750  bool bBackgroundTransparent = GetFormat()->IsBackgroundTransparent();
3751  if ( !bBackgroundTransparent &&
3752  GetFormat()->IsBackgroundBrushInherited() )
3753  {
3754  const SvxBrushItem* pBackgrdBrush = nullptr;
3755  const Color* pSectionTOXColor = nullptr;
3756  SwRect aDummyRect;
3758 
3759  if ( GetBackgroundBrush( aFillAttributes, pBackgrdBrush, pSectionTOXColor, aDummyRect, false, /*bConsiderTextBox=*/false) )
3760  {
3761  if ( pSectionTOXColor &&
3762  (pSectionTOXColor->GetTransparency() != 0) &&
3763  (*pSectionTOXColor != COL_TRANSPARENT) )
3764  {
3765  bBackgroundTransparent = true;
3766  }
3767  else if(aFillAttributes && aFillAttributes->isUsed())
3768  {
3769  bBackgroundTransparent = aFillAttributes->isTransparent();
3770  }
3771  else if ( pBackgrdBrush )
3772  {
3773  if ( (pBackgrdBrush->GetColor().GetTransparency() != 0) &&
3774  (pBackgrdBrush->GetColor() != COL_TRANSPARENT) )
3775  {
3776  bBackgroundTransparent = true;
3777  }
3778  else
3779  {
3780  const GraphicObject *pTmpGrf =
3781  pBackgrdBrush->GetGraphicObject();
3782  if ( pTmpGrf &&
3783  (pTmpGrf->GetAttr().GetTransparency() != 0)
3784  )
3785  {
3786  bBackgroundTransparent = true;
3787  }
3788  }
3789  }
3790  }
3791  }
3792 
3793  return bBackgroundTransparent;
3794 };
3795 
3796 bool SwFlyFrame::IsPaint( SdrObject *pObj, const SwViewShell *pSh )
3797 {
3798  SdrObjUserCall *pUserCall = GetUserCall(pObj);
3799 
3800  if ( nullptr == pUserCall )
3801  return true;
3802 
3803  //Attribute dependent, don't paint for printer or Preview
3804  bool bPaint = gProp.pSFlyOnlyDraw ||
3805  static_cast<SwContact*>(pUserCall)->GetFormat()->GetPrint().GetValue();
3806  if ( !bPaint )
3807  bPaint = pSh->GetWin() && !pSh->IsPreview();
3808 
3809  if ( bPaint )
3810  {
3811  //The paint may be prevented by the superior Flys.
3812  SwFrame *pAnch = nullptr;
3813  if ( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr ) // i#117962#
3814  {
3815  bPaint = false;
3816  }
3817  if ( auto pFlyDraw = dynamic_cast<SwVirtFlyDrawObj *>( pObj ) )
3818  {
3819  SwFlyFrame *pFly = pFlyDraw->GetFlyFrame();
3820  if ( gProp.pSFlyOnlyDraw && gProp.pSFlyOnlyDraw == pFly )
3821  return true;
3822 
3823  //Try to avoid displaying the intermediate stage, Flys which don't
3824  //overlap with the page on which they are anchored won't be
3825  //painted.
3826  //HACK: exception: printing of frames in tables, those can overlap
3827  //a page once in a while when dealing with oversized tables (HTML).
3828  SwPageFrame *pPage = pFly->FindPageFrame();
3829  if ( pPage && pPage->getFrameArea().IsOver( pFly->getFrameArea() ) )
3830  {
3831  pAnch = pFly->AnchorFrame();
3832  }
3833 
3834  }
3835  else
3836  {
3837  // Consider 'virtual' drawing objects
3838  SwDrawContact* pDrawContact = dynamic_cast<SwDrawContact*>(pUserCall);
3839  pAnch = pDrawContact ? pDrawContact->GetAnchorFrame(pObj) : nullptr;
3840  if ( pAnch )
3841  {
3842  if ( !pAnch->isFrameAreaPositionValid() )
3843  pAnch = nullptr;
3844  else if ( pSh->GetOut() == pSh->getIDocumentDeviceAccess().getPrinter( false ))
3845  {
3846  //HACK: we have to omit some of the objects for printing,
3847  //otherwise they would be printed twice.
3848  //The objects should get printed if the TableHack is active
3849  //right now. Afterwards they must not be printed if the
3850  //page over which they float position wise gets printed.
3851  const SwPageFrame *pPage = pAnch->FindPageFrame();
3852  if ( !pPage->getFrameArea().IsOver( pObj->GetCurrentBoundRect() ) )
3853  pAnch = nullptr;
3854  }
3855  }
3856  else
3857  {
3858  if ( dynamic_cast< const SdrObjGroup *>( pObj ) == nullptr )
3859  {
3860  OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" );
3861  }
3862  }
3863  }
3864  if ( pAnch )
3865  {
3866  if ( pAnch->IsInFly() )
3867  bPaint = SwFlyFrame::IsPaint( pAnch->FindFlyFrame()->GetVirtDrawObj(),
3868  pSh );
3869  else if ( gProp.pSFlyOnlyDraw )
3870  bPaint = false;
3871  }
3872  else
3873  bPaint = false;
3874  }
3875  return bPaint;
3876 }
3877 
3878 void SwCellFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3879 {
3880  if ( GetLayoutRowSpan() >= 1 )
3881  SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
3882 }
3883 
3884 namespace {
3885 
3886 struct BorderLinesGuard
3887 {
3888  explicit BorderLinesGuard() : m_pBorderLines(std::move(gProp.pBLines))
3889  {
3890  gProp.pBLines.reset(new BorderLines);
3891  }
3892  ~BorderLinesGuard()
3893  {
3894  gProp.pBLines = std::move(m_pBorderLines);
3895  }
3896 private:
3897  std::unique_ptr<BorderLines> m_pBorderLines;
3898 };
3899 
3900 }
3901 
3902 void SwFlyFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3903 {
3904  //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
3905  SwViewShell *pShell = getRootFrame()->GetCurrShell();
3906  if (pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocShell())
3907  {
3908  bool bInGenerateThumbnail = pShell->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail();
3909  if (bInGenerateThumbnail)
3910  {
3911  const SwRect& aVisRect = pShell->VisArea();
3912  if (!aVisRect.IsOver(getFrameArea()))
3913  return;
3914  }
3915  }
3916 
3917  //because of the overlapping of frames and drawing objects the flys have to
3918  //paint their borders (and those of the internal ones) directly.
3919  //e.g. #33066#
3920  gProp.pSLines->LockLines(true);
3921  BorderLinesGuard blg; // this should not paint borders added from PaintBaBo
3922 
3923  SwRect aRect( rRect );
3924  aRect.Intersection_( getFrameArea() );
3925 
3926  rRenderContext.Push( PushFlags::CLIPREGION );
3927  rRenderContext.SetClipRegion();
3928  const SwPageFrame* pPage = FindPageFrame();
3929 
3930  const SwNoTextFrame *pNoText = Lower() && Lower()->IsNoTextFrame()
3931  ? static_cast<const SwNoTextFrame*>(Lower()) : nullptr;
3932 
3933  bool bIsChart = false; //#i102950# don't paint additional borders for charts
3934  //check whether we have a chart
3935  if(pNoText)
3936  {
3937  const SwNoTextNode* pNoTNd = dynamic_cast<const SwNoTextNode*>(pNoText->GetNode());
3938  if( pNoTNd )
3939  {
3940  SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTNd->GetOLENode());
3941  if( pOLENd && pOLENd->GetOLEObj().GetObject().IsChart() )
3942  bIsChart = true;
3943  }
3944  }
3945 
3946  {
3947  bool bContour = GetFormat()->GetSurround().IsContour();
3948  tools::PolyPolygon aPoly;
3949  if ( bContour )
3950  {
3951  // add 2nd parameter with value <true>
3952  // to indicate that method is called for paint in order to avoid
3953  // load of the intrinsic graphic.
3954  bContour = GetContour( aPoly, true );
3955  }
3956 
3957  // #i47804# - distinguish complete background paint
3958  // and margin paint.
3959  // paint complete background for Writer text fly frames
3960  bool bPaintCompleteBack( !pNoText );
3961  // paint complete background for transparent graphic and contour,
3962  // if own background color exists.
3963  const bool bIsGraphicTransparent = pNoText && pNoText->IsTransparent();
3964  if ( !bPaintCompleteBack &&
3965  ( bIsGraphicTransparent|| bContour ) )
3966  {
3967  const SwFrameFormat* pSwFrameFormat = dynamic_cast< const SwFrameFormat* >(GetFormat());
3968 
3969  if (pSwFrameFormat && pSwFrameFormat->supportsFullDrawingLayerFillAttributeSet())
3970  {
3971  // check for transparency
3973 
3974  // check if the new fill attributes are used
3975  if(aFillAttributes && aFillAttributes->isUsed())
3976  {
3977  bPaintCompleteBack = true;
3978  }
3979  }
3980  else
3981  {
3982  std::unique_ptr<SvxBrushItem> aBack = GetFormat()->makeBackgroundBrushItem();
3983  // to determine, if background has to be painted, by checking, if
3984  // background color is not COL_TRANSPARENT ("no fill"/"auto fill")
3985  // or a background graphic exists.
3986  bPaintCompleteBack = aBack &&
3987  ((aBack->GetColor() != COL_TRANSPARENT) ||
3988  aBack->GetGraphicPos() != GPOS_NONE);
3989  }
3990  }
3991  // paint of margin needed.
3992  const bool bPaintMarginOnly( !bPaintCompleteBack &&
3994 
3995  // #i47804# - paint background of parent fly frame
3996  // for transparent graphics in layer Hell, if parent fly frame isn't
3997  // in layer Hell. It's only painted the intersection between the
3998  // parent fly frame area and the paint area <aRect>
4000 
4001  if (bIsGraphicTransparent &&
4002  GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS) &&
4003  GetVirtDrawObj()->GetLayer() == rIDDMA.GetHellId() &&
4005  {
4006  const SwFlyFrame* pParentFlyFrame = GetAnchorFrame()->FindFlyFrame();
4007  if ( pParentFlyFrame->GetDrawObj()->GetLayer() !=
4008  rIDDMA.GetHellId() )
4009  {
4010  SwFlyFrame* pOldRet = gProp.pSRetoucheFly2;
4011  gProp.pSRetoucheFly2 = const_cast<SwFlyFrame*>(this);
4012 
4013  SwBorderAttrAccess aAccess( SwFrame::GetCache(), pParentFlyFrame );
4014  const SwBorderAttrs &rAttrs = *aAccess.Get();
4015  SwRect aPaintRect( aRect );
4016  aPaintRect.Intersection_( pParentFlyFrame->getFrameArea() );
4017  pParentFlyFrame->PaintSwFrameBackground( aPaintRect, pPage, rAttrs );
4018 
4019  gProp.pSRetoucheFly2 = pOldRet;
4020  }
4021  }
4022 
4023  if ( bPaintCompleteBack || bPaintMarginOnly )
4024  {
4025  //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder
4026  //receives the original Rect but PaintSwFrameBackground only the limited
4027  //one.
4028 
4029  rRenderContext.Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
4030  rRenderContext.SetLineColor();
4031 
4032  pPage = FindPageFrame();
4033 
4034  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4035  const SwBorderAttrs &rAttrs = *aAccess.Get();
4036 
4037  // paint background
4038  {
4039  SwRegionRects aRegion( aRect );
4040  // #i80822#
4041  // suppress painting of background in printing area for
4042  // non-transparent graphics.
4043  if ( bPaintMarginOnly ||
4044  ( pNoText && !bIsGraphicTransparent ) )
4045  {
4046  //What we actually want to paint is the small stripe between
4047  //PrtArea and outer border.
4048  SwRect aTmp( getFramePrintArea() ); aTmp += getFrameArea().Pos();
4049  aRegion -= aTmp;
4050  }
4051  if ( bContour )
4052  {
4053  rRenderContext.Push();
4054  // #i80822#
4055  // apply clip region under the same conditions, which are
4056  // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region
4057  // for painting the graphic/OLE. Thus, the clip region is
4058  // also applied for the PDF export.
4060 
4061  if ( !rRenderContext.GetConnectMetaFile() || !pSh || !pSh->GetWin() )
4062  {
4063  rRenderContext.SetClipRegion(vcl::Region(aPoly));
4064  }
4065 
4066  for ( size_t i = 0; i < aRegion.size(); ++i )
4067  {
4068  PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4069  }
4070 
4071  rRenderContext.Pop();
4072  }
4073  else
4074  {
4075  for ( size_t i = 0; i < aRegion.size(); ++i )
4076  {
4077  PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4078  }
4079  }
4080  }
4081 
4082  // paint border before painting background
4083  PaintSwFrameShadowAndBorder(rRect, pPage, rAttrs);
4084 
4085  rRenderContext.Pop();
4086  }
4087  }
4088 
4089  // fly frame will paint it's subsidiary lines and
4090  // the subsidiary lines of its lowers on its own, due to overlapping with
4091  // other fly frames or other objects.
4092  if( gProp.pSGlobalShell->GetWin()
4093  && !bIsChart ) //#i102950# don't paint additional borders for charts
4094  {
4095  bool bSubsLineRectsCreated;
4096  if ( gProp.pSSubsLines )
4097  {
4098  // Lock already existing subsidiary lines
4099  gProp.pSSubsLines->LockLines( true );
4100  bSubsLineRectsCreated = false;
4101  }
4102  else
4103  {
4104  // create new subsidiary lines
4105  gProp.pSSubsLines.reset(new SwSubsRects);
4106  bSubsLineRectsCreated = true;
4107  }
4108 
4109  bool bSpecSubsLineRectsCreated;
4110  if ( gProp.pSSpecSubsLines )
4111  {
4112  // Lock already existing special subsidiary lines
4113  gProp.pSSpecSubsLines->LockLines( true );
4114  bSpecSubsLineRectsCreated = false;
4115  }
4116  else
4117  {
4118  // create new special subsidiary lines
4119  gProp.pSSpecSubsLines.reset(new SwSubsRects);
4120  bSpecSubsLineRectsCreated = true;
4121  }
4122  // Add subsidiary lines of fly frame and its lowers
4123  RefreshLaySubsidiary( pPage, aRect );
4124  // paint subsidiary lines of fly frame and its lowers
4125  gProp.pSSpecSubsLines->PaintSubsidiary( &rRenderContext, nullptr, gProp );
4126  gProp.pSSubsLines->PaintSubsidiary(&rRenderContext, gProp.pSLines.get(), gProp);
4127  if ( !bSubsLineRectsCreated )
4128  // unlock subsidiary lines
4129  gProp.pSSubsLines->LockLines( false );
4130  else
4131  {
4132  // delete created subsidiary lines container
4133  gProp.pSSubsLines.reset();
4134  }
4135 
4136  if ( !bSpecSubsLineRectsCreated )
4137  // unlock special subsidiary lines
4138  gProp.pSSpecSubsLines->LockLines( false );
4139  else
4140  {
4141  // delete created special subsidiary lines container
4142  gProp.pSSpecSubsLines.reset();
4143  }
4144  }
4145 
4146  SwLayoutFrame::PaintSwFrame( rRenderContext, aRect );
4147 
4148  Validate();
4149 
4150  // first paint lines added by fly frame paint
4151  // and then unlock other lines.
4152  gProp.pSLines->PaintLines( &rRenderContext, gProp );
4153  gProp.pSLines->LockLines( false );
4154  // have to paint frame borders added in heaven layer here...
4155  ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
4156 
4157  PaintDecorators();
4158 
4159  rRenderContext.Pop();
4160 
4161  if ( gProp.pSProgress && pNoText )
4163 }
4164 
4166 {
4167  // Show the un-float button
4168  SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
4169  if ( pWrtSh )
4170  {
4171  UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
4172  }
4173 }
4174 
4175 void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
4176 {
4177  const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions();
4178  if (pViewOption->IsTable())
4179  {
4180  // #i29550#
4181  if ( IsCollapsingBorders() )
4182  {
4183  SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4184  const SwBorderAttrs &rAttrs = *aAccess.Get();
4185 
4186  // paint shadow
4187  if ( rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
4188  {
4189  SwRect aRect;
4190  ::lcl_CalcBorderRect( aRect, this, rAttrs, true, gProp );
4191  PaintShadow( rRect, aRect, rAttrs );
4192  }
4193 
4194  SwTabFramePainter aHelper(*this);
4195  aHelper.PaintLines(rRenderContext, rRect);
4196  }
4197 
4198  SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
4199  }
4200  // #i6467# - no light grey rectangle for page preview
4201  else if ( gProp.pSGlobalShell->GetWin() && !gProp.pSGlobalShell->IsPreview() )
4202  {
4203  // #i6467# - intersect output rectangle with table frame
4204  SwRect aTabRect( getFramePrintArea() );
4205  aTabRect.Pos() += getFrameArea().Pos();
4206  SwRect aTabOutRect( rRect );
4207  aTabOutRect.Intersection( aTabRect );
4208  SwViewOption::DrawRect( &rRenderContext, aTabOutRect, COL_LIGHTGRAY );
4209  }
4210  const_cast<SwTabFrame*>(this)->ResetComplete();
4211 }
4212 
4226 static void lcl_PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4227  const SvxShadowItem& rShadow, const bool bDrawFullShadowRectangle,
4228  const bool bTop, const bool bBottom,
4229  const bool bLeft, const bool bRight,
4230  SwPaintProperties const & properties)
4231 {
4232  const tools::Long nWidth = ::lcl_AlignWidth ( rShadow.GetWidth(), properties );
4233  const tools::Long nHeight = ::lcl_AlignHeight( rShadow.GetWidth(), properties );
4234 
4235  SwRects aRegion;
4236  SwRect aOut( rOutRect );
4237 
4238  switch ( rShadow.GetLocation() )
4239  {
4240  case SvxShadowLocation::BottomRight:
4241  {
4242  if ( bDrawFullShadowRectangle )
4243  {
4244  // draw full shadow rectangle
4245  aOut.Top( rOutRect.Top() + nHeight );
4246  aOut.Left( rOutRect.Left() + nWidth );
4247  aRegion.push_back( aOut );
4248  }
4249  else
4250  {
4251  if( bBottom )
4252  {
4253  aOut.Top( rOutRect.Bottom() - nHeight );
4254  if( bLeft )
4255  aOut.Left( rOutRect.Left() + nWidth );
4256  aRegion.push_back( aOut );
4257  }
4258  if( bRight )
4259  {
4260  aOut.Left( rOutRect.Right() - nWidth );
4261  if( bTop )
4262  aOut.Top( rOutRect.Top() + nHeight );
4263  else
4264  aOut.Top( rOutRect.Top() );
4265  if( bBottom )
4266  aOut.Bottom( rOutRect.Bottom() - nHeight );
4267  aRegion.push_back( aOut );
4268  }
4269  }
4270 
4271  if( bRight )
4272  rOutRect.AddRight(- nWidth );
4273  if( bBottom )
4274  rOutRect.AddBottom(- nHeight );
4275  }
4276  break;
4277  case SvxShadowLocation::TopLeft:
4278  {
4279  if ( bDrawFullShadowRectangle )
4280  {
4281  // draw full shadow rectangle
4282  aOut.Bottom( rOutRect.Bottom() - nHeight );
4283  aOut.Right( rOutRect.Right() - nWidth );
4284  aRegion.push_back( aOut );
4285  }
4286  else
4287  {
4288  if( bTop )
4289  {
4290  aOut.Bottom( rOutRect.Top() + nHeight );
4291  if( bRight )
4292  aOut.Right( rOutRect.Right() - nWidth );
4293  aRegion.push_back( aOut );
4294  }
4295  if( bLeft )
4296  {
4297  aOut.Right( rOutRect.Left() + nWidth );
4298  if( bBottom )
4299  aOut.Bottom( rOutRect.Bottom() - nHeight );
4300  else
4301  aOut.Bottom( rOutRect.Bottom() );
4302  if( bTop )
4303  aOut.Top( rOutRect.Top() + nHeight );
4304  aRegion.push_back( aOut );
4305  }
4306  }
4307 
4308  if( bLeft )
4309  rOutRect.AddLeft( nWidth );
4310  if( bTop )
4311  rOutRect.AddTop( nHeight );
4312  }
4313  break;
4314  case SvxShadowLocation::TopRight:
4315  {
4316  if ( bDrawFullShadowRectangle )
4317  {
4318  // draw full shadow rectangle
4319  aOut.Bottom( rOutRect.Bottom() - nHeight);
4320  aOut.Left( rOutRect.Left() + nWidth );
4321  aRegion.push_back( aOut );
4322  }
4323  else
4324  {
4325  if( bTop )
4326  {
4327  aOut.Bottom( rOutRect.Top() + nHeight );
4328  if( bLeft )
4329  aOut.Left( rOutRect.Left() + nWidth );
4330  aRegion.push_back( aOut );
4331  }
4332  if( bRight )
4333  {
4334  aOut.Left( rOutRect.Right() - nWidth );
4335  if( bBottom )
4336  aOut.Bottom( rOutRect.Bottom() - nHeight );
4337  else
4338  aOut.Bottom( rOutRect.Bottom() );
4339  if( bTop )
4340  aOut.Top( rOutRect.Top() + nHeight );
4341  aRegion.push_back( aOut );
4342  }
4343  }
4344 
4345  if( bRight )
4346  rOutRect.AddRight( - nWidth );
4347  if( bTop )
4348  rOutRect.AddTop( nHeight );
4349  }
4350  break;
4351  case SvxShadowLocation::BottomLeft:
4352  {
4353  if ( bDrawFullShadowRectangle )
4354  {
4355  // draw full shadow rectangle
4356  aOut.Top( rOutRect.Top() + nHeight );
4357  aOut.Right( rOutRect.Right() - nWidth );
4358  aRegion.push_back( aOut );
4359  }
4360  else
4361  {
4362  if( bBottom )
4363  {
4364  aOut.Top( rOutRect.Bottom()- nHeight );
4365  if( bRight )
4366  aOut.Right( rOutRect.Right() - nWidth );
4367  aRegion.push_back( aOut );
4368  }
4369  if( bLeft )
4370  {
4371  aOut.Right( rOutRect.Left() + nWidth );
4372  if( bTop )
4373  aOut.Top( rOutRect.Top() + nHeight );
4374  else
4375  aOut.Top( rOutRect.Top() );
4376  if( bBottom )
4377  aOut.Bottom( rOutRect.Bottom() - nHeight );
4378  aRegion.push_back( aOut );
4379  }
4380  }
4381 
4382  if( bLeft )
4383  rOutRect.AddLeft( nWidth );
4384  if( bBottom )
4385  rOutRect.AddBottom( - nHeight );
4386  }
4387  break;
4388  default:
4389  assert(false);
4390  break;
4391  }
4392 
4393  vcl::RenderContext *pOut = properties.pSGlobalShell->GetOut();
4394 
4395  DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
4396  Color aShadowColor( rShadow.GetColor().GetRGBColor() );
4397  if( !aRegion.empty() && properties.pSGlobalShell->GetWin() &&
4399  {
4400  // In high contrast mode, the output device has already set the
4401  // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function
4402  // to ignore the setting of a new color. Therefore we have to reset
4403  // the drawing mode
4404  pOut->SetDrawMode( DrawModeFlags::Default );
4405  aShadowColor = SwViewOption::GetFontColor();
4406  }
4407 
4408  if ( pOut->GetFillColor() != aShadowColor )
4409  pOut->SetFillColor( aShadowColor );
4410 
4411  pOut->SetLineColor();
4412 
4413  pOut->SetDrawMode( nOldDrawMode );
4414 
4415  for (const SwRect & rOut : aRegion)
4416  {
4417  aOut = rOut;
4418  if ( rRect.IsOver( aOut ) && aOut.Height() > 0 && aOut.Width() > 0 )
4419  {
4420  aOut.Intersection_( rRect );
4421  pOut->DrawRect( aOut.SVRect() );
4422  }
4423  }
4424 }
4425 
4435 void SwFrame::PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4436  const SwBorderAttrs &rAttrs ) const
4437 {
4438  SvxShadowItem rShadow = rAttrs.GetShadow();
4439 
4440  const bool bCnt = IsContentFrame();
4441  const bool bTop = !bCnt || rAttrs.GetTopLine ( *(this) );
4442  const bool bBottom = !bCnt || rAttrs.GetBottomLine( *(this) );
4443 
4444  if( IsVertical() )
4445  {
4446  switch( rShadow.GetLocation() )
4447  {
4448  case SvxShadowLocation::BottomRight: rShadow.SetLocation(SvxShadowLocation::BottomLeft); break;
4449  case SvxShadowLocation::TopLeft: rShadow.SetLocation(SvxShadowLocation::TopRight); break;
4450  case SvxShadowLocation::TopRight: rShadow.SetLocation(SvxShadowLocation::BottomRight); break;
4451  case SvxShadowLocation::BottomLeft: rShadow.SetLocation(SvxShadowLocation::TopLeft); break;
4452  default: break;
4453  }
4454  }
4455 
4456  // determine, if full shadow rectangle have to be drawn or only two shadow rectangles beside the frame.
4457  // draw full shadow rectangle, if frame background is drawn transparent.
4458  // Status Quo:
4459  // SwLayoutFrame can have transparent drawn backgrounds. Thus,
4460  // "asked" their frame format.
4461  const bool bDrawFullShadowRectangle =
4462  ( IsLayoutFrame() &&
4463  static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent()
4464  );
4465 
4466  SwRectFnSet aRectFnSet(this);
4467  ::lcl_ExtendLeftAndRight( rOutRect, *(this), rAttrs, aRectFnSet.FnRect() );
4468 
4469  lcl_PaintShadow(rRect, rOutRect, rShadow, bDrawFullShadowRectangle, bTop, bBottom, true, true, gProp);
4470 }
4471 
4473  const SwRect& rOutRect,
4474  const SwPageFrame * pPage,
4475  const Color *pColor,
4476  const SvxBorderLineStyle nStyle ) const
4477 {
4478  if ( !rOutRect.IsOver( rRect ) )
4479  return;
4480 
4481  SwRect aOut( rOutRect );
4482  aOut.Intersection_( rRect );
4483 
4484  const SwTabFrame *pTab = IsCellFrame() ? FindTabFrame() : nullptr;
4485  SubColFlags nSubCol = ( IsCellFrame() || IsRowFrame() )
4486  ? SubColFlags::Tab
4487  : ( IsInSct()
4488  ? SubColFlags::Sect
4489  : ( IsInFly() ? SubColFlags::Fly : SubColFlags::Page ) );
4490  if( pColor && gProp.pSGlobalShell->GetWin() &&
4492  {
4493  pColor = &SwViewOption::GetFontColor();
4494  }
4495 
4496  if (pPage->GetSortedObjs() &&
4498  {
4499  SwRegionRects aRegion( aOut, 4 );
4500  basegfx::utils::B2DClipState aClipState;
4501  ::lcl_SubtractFlys( this, pPage, aOut, aRegion, aClipState, gProp );
4502  for ( size_t i = 0; i < aRegion.size(); ++i )
4503  gProp.pSLines->AddLineRect( aRegion[i], pColor, nStyle, pTab, nSubCol, gProp );
4504  }
4505  else
4506  gProp.pSLines->AddLineRect( aOut, pColor, nStyle, pTab, nSubCol, gProp );
4507 }
4508 
4509 namespace drawinglayer::primitive2d
4510 {
4511  namespace {
4512 
4513  class SwBorderRectanglePrimitive2D : public BufferedDecompositionPrimitive2D
4514  {
4515  private:
4518 
4524 
4525  protected:
4527  virtual void create2DDecomposition(
4528  Primitive2DContainer& rContainer,
4529  const geometry::ViewInformation2D& rViewInformation) const override;
4530 
4531  public:
4533  SwBorderRectanglePrimitive2D(
4534  const basegfx::B2DHomMatrix& rB2DHomMatrix,
4535  const svx::frame::Style& rStyleTop,
4536  const svx::frame::Style& rStyleRight,
4537  const svx::frame::Style& rStyleBottom,
4538  const svx::frame::Style& rStyleLeft);
4539 
4541  const basegfx::B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; }
4542  const svx::frame::Style& getStyleTop() const { return maStyleTop; }
4543  const svx::frame::Style& getStyleRight() const { return maStyleRight; }
4544  const svx::frame::Style& getStyleBottom() const { return maStyleBottom; }
4545  const svx::frame::Style& getStyleLeft() const { return maStyleLeft; }
4546 
4548  virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
4549 
4551  virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
4552 
4554  virtual sal_uInt32 getPrimitive2DID() const override;
4555  };
4556 
4557  }
4558 
4559  void SwBorderRectanglePrimitive2D::create2DDecomposition(
4560  Primitive2DContainer& rContainer,
4561  const geometry::ViewInformation2D& /*rViewInformation*/) const
4562  {
4563  basegfx::B2DPoint aTopLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 0.0));
4564  basegfx::B2DPoint aTopRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 0.0));
4565  basegfx::B2DPoint aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0));
4566  basegfx::B2DPoint aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0));
4567 
4568  // prepare SdrFrameBorderDataVector
4569  std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
4570  std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
4571 
4572  if(getStyleTop().IsUsed())
4573  {
4574  // move top left/right inwards half border width
4575  basegfx::B2DVector aDown(getB2DHomMatrix() * basegfx::B2DVector(0.0, 1.0));
4576  aDown.setLength(getStyleTop().GetWidth() * 0.5);
4577  aTopLeft += aDown;
4578  aTopRight += aDown;
4579  }
4580 
4581  if(getStyleBottom().IsUsed())
4582  {
4583  // move bottom left/right inwards half border width
4584  basegfx::B2DVector aUp(getB2DHomMatrix() * basegfx::B2DVector(0.0, -1.0));
4585  aUp.setLength(getStyleBottom().GetWidth() * 0.5);
4586  aBottomLeft += aUp;
4587  aBottomRight += aUp;
4588  }
4589 
4590  if(getStyleLeft().IsUsed())
4591  {
4592  // move left top/bottom inwards half border width
4593  basegfx::B2DVector aRight(getB2DHomMatrix() * basegfx::B2DVector(1.0, 0.0));
4594  aRight.setLength(getStyleLeft().GetWidth() * 0.5);
4595  aTopLeft += aRight;
4596  aBottomLeft += aRight;
4597  }
4598 
4599  if(getStyleRight().IsUsed())
4600  {
4601  // move right top/bottom inwards half border width
4602  basegfx::B2DVector aLeft(getB2DHomMatrix() * basegfx::B2DVector(-1.0, 0.0));
4603  aLeft.setLength(getStyleRight().GetWidth() * 0.5);
4604  aTopRight += aLeft;
4605  aBottomRight += aLeft;
4606  }
4607 
4608  // go round-robin, from TopLeft to TopRight, down, left and back up. That
4609  // way, the borders will not need to be mirrored in any way
4610  if(getStyleTop().IsUsed())
4611  {
4612  // create BorderPrimitive(s) for top border
4613  const basegfx::B2DVector aVector(aTopRight - aTopLeft);
4614  aData->emplace_back(
4615  aTopLeft,
4616  aVector,
4617  getStyleTop(),
4618  nullptr);
4620 
4621  if(getStyleLeft().IsUsed())
4622  {
4623  rInstance.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft - aTopLeft), false);
4624  }
4625 
4626  if(getStyleRight().IsUsed())
4627  {
4628  rInstance.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight - aTopRight), false);
4629  }
4630  }
4631 
4632  if(getStyleRight().IsUsed())
4633  {
4634  // create BorderPrimitive(s) for right border
4635  const basegfx::B2DVector aVector(aBottomRight - aTopRight);
4636  aData->emplace_back(
4637  aTopRight,
4638  aVector,
4639  getStyleRight(),
4640  nullptr);
4642 
4643  if(getStyleTop().IsUsed())
4644  {
4645  rInstance.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft - aTopRight), false);
4646  }
4647 
4648  if(getStyleBottom().IsUsed())
4649  {
4650  rInstance.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft - aBottomRight), false);
4651  }
4652  }
4653 
4654  if(getStyleBottom().IsUsed())
4655  {
4656  // create BorderPrimitive(s) for bottom border
4657  const basegfx::B2DVector aVector(aBottomLeft - aBottomRight);
4658  aData->emplace_back(
4659  aBottomRight,
4660  aVector,
4661  getStyleBottom(),
4662  nullptr);
4664 
4665  if(getStyleRight().IsUsed())
4666  {
4667  rInstance.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight - aBottomRight), false);
4668  }
4669 
4670  if(getStyleLeft().IsUsed())
4671  {
4672  rInstance.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft - aBottomLeft), false);
4673  }
4674  }
4675 
4676  if(getStyleLeft().IsUsed())
4677  {
4678  // create BorderPrimitive(s) for left border
4679  const basegfx::B2DVector aVector(aTopLeft - aBottomLeft);
4680  aData->emplace_back(
4681  aBottomLeft,
4682  aVector,
4683  getStyleLeft(),
4684  nullptr);
4686 
4687  if(getStyleBottom().IsUsed())
4688  {
4689  rInstance.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight - aBottomLeft), false);
4690  }
4691 
4692  if(getStyleTop().IsUsed())
4693  {
4694  rInstance.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight - aTopLeft), false);
4695  }
4696  }
4697 
4698  // create instance of SdrFrameBorderPrimitive2D if
4699  // SdrFrameBorderDataVector is used
4700  if(!aData->empty())
4701  {
4702  rContainer.append(
4705  aData,
4706  true))); // force visualization to minimal one discrete unit (pixel)
4707  }
4708  }
4709 
4710  SwBorderRectanglePrimitive2D::SwBorderRectanglePrimitive2D(
4711  const basegfx::B2DHomMatrix& rB2DHomMatrix,
4712  const svx::frame::Style& rStyleTop,
4713  const svx::frame::Style& rStyleRight,
4714  const svx::frame::Style& rStyleBottom,
4715  const svx::frame::Style& rStyleLeft)
4716  : BufferedDecompositionPrimitive2D(),
4717  maB2DHomMatrix(rB2DHomMatrix),
4718  maStyleTop(rStyleTop),
4719  maStyleRight(rStyleRight),
4720  maStyleBottom(rStyleBottom),
4721  maStyleLeft(rStyleLeft)
4722  {
4723  }
4724 
4725  bool SwBorderRectanglePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
4726  {
4727  if(BasePrimitive2D::operator==(rPrimitive))
4728  {
4729  const SwBorderRectanglePrimitive2D& rCompare = static_cast<const SwBorderRectanglePrimitive2D&>(rPrimitive);
4730 
4731  return (getB2DHomMatrix() == rCompare.getB2DHomMatrix() &&
4732  getStyleTop() == rCompare.getStyleTop() &&
4733  getStyleRight() == rCompare.getStyleRight() &&
4734  getStyleBottom() == rCompare.getStyleBottom() &&
4735  getStyleLeft() == rCompare.getStyleLeft());
4736  }
4737 
4738  return false;
4739  }
4740 
4741  basegfx::B2DRange SwBorderRectanglePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
4742  {
4743  basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
4744 
4745  aRetval.transform(getB2DHomMatrix());
4746  return aRetval;
4747  }
4748 
4749  // provide unique ID
4751 
4752 } // end of namespace drawinglayer::primitive2d
4753 
4754 namespace {
4755 
4756 editeng::SvxBorderLine const * get_ptr(std::optional<editeng::SvxBorderLine> const & opt) {
4757  return opt ? &*opt : nullptr;
4758 }
4759 
4760 }
4761 
4763  const SwFont& rFont,
4764  const SwRect& rPaintArea,
4765  const bool bVerticalLayout,
4766  const bool bVerticalLayoutLRBT,
4767  const bool bJoinWithPrev,
4768  const bool bJoinWithNext )
4769 {
4770  SwRect aAlignedRect(rPaintArea);
4771  SwAlignRect(aAlignedRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut());
4772 
4773  bool bTop = true;
4774  bool bBottom = true;
4775  bool bLeft = true;
4776  bool bRight = true;
4777 
4778  switch (rFont.GetOrientation(bVerticalLayout, bVerticalLayoutLRBT).get())
4779  {
4780  case 0 :
4781  bLeft = !bJoinWithPrev;
4782  bRight = !bJoinWithNext;
4783  break;
4784  case 900 :
4785  bBottom = !bJoinWithPrev;
4786  bTop = !bJoinWithNext;
4787  break;
4788  case 1800 :
4789  bRight = !bJoinWithPrev;
4790  bLeft = !bJoinWithNext;
4791  break;
4792  case 2700 :
4793  bTop = !bJoinWithPrev;
4794  bBottom = !bJoinWithNext;
4795  break;
4796  }
4797 
4798  // Paint shadow (reduce painting rect)
4799  {
4800  const SvxShadowItem aShadow(
4801  0, &rFont.GetShadowColor(), rFont.GetShadowWidth(),
4802  rFont.GetAbsShadowLocation(bVerticalLayout, bVerticalLayoutLRBT));
4803 
4804  if( aShadow.GetLocation() != SvxShadowLocation::NONE )
4805  {
4806  lcl_PaintShadow( rPaintArea, aAlignedRect, aShadow,
4807  false, bTop, bBottom, bLeft, bRight, gProp);
4808  }
4809  }
4810 
4811  const basegfx::B2DHomMatrix aBorderTransform(
4813  aAlignedRect.Width(), aAlignedRect.Height(),
4814  aAlignedRect.Left(), aAlignedRect.Top()));
4815  const svx::frame::Style aStyleTop(
4816  bTop ? get_ptr(rFont.GetAbsTopBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4817  1.0);
4818  const svx::frame::Style aStyleRight(
4819  bRight ? get_ptr(rFont.GetAbsRightBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4820  1.0);
4821  const svx::frame::Style aStyleBottom(
4822  bBottom ? get_ptr(rFont.GetAbsBottomBorder(bVerticalLayout, bVerticalLayoutLRBT))
4823  : nullptr,
4824  1.0);
4825  const svx::frame::Style aStyleLeft(
4826  bLeft ? get_ptr(rFont.GetAbsLeftBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4827  1.0);
4829 
4830  aBorderLineTarget.append(
4832  new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
4833  aBorderTransform,
4834  aStyleTop,
4835  aStyleRight,
4836  aStyleBottom,
4837  aStyleLeft)));
4838  gProp.pBLines->AddBorderLines(aBorderLineTarget);
4839 }
4840 
4842 static const SwFrame* lcl_HasNextCell( const SwFrame& rFrame )
4843 {
4844  OSL_ENSURE( rFrame.IsCellFrame(),
4845  "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame" );
4846 
4847  const SwFrame* pTmpFrame = &rFrame;
4848  do
4849  {
4850  if ( pTmpFrame->GetNext() )
4851  return pTmpFrame->GetNext();
4852 
4853  pTmpFrame = pTmpFrame->GetUpper()->GetUpper();
4854  }
4855  while ( pTmpFrame->IsCellFrame() );
4856 
4857  return nullptr;
4858 }
4859 
4881 static const SwFrame* lcl_GetCellFrameForBorderAttrs( const SwFrame* _pCellFrame,
4882  const SwBorderAttrs& _rCellBorderAttrs,
4883  const bool _bTop )
4884 {
4885  OSL_ENSURE( _pCellFrame, "No cell frame available, dying soon" );
4886 
4887  // determine, if cell frame is at bottom/top border of a table frame and
4888  // the table frame has/is a follow.
4889  const SwFrame* pTmpFrame = _pCellFrame;
4890  bool bCellAtBorder = true;
4891  bool bCellAtLeftBorder = !_pCellFrame->GetPrev();
4892  bool bCellAtRightBorder = !_pCellFrame->GetNext();
4893  while( !pTmpFrame->IsRowFrame() || !pTmpFrame->GetUpper()->IsTabFrame() )
4894  {
4895  pTmpFrame = pTmpFrame->GetUpper();
4896  if ( pTmpFrame->IsRowFrame() &&
4897  (_bTop ? pTmpFrame->GetPrev() : pTmpFrame->GetNext())
4898  )
4899  {
4900  bCellAtBorder = false;
4901  }
4902  if ( pTmpFrame->IsCellFrame() )
4903  {
4904  if ( pTmpFrame->GetPrev() )
4905  {
4906  bCellAtLeftBorder = false;
4907  }
4908  if ( pTmpFrame->GetNext() )
4909  {
4910  bCellAtRightBorder = false;
4911  }
4912  }
4913  }
4914  OSL_ENSURE( pTmpFrame && pTmpFrame->IsRowFrame(), "No RowFrame available" );
4915 
4916  const SwLayoutFrame* pParentRowFrame = static_cast<const SwLayoutFrame*>(pTmpFrame);
4917  const SwTabFrame* pParentTabFrame =
4918  static_cast<const SwTabFrame*>(pParentRowFrame->GetUpper());
4919 
4920  const bool bCellNeedsAttribute = bCellAtBorder &&
4921  ( _bTop ?
4922  // bCellInFirstRowWithMaster
4923  ( !pParentRowFrame->GetPrev() &&
4924  pParentTabFrame->IsFollow() &&
4925  0 == pParentTabFrame->GetTable()->GetRowsToRepeat() ) :
4926  // bCellInLastRowWithFollow
4927  ( !pParentRowFrame->GetNext() &&
4928  pParentTabFrame->GetFollow() )
4929  );
4930 
4931  const SwFrame* pRet = _pCellFrame;
4932  if ( bCellNeedsAttribute )
4933  {
4934  // determine, if cell frame has no borders inside the table.
4935  const SwFrame* pNextCell = nullptr;
4936  bool bNoBordersInside = false;
4937 
4938  if ( bCellAtLeftBorder && ( nullptr != ( pNextCell = lcl_HasNextCell( *_pCellFrame ) ) ) )
4939  {
4940  SwBorderAttrAccess aAccess( SwFrame::GetCache(), pNextCell );
4941  const SwBorderAttrs &rBorderAttrs = *aAccess.Get();
4942  const SvxBoxItem& rBorderBox = rBorderAttrs.GetBox();
4943  bCellAtRightBorder = !lcl_HasNextCell( *pNextCell );
4944  bNoBordersInside =
4945  ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4946  !rBorderBox.GetLeft() &&
4947  ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4948  ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4949  }
4950  else
4951  {
4952  const SvxBoxItem& rBorderBox = _rCellBorderAttrs.GetBox();
4953  bNoBordersInside =
4954  ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4955  ( !rBorderBox.GetLeft() || bCellAtLeftBorder ) &&
4956  ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4957  ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4958  }
4959 
4960  if ( bNoBordersInside )
4961  {
4962  if ( _bTop && !_rCellBorderAttrs.GetBox().GetTop() )
4963  {
4964  //-hack
4965  // Cell frame has no top border and no border inside the table, but
4966  // it is at the top border of a table frame, which is a follow.
4967  // Thus, use border attributes of cell frame in first row of complete table.
4968  // First, determine first table frame of complete table.
4969  SwTabFrame* pMasterTabFrame = pParentTabFrame->FindMaster( true );
4970  // determine first row of complete table.
4971  const SwFrame* pFirstRow = pMasterTabFrame->GetLower();
4972  // return first cell in first row
4973  SwFrame* pLowerCell = const_cast<SwFrame*>(pFirstRow->GetLower());
4974  while ( !pLowerCell->IsCellFrame() ||
4975  ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
4976  )
4977  {
4978  pLowerCell = pLowerCell->GetLower();
4979  }
4980  OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
4981  pRet = pLowerCell;
4982  }
4983  else if ( !_bTop && !_rCellBorderAttrs.GetBox().GetBottom() )
4984  {
4985  //-hack
4986  // Cell frame has no bottom border and no border inside the table,
4987  // but it is at the bottom border of a table frame, which has a follow.
4988  // Thus, use border attributes of cell frame in last row of complete table.
4989  // First, determine last table frame of complete table.
4990  SwTabFrame* pLastTabFrame = const_cast<SwTabFrame*>(pParentTabFrame->GetFollow());
4991  while ( pLastTabFrame->GetFollow() )
4992  {
4993  pLastTabFrame = pLastTabFrame->GetFollow();
4994  }
4995  // determine last row of complete table.
4996  SwFrame* pLastRow = pLastTabFrame->GetLastLower();
4997  // return first bottom border cell in last row
4998  SwFrame* pLowerCell = pLastRow->GetLower();
4999  while ( !pLowerCell->IsCellFrame() ||
5000  ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
5001  )
5002  {
5003  if ( pLowerCell->IsRowFrame() )
5004  {
5005  while ( pLowerCell->GetNext() )
5006  {
5007  pLowerCell = pLowerCell->GetNext();
5008  }
5009  }
5010  pLowerCell = pLowerCell->GetLower();
5011  }
5012  OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" );
5013  pRet = pLowerCell;
5014  }
5015  }
5016  }
5017 
5018  return pRet;
5019 }
5020 
5021 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> SwFrame::CreateProcessor2D( ) const
5022 {
5023  basegfx::B2DRange aViewRange;
5024 
5025  SdrPage *pDrawPage = getRootFrame()->GetCurrShell()->Imp()->GetPageView()->GetPage();
5026  const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
5028  getRootFrame()->GetCurrShell()->GetOut()->GetViewTransformation(),
5029  aViewRange,
5030  GetXDrawPageForSdrPage( pDrawPage ),
5031  0.0,
5032  uno::Sequence< beans::PropertyValue >() );
5033 
5035  *getRootFrame()->GetCurrShell()->GetOut(),
5036  aNewViewInfos );
5037 }
5038 
5040 {
5041  std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D = CreateProcessor2D();
5042  if ( pProcessor2D )
5043  {
5044  pProcessor2D->process( rSequence );
5045  }
5046 }
5047 
5050  const SwRect& rRect,
5051  const SwPageFrame* /*pPage*/,
5052  const SwBorderAttrs& rAttrs) const
5053 {
5054  // There's nothing (Row,Body,Footnote,Root,Column,NoText) need to do here
5056  return;
5057 
5058  if (IsCellFrame() && !gProp.pSGlobalShell->GetViewOptions()->IsTable())
5059  return;
5060 
5061  // #i29550#
5062  if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
5063  {
5064  const SwTabFrame* pTabFrame = FindTabFrame();
5065  if ( pTabFrame->IsCollapsingBorders() )
5066  return;
5067 
5068  if ( pTabFrame->GetTable()->IsNewModel() && ( !IsCellFrame() || IsCoveredCell() ) )
5069  return;
5070  }
5071 
5072  const bool bLine = rAttrs.IsLine();
5073  const bool bShadow = rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE;
5074 
5075  // - flag to control,
5076  //-hack has to be used.
5077  const bool bb4779636HackActive = true;
5078 
5079  const SwFrame* pCellFrameForBottomBorderAttrs = nullptr;
5080  const SwFrame* pCellFrameForTopBorderAttrs = nullptr;
5081  bool bFoundCellForTopOrBorderAttrs = false;
5082  if ( bb4779636HackActive && IsCellFrame() )
5083  {
5084  pCellFrameForBottomBorderAttrs = lcl_GetCellFrameForBorderAttrs( this, rAttrs, false );
5085  if ( pCellFrameForBottomBorderAttrs != this )
5086  bFoundCellForTopOrBorderAttrs = true;
5087  pCellFrameForTopBorderAttrs = lcl_GetCellFrameForBorderAttrs( this, rAttrs, true );
5088  if ( pCellFrameForTopBorderAttrs != this )
5089  bFoundCellForTopOrBorderAttrs = true;
5090  }
5091 
5092  // - add condition <bFoundCellForTopOrBorderAttrs>
5093  //-hack
5094  if ( !(bLine || bShadow || bFoundCellForTopOrBorderAttrs) )
5095  return;
5096 
5097  //If the rectangle is completely inside the PrtArea, no border needs to
5098  //be painted.
5099  //For the PrtArea the aligned value needs to be used, otherwise it could
5100  //happen, that some parts won't be processed.
5101  SwRect aRect( getFramePrintArea() );
5102  aRect += getFrameArea().Pos();
5103  ::SwAlignRect( aRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
5104  // new local boolean variable in order to
5105  // suspend border paint under special cases - see below.
5106  // NOTE: This is a fix for the implementation of feature #99657#.
5107  bool bDrawOnlyShadowForTransparentFrame = false;
5108  if ( aRect.IsInside( rRect ) )
5109  {
5110  // paint shadow, if background is transparent.
5111  // Because of introduced transparent background for fly frame #99657#,
5112  // the shadow have to be drawn if the background is transparent,
5113  // in spite the fact that the paint rectangle <rRect> lies fully
5114  // in the printing area.
5115  // NOTE to chosen solution:
5116  // On transparent background, continue processing, but suspend
5117  // drawing of border by setting <bDrawOnlyShadowForTransparentFrame>
5118  // to true.
5119  if ( IsLayoutFrame() &&
5120  static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent() )
5121  {
5122  bDrawOnlyShadowForTransparentFrame = true;
5123  }
5124  else
5125  {
5126  return;
5127  }
5128  }
5129 
5130  ::lcl_CalcBorderRect( aRect, this, rAttrs, true, gProp );
5131  rAttrs.SetGetCacheLine( true );
5132 
5133  if(bShadow)
5134  {
5135  PaintShadow(rRect, aRect, rAttrs);
5136  }
5137 
5138  // suspend drawing of border
5139  // add condition < NOT bDrawOnlyShadowForTransparentFrame > - see above
5140  // - add condition <bFoundCellForTopOrBorderAttrs>
5141  //-hack.
5142  if((bLine || bFoundCellForTopOrBorderAttrs) && !bDrawOnlyShadowForTransparentFrame)
5143  {
5144  // define SvxBorderLine(s) to use
5145  const SvxBoxItem& rBox(rAttrs.GetBox());
5146  const SvxBorderLine* pLeftBorder(rBox.GetLeft());
5147  const SvxBorderLine* pRightBorder(rBox.GetRight());
5148  const SvxBorderLine* pTopBorder(rBox.GetTop());
5149  const SvxBorderLine* pBottomBorder(rBox.GetBottom());
5150 
5151  // if R2L, exchange Right/Left
5152  const bool bR2L(IsCellFrame() && IsRightToLeft());
5153 
5154  if(bR2L)
5155  {
5156  std::swap(pLeftBorder, pRightBorder);
5157  }
5158 
5159  // if ContentFrame and joined Prev/Next, reset top/bottom as needed
5160  if(IsContentFrame())
5161  {
5162  const SwFrame* pDirRefFrame(IsCellFrame() ? FindTabFrame() : this);
5163  const SwRectFnSet aRectFnSet(pDirRefFrame);
5164  const SwRectFn& _rRectFn(aRectFnSet.FnRect());
5165 
5166  if(rAttrs.JoinedWithPrev(*this))
5167  {
5168  // tdf#115296 re-add adaptation of vert distance to close the evtl.
5169  // existing gap to previous frame
5170  const SwFrame* pPrevFrame(GetPrev());
5171  (aRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
5172 
5173  // ...and disable top border paint/creation
5174  pTopBorder = nullptr;
5175  }
5176 
5177  if(rAttrs.JoinedWithNext(*this))
5178  {
5179  // tdf#115296 re-add adaptation of vert distance to close the evtl.
5180  // existing gap to next frame
5181  const SwFrame* pNextFrame(GetNext());
5182  (aRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
5183 
5184  // ...and disable bottom border paint/creation
5185  pBottomBorder = nullptr;
5186  }
5187  }
5188 
5189  // necessary to replace TopBorder?
5190  if((!IsContentFrame() || rAttrs.GetTopLine(*this)) && IsCellFrame() && pCellFrameForTopBorderAttrs != this)
5191  {
5192  SwBorderAttrAccess aAccess(SwFrame::GetCache(), pCellFrameForTopBorderAttrs);
5193  pTopBorder = aAccess.Get()->GetBox().GetTop();
5194  }
5195 
5196  // necessary to replace BottomBorder?
5197  if((!IsContentFrame() || rAttrs.GetBottomLine(*this)) && IsCellFrame() && pCellFrameForBottomBorderAttrs != this)
5198  {
5199  SwBorderAttrAccess aAccess(SwFrame::GetCache(), pCellFrameForBottomBorderAttrs);
5200  pBottomBorder = aAccess.Get()->GetBox().GetBottom();
5201  }
5202 
5203  if(nullptr != pLeftBorder || nullptr != pRightBorder || nullptr != pTopBorder || nullptr != pBottomBorder)
5204  {
5205  // now we have all SvxBorderLine(s) sorted out, create geometry
5206  const basegfx::B2DHomMatrix aBorderTransform(
5208  aRect.Width(), aRect.Height(),
5209  aRect.Left(), aRect.Top()));
5210  const svx::frame::Style aStyleTop(pTopBorder, 1.0);
5211  const svx::frame::Style aStyleRight(pRightBorder, 1.0);
5212  const svx::frame::Style aStyleBottom(pBottomBorder, 1.0);
5213  const svx::frame::Style aStyleLeft(pLeftBorder, 1.0);
5215 
5216  aBorderLineTarget.append(
5218  new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
5219  aBorderTransform,
5220  aStyleTop,
5221  aStyleRight,
5222  aStyleBottom,
5223  aStyleLeft)));
5224  gProp.pBLines->AddBorderLines(aBorderLineTarget);
5225  }
5226  }
5227 
5228  rAttrs.SetGetCacheLine( false );
5229 }
5230 
5238  const SwRect& rRect,
5239  const SwPageFrame* pPage,
5240  const SwBorderAttrs&) const
5241 {
5242  //If the rectangle is completely inside the PrtArea, no border needs to
5243  //be painted.
5244  SwRect aRect( getFramePrintArea() );
5245  aRect.Pos() += getFrameArea().Pos();
5246  if ( !aRect.IsInside( rRect ) )
5247  PaintLine( rRect, pPage );
5248 }
5249 
5252  const SwPageFrame *pPage ) const
5253 {
5254  //The length of the line is derived from the percentual indication on the
5255  //PageDesc. The position is also stated on the PageDesc.
5256  //The pen can directly be taken from the PageDesc.
5257 
5258  if ( !pPage )
5259  pPage = FindPageFrame();
5260  const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
5261 
5262  SwRectFnSet aRectFnSet(this);
5263  SwTwips nPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
5264  Fraction aFract( nPrtWidth, 1 );
5265  aFract *= rInf.GetWidth();
5266  const SwTwips nWidth = static_cast<tools::Long>(aFract);
5267 
5268  SwTwips nX = aRectFnSet.GetPrtLeft(*this);
5269  switch ( rInf.GetAdj() )
5270  {
5271  case css::text::HorizontalAdjust_CENTER:
5272  nX += nPrtWidth/2 - nWidth/2; break;
5273  case css::text::HorizontalAdjust_RIGHT:
5274  nX += nPrtWidth - nWidth; break;
5275  case css::text::HorizontalAdjust_LEFT:
5276  /* do nothing */; break;
5277  default:
5278  SAL_WARN("sw.core", "New adjustment for footnote lines?");
5279  assert(false);
5280  }
5281  SwTwips nLineWidth = rInf.GetLineWidth();
5282  const SwRect aLineRect = aRectFnSet.IsVert() ?
5283  SwRect( Point(getFrameArea().Left()+getFrameArea().Width()-rInf.GetTopDist()-nLineWidth,
5284  nX), Size( nLineWidth, nWidth ) )
5285  : SwRect( Point( nX, getFrameArea().Pos().Y() + rInf.GetTopDist() ),
5286  Size( nWidth, rInf.GetLineWidth()));
5287  if ( aLineRect.HasArea() && rInf.GetLineStyle() != SvxBorderLineStyle::NONE)
5288  PaintBorderLine( rRect, aLineRect , pPage, &rInf.GetLineColor(),
5289  rInf.GetLineStyle() );
5290 }
5291 
5293 void SwLayoutFrame::PaintColLines( const SwRect &rRect, const SwFormatCol &rFormatCol,
5294  const SwPageFrame *pPage ) const
5295 {
5296  const SwFrame *pCol = Lower();
5297  if ( !pCol || !pCol->IsColumnFrame() )
5298  return;
5299 
5300  SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? (pCol->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
5301 
5302  SwRect aLineRect = getFramePrintArea();
5303  aLineRect += getFrameArea().Pos();
5304 
5305  SwTwips nTop = ((aLineRect.*fnRect->fnGetHeight)()*rFormatCol.GetLineHeight())
5306  / 100 - (aLineRect.*fnRect->fnGetHeight)();
5307  SwTwips nBottom = 0;
5308 
5309  switch ( rFormatCol.GetLineAdj() )
5310  {
5311  case COLADJ_CENTER:
5312  nBottom = nTop / 2; nTop -= nBottom; break;
5313  case COLADJ_TOP:
5314  nBottom = nTop; nTop = 0; break;
5315  case COLADJ_BOTTOM:
5316  break;
5317  default:
5318  OSL_ENSURE( false, "New adjustment for column lines?" );
5319  }
5320 
5321  if( nTop )
5322  (aLineRect.*fnRect->fnSubTop)( nTop );
5323  if( nBottom )
5324  (aLineRect.*fnRect->fnAddBottom)( nBottom );
5325 
5326  SwTwips nPenHalf = rFormatCol.GetLineWidth();
5327  (aLineRect.*fnRect->fnSetWidth)( nPenHalf );
5328  nPenHalf /= 2;
5329 
5330  //We need to be a bit generous here, to not lose something.
5331  SwRect aRect( rRect );
5332  (aRect.*fnRect->fnSubLeft)( nPenHalf + gProp.nSPixelSzW );
5333  (aRect.*fnRect->fnAddRight)( nPenHalf + gProp.nSPixelSzW );
5334  SwRectGet fnGetX = IsRightToLeft() ? fnRect->fnGetLeft : fnRect->fnGetRight;
5335  while ( pCol->GetNext() )
5336  {
5337  (aLineRect.*fnRect->fnSetPosX)
5338  ( (pCol->getFrameArea().*fnGetX)() - nPenHalf );
5339  if ( aRect.IsOver( aLineRect ) )
5340  PaintBorderLine( aRect, aLineRect , pPage, &rFormatCol.GetLineColor(),
5341  rFormatCol.GetLineStyle() );
5342  pCol = pCol->GetNext();
5343  }
5344 }
5345 
5346 void SwPageFrame::PaintGrid( OutputDevice const * pOut, SwRect const &rRect ) const
5347 {
5348  if( !m_bHasGrid || gProp.pSRetoucheFly || gProp.pSRetoucheFly2 )
5349  return;
5350  SwTextGridItem const*const pGrid(GetGridItem(this));
5351  if( !(pGrid && ( OUTDEV_PRINTER != pOut->GetOutDevType() ?
5352  pGrid->GetDisplayGrid() : pGrid->GetPrintGrid() )) )
5353  return;
5354 
5355  const SwLayoutFrame* pBody = FindBodyCont();
5356  if( !pBody )
5357  return;
5358 
5359  SwRect aGrid( pBody->getFramePrintArea() );
5360  aGrid += pBody->getFrameArea().Pos();
5361 
5362  SwRect aInter( aGrid );
5363  aInter.Intersection( rRect );
5364  if( !aInter.HasArea() )
5365  return;
5366 
5367  bool bGrid = pGrid->GetRubyTextBelow();
5368  bool bCell = GRID_LINES_CHARS == pGrid->GetGridType();
5369  tools::Long nGrid = pGrid->GetBaseHeight();
5370  const SwDoc* pDoc = GetFormat()->GetDoc();
5371  tools::Long nGridWidth = GetGridWidth(*pGrid, *pDoc);
5372  tools::Long nRuby = pGrid->GetRubyHeight();
5373  tools::Long nSum = nGrid + nRuby;
5374  const Color *pCol = &pGrid->GetColor();
5375 
5376  SwTwips nRight = aInter.Left() + aInter.Width();
5377  SwTwips nBottom = aInter.Top() + aInter.Height();
5378  if( IsVertical() )
5379  {
5380  SwTwips nOrig = aGrid.Left() + aGrid.Width();
5381  SwTwips nY = nOrig + nSum *
5382  ( ( nOrig - aInter.Left() ) / nSum );
5383  SwRect aTmp( Point( nY, aInter.Top() ),
5384  Size( 1, aInter.Height() ) );
5385  SwTwips nX = aGrid.Top() + nGrid *
5386  ( ( aInter.Top() - aGrid.Top() )/ nGrid );
5387  if( nX < aInter.Top() )
5388  nX += nGrid;
5389  SwTwips nGridBottom = aGrid.Top() + aGrid.Height();
5390  bool bLeft = aGrid.Top() >= aInter.Top();
5391  bool bRight = nGridBottom <= nBottom;
5392  bool bBorder = bLeft || bRight;
5393  while( nY > nRight )
5394  {
5395  aTmp.Pos().setX( nY );
5396  if( bGrid )
5397  {
5398  nY -= nGrid;
5399  SwTwips nPosY = std::max( aInter.Left(), nY );
5400  SwTwips nHeight = std::min(nRight, aTmp.Pos().X())-nPosY;
5401  if( nHeight > 0 )
5402  {
5403  if( bCell )
5404  {
5405  SwRect aVert( Point( nPosY, nX ),
5406  Size( nHeight, 1 ) );
5407  while( aVert.Top() <= nBottom )
5408  {
5409  PaintBorderLine(rRect,aVert,this,pCol);
5410  aVert.Pos().AdjustY(nGrid );
5411  }
5412  }
5413  else if( bBorder )
5414  {
5415  SwRect aVert( Point( nPosY, aGrid.Top() ),
5416  Size( nHeight, 1 ) );
5417  if( bLeft )
5418  PaintBorderLine(rRect,aVert,this,pCol);
5419  if( bRight )
5420  {
5421  aVert.Pos().setY( nGridBottom );
5422  PaintBorderLine(rRect,aVert,this,pCol);
5423  }
5424  }
5425  }
5426  }
5427  else
5428  {
5429  nY -= nRuby;
5430  if( bBorder )
5431  {
5432  SwTwips nPos = std::max( aInter.Left(), nY );
5433  SwTwips nW = std::min(nRight, aTmp.Pos().X()) - nPos;
5434  SwRect aVert( Point( nPos, aGrid.Top() ),
5435  Size( nW, 1 ) );
5436  if( nW > 0 )
5437  {
5438  if( bLeft )
5439  PaintBorderLine(rRect,aVert,this,pCol);
5440  if( bRight )
5441  {
5442  aVert.Pos().setY( nGridBottom );
5443  PaintBorderLine(rRect,aVert,this,pCol);
5444  }
5445  }
5446  }
5447  }
5448  bGrid = !bGrid;
5449  }
5450  while( nY >= aInter.Left() )
5451  {
5452  aTmp.Pos().setX( nY );
5453  PaintBorderLine( rRect, aTmp, this, pCol);
5454  if( bGrid )
5455  {
5456  nY -= nGrid;
5457  SwTwips nHeight = aTmp.Pos().X()
5458  - std::max(aInter.Left(), nY );
5459  if( nHeight > 0 )
5460  {
5461  if( bCell )
5462  {
5463  SwRect aVert( Point(aTmp.Pos().X()-nHeight,
5464  nX ), Size( nHeight, 1 ) );
5465  while( aVert.Top() <= nBottom )
5466  {
5467  PaintBorderLine(rRect,aVert,this,pCol);
5468  aVert.Pos().AdjustY(nGrid );
5469  }
5470  }
5471  else if( bBorder )
5472  {
5473  SwRect aVert( Point(aTmp.Pos().X()-nHeight,
5474  aGrid.Top() ), Size( nHeight, 1 ) );
5475  if( bLeft )
5476  PaintBorderLine(rRect,aVert,this,pCol);
5477  if( bRight )
5478  {
5479  aVert.Pos().setY( nGridBottom );
5480  PaintBorderLine(rRect,aVert,this,pCol);
5481  }
5482  }
5483  }
5484  }
5485  else
5486  {
5487  nY -= nRuby;
5488  if( bBorder )
5489  {
5490  SwTwips nPos = std::max( aInter.Left(), nY );
5491  SwTwips nW = std::min(nRight, aTmp.Pos().X()) - nPos;
5492  SwRect aVert( Point( nPos, aGrid.Top() ),
5493  Size( nW, 1 ) );
5494  if( nW > 0 )
5495  {
5496  if( bLeft )
5497  PaintBorderLine(rRect,aVert,this,pCol);
5498  if( bRight )
5499  {
5500  aVert.Pos().setY( nGridBottom );
5501  PaintBorderLine(rRect,aVert,this,pCol);
5502  }
5503  }
5504  }
5505  }
5506  bGrid = !bGrid;
5507  }
5508  }
5509  else
5510  {
5511  SwTwips nOrig = aGrid.Top();
5512  SwTwips nY = nOrig + nSum *( (aInter.Top()-nOrig)/nSum );
5513