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