Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx
Warning:line 3853, column 57
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name paintfrm.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx

/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <vcl/lazydelete.hxx>
21#include <sfx2/docfile.hxx>
22#include <sfx2/printer.hxx>
23#include <sfx2/progress.hxx>
24#include <editeng/brushitem.hxx>
25#include <editeng/prntitem.hxx>
26#include <editeng/boxitem.hxx>
27#include <editeng/shaditem.hxx>
28#include <svx/framelink.hxx>
29#include <drawdoc.hxx>
30#include <tgrditem.hxx>
31#include <calbck.hxx>
32#include <fmtsrnd.hxx>
33#include <fmtclds.hxx>
34#include <strings.hrc>
35#include <swmodule.hxx>
36#include <rootfrm.hxx>
37#include <pagefrm.hxx>
38#include <section.hxx>
39#include <sectfrm.hxx>
40#include <viewimp.hxx>
41#include <dflyobj.hxx>
42#include <flyfrm.hxx>
43#include <frmatr.hxx>
44#include <frmtool.hxx>
45#include <viewopt.hxx>
46#include <dview.hxx>
47#include <dcontact.hxx>
48#include <txtfrm.hxx>
49#include <ftnfrm.hxx>
50#include <tabfrm.hxx>
51#include <rowfrm.hxx>
52#include <cellfrm.hxx>
53#include <notxtfrm.hxx>
54#include <layact.hxx>
55#include <pagedesc.hxx>
56#include <ptqueue.hxx>
57#include <noteurl.hxx>
58#include "virtoutp.hxx"
59#include <lineinfo.hxx>
60#include <dbg_lay.hxx>
61#include <docsh.hxx>
62#include <svx/svdogrp.hxx>
63#include <sortedobjs.hxx>
64#include <EnhancedPDFExportHelper.hxx>
65#include <bodyfrm.hxx>
66#include <hffrm.hxx>
67#include <colfrm.hxx>
68#include <sw_primitivetypes2d.hxx>
69#include <swfont.hxx>
70
71#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
72#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
73#include <svx/sdr/contact/viewobjectcontact.hxx>
74#include <svx/sdr/contact/viewcontact.hxx>
75#include <DocumentSettingManager.hxx>
76#include <IDocumentDeviceAccess.hxx>
77#include <IDocumentDrawModelAccess.hxx>
78
79#include <ndole.hxx>
80#include <PostItMgr.hxx>
81#include <FrameControlsManager.hxx>
82#include <vcl/settings.hxx>
83
84#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
85#include <drawinglayer/processor2d/processor2dtools.hxx>
86
87#include <svtools/borderhelper.hxx>
88
89#include <bitmaps.hlst>
90#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
91#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
92#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
93#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
94#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
95#include <drawinglayer/primitive2d/textprimitive2d.hxx>
96#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
97#include <drawinglayer/processor2d/baseprocessor2d.hxx>
98#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
99#include <svx/unoapi.hxx>
100#include <svx/svdpagv.hxx>
101#include <svx/xfillit0.hxx>
102#include <basegfx/matrix/b2dhommatrixtools.hxx>
103#include <basegfx/color/bcolortools.hxx>
104#include <basegfx/utils/b2dclipstate.hxx>
105#include <sal/log.hxx>
106
107#include <memory>
108#include <vector>
109#include <algorithm>
110#include <wrtsh.hxx>
111#include <edtwin.hxx>
112#include <view.hxx>
113#include <paintfrm.hxx>
114#include <textboxhelper.hxx>
115#include <o3tl/typed_flags_set.hxx>
116
117#include <vcl/BitmapTools.hxx>
118#include <comphelper/lok.hxx>
119
120#define COL_NOTES_SIDEPANEColor(230,230,230) Color(230,230,230)
121#define COL_NOTES_SIDEPANE_BORDERColor(200,200,200) Color(200,200,200)
122#define COL_NOTES_SIDEPANE_SCROLLAREAColor(230,230,220) Color(230,230,220)
123
124using namespace ::editeng;
125using namespace ::com::sun::star;
126
127namespace {
128
129struct SwPaintProperties;
130
131//Class declaration; here because they are only used in this file
132enum class SubColFlags {
133 Page = 0x01, //Helplines of the page
134 Tab = 0x08, //Helplines inside tables
135 Fly = 0x10, //Helplines inside fly frames
136 Sect = 0x20, //Helplines inside sections
137};
138
139}
140
141namespace o3tl {
142 template<> struct typed_flags<SubColFlags> : is_typed_flags<SubColFlags, 0x39> {};
143}
144
145namespace {
146
147// Classes collecting the border lines and help lines
148class SwLineRect : public SwRect
149{
150 Color aColor;
151 SvxBorderLineStyle nStyle;
152 const SwTabFrame *pTab;
153 SubColFlags nSubColor; //colorize subsidiary lines
154 bool bPainted; //already painted?
155 sal_uInt8 nLock; //To distinguish the line and the hell layer.
156public:
157 SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
158 const SwTabFrame *pT , const SubColFlags nSCol );
159
160 const Color& GetColor() const { return aColor;}
161 SvxBorderLineStyle GetStyle() const { return nStyle; }
162 const SwTabFrame *GetTab() const { return pTab; }
163 void SetPainted() { bPainted = true; }
164 void Lock( bool bLock ) { if ( bLock )
165 ++nLock;
166 else if ( nLock )
167 --nLock;
168 }
169 bool IsPainted() const { return bPainted; }
170 bool IsLocked() const { return nLock != 0; }
171 SubColFlags GetSubColor() const { return nSubColor;}
172
173 bool MakeUnion( const SwRect &rRect, SwPaintProperties const &properties );
174};
175
176}
177
178#ifdef IOS
179static void dummy_function()
180{
181 pid_t pid = getpid();
182 (void) pid;
183}
184#endif
185
186namespace {
187
188class SwLineRects
189{
190public:
191 std::vector< SwLineRect > aLineRects;
192 typedef std::vector< SwLineRect >::const_iterator const_iterator;
193 typedef std::vector< SwLineRect >::iterator iterator;
194 typedef std::vector< SwLineRect >::reverse_iterator reverse_iterator;
195 typedef std::vector< SwLineRect >::size_type size_type;
196 size_t nLastCount; //avoid unnecessary cycles in PaintLines
197 SwLineRects() : nLastCount( 0 )
198 {
199#ifdef IOS
200 // Work around what is either a compiler bug in Xcode 5.1.1,
201 // or some unknown problem in this file. If I ifdef out this
202 // call, I get a crash in SwSubsRects::PaintSubsidiary: the
203 // address of the rLi reference variable is claimed to be
204 // 0x4000000!
205 dummy_function();
206#endif
207 }
208 void AddLineRect( const SwRect& rRect, const Color *pColor, const SvxBorderLineStyle nStyle,
209 const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const &properties );
210 void ConnectEdges( OutputDevice const *pOut, SwPaintProperties const &properties );
211 void PaintLines ( OutputDevice *pOut, SwPaintProperties const &properties );
212 void LockLines( bool bLock );
213
214 //Limit lines to 100
215 bool isFull() const { return aLineRects.size()>100; }
216};
217
218class SwSubsRects : public SwLineRects
219{
220 void RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const &properties );
221public:
222 void PaintSubsidiary( OutputDevice *pOut, const SwLineRects *pRects, SwPaintProperties const &properties );
223};
224
225class BorderLines
226{
227 drawinglayer::primitive2d::Primitive2DContainer m_Lines;
228public:
229 void AddBorderLines(const drawinglayer::primitive2d::Primitive2DContainer& rContainer);
230 drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
231 {
232 drawinglayer::primitive2d::Primitive2DContainer lines;
233 lines.swap(m_Lines);
234 return lines;
235 }
236};
237
238}
239
240// Default zoom factor
241const double aEdgeScale = 0.5;
242
243//To optimize the expensive RetouchColor determination
244Color aGlobalRetoucheColor;
245
246namespace sw
247{
248Color* GetActiveRetoucheColor()
249{
250 return &aGlobalRetoucheColor;
251}
252}
253
254namespace {
255
256/**
257 * Container for static properties
258 */
259struct SwPaintProperties {
260 // Only repaint the Fly content as well as the background of the Fly content if
261 // a metafile is taken of the Fly.
262 bool bSFlyMetafile;
263 VclPtr<OutputDevice> pSFlyMetafileOut;
264 SwViewShell *pSGlobalShell;
265
266 // Retouch for transparent Flys is done by the background of the Flys.
267 // The Fly itself should certainly not be spared out. See PaintSwFrameBackground and
268 // lcl_SubtractFlys()
269 SwFlyFrame *pSRetoucheFly;
270 SwFlyFrame *pSRetoucheFly2;
271 SwFlyFrame *pSFlyOnlyDraw;
272
273 // The borders will be collected in pSLines during the Paint and later
274 // possibly merge them.
275 // The help lines will be collected and merged in gProp.pSSubsLines. These will
276 // be compared with pSLines before the work in order to avoid help lines
277 // to hide borders.
278 std::unique_ptr<BorderLines> pBLines;
279 std::unique_ptr<SwLineRects> pSLines;
280 std::unique_ptr<SwSubsRects> pSSubsLines;
281
282 // global variable for sub-lines of body, header, footer, section and footnote frames.
283 std::unique_ptr<SwSubsRects> pSSpecSubsLines;
284 SfxProgress *pSProgress;
285
286 // Sizes of a pixel and the corresponding halves. Will be reset when
287 // entering SwRootFrame::PaintSwFrame
288 long nSPixelSzW;
289 long nSPixelSzH;
290 long nSHalfPixelSzW;
291 long nSHalfPixelSzH;
292 long nSMinDistPixelW;
293 long nSMinDistPixelH;
294
295 Color aSGlobalRetoucheColor;
296
297 // Current zoom factor
298 double aSScaleX;
299 double aSScaleY;
300
301 SwPaintProperties()
302 : bSFlyMetafile(false)
303 , pSFlyMetafileOut(nullptr)
304 , pSGlobalShell(nullptr)
305 , pSRetoucheFly(nullptr)
306 , pSRetoucheFly2(nullptr)
307 , pSFlyOnlyDraw(nullptr)
308 , pSProgress(nullptr)
309 , nSPixelSzW(0)
310 , nSPixelSzH(0)
311 , nSHalfPixelSzW(0)
312 , nSHalfPixelSzH(0)
313 , nSMinDistPixelW(0)
314 , nSMinDistPixelH(0)
315 , aSScaleX(1)
316 , aSScaleY(1)
317 {
318 }
319
320};
321
322}
323
324static SwPaintProperties gProp;
325
326static bool isSubsidiaryLinesFlysEnabled()
327{
328 return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
329 !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
330 !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
331 SwViewOption::IsObjectBoundaries();
332}
333//other subsidiary lines enabled?
334static bool isSubsidiaryLinesEnabled()
335{
336 return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
337 !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
338 !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
339 !gProp.pSGlobalShell->GetViewOptions()->IsWhitespaceHidden() &&
340 SwViewOption::IsDocBoundaries();
341}
342//subsidiary lines for sections
343static bool isSubsidiaryLinesForSectionsEnabled()
344{
345 return !gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() &&
346 !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
347 !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&
348 SwViewOption::IsSectionBoundaries();
349}
350
351
352namespace {
353
354bool isTableBoundariesEnabled()
355{
356 if (!gProp.pSGlobalShell->GetViewOptions()->IsTable())
357 return false;
358
359 if (gProp.pSGlobalShell->GetViewOptions()->IsPagePreview())
360 return false;
361
362 if (gProp.pSGlobalShell->GetViewOptions()->IsReadonly())
363 return false;
364
365 if (gProp.pSGlobalShell->GetViewOptions()->IsFormView())
366 return false;
367
368 return SwViewOption::IsTableBoundaries();
369}
370
371}
372
373/**
374 * Set borders alignment statics
375 * Adjustment for 'small' twip-to-pixel relations:
376 * For 'small' twip-to-pixel relations (less than 2:1)
377 * values of <gProp.nSHalfPixelSzW> and <gProp.nSHalfPixelSzH> are set to ZERO
378 */
379void SwCalcPixStatics( vcl::RenderContext const *pOut )
380{
381 // determine 'small' twip-to-pixel relation
382 bool bSmallTwipToPxRelW = false;
383 bool bSmallTwipToPxRelH = false;
384 {
385 Size aCheckTwipToPxRelSz( pOut->PixelToLogic( Size( 100, 100 )) );
386 if ( (aCheckTwipToPxRelSz.Width()/100.0) < 2.0 )
387 {
388 bSmallTwipToPxRelW = true;
389 }
390 if ( (aCheckTwipToPxRelSz.Height()/100.0) < 2.0 )
391 {
392 bSmallTwipToPxRelH = true;
393 }
394 }
395
396 Size aSz( pOut->PixelToLogic( Size( 1,1 )) );
397
398 gProp.nSPixelSzW = aSz.Width();
399 if( !gProp.nSPixelSzW )
400 gProp.nSPixelSzW = 1;
401 gProp.nSPixelSzH = aSz.Height();
402 if( !gProp.nSPixelSzH )
403 gProp.nSPixelSzH = 1;
404
405 // consider 'small' twip-to-pixel relations
406 if ( !bSmallTwipToPxRelW )
407 {
408 gProp.nSHalfPixelSzW = gProp.nSPixelSzW / 2 + 1;
409 }
410 else
411 {
412 gProp.nSHalfPixelSzW = 0;
413 }
414 // consider 'small' twip-to-pixel relations
415 if ( !bSmallTwipToPxRelH )
416 {
417 gProp.nSHalfPixelSzH = gProp.nSPixelSzH / 2 + 1;
418 }
419 else
420 {
421 gProp.nSHalfPixelSzH = 0;
422 }
423
424 gProp.nSMinDistPixelW = gProp.nSPixelSzW * 2 + 1;
425 gProp.nSMinDistPixelH = gProp.nSPixelSzH * 2 + 1;
426
427 const MapMode &rMap = pOut->GetMapMode();
428 gProp.aSScaleX = double(rMap.GetScaleX());
429 gProp.aSScaleY = double(rMap.GetScaleY());
430}
431
432namespace {
433
434/**
435 * To be able to save the statics so the paint is more or less reentrant
436 */
437class SwSavePaintStatics : public SwPaintProperties
438{
439public:
440 SwSavePaintStatics();
441 ~SwSavePaintStatics();
442};
443
444}
445
446SwSavePaintStatics::SwSavePaintStatics()
447{
448 // Saving globales
449 bSFlyMetafile = gProp.bSFlyMetafile;
450 pSGlobalShell = gProp.pSGlobalShell;
451 pSFlyMetafileOut = gProp.pSFlyMetafileOut;
452 pSRetoucheFly = gProp.pSRetoucheFly;
453 pSRetoucheFly2 = gProp.pSRetoucheFly2;
454 pSFlyOnlyDraw = gProp.pSFlyOnlyDraw;
455 pBLines = std::move(gProp.pBLines);
456 pSLines = std::move(gProp.pSLines);
457 pSSubsLines = std::move(gProp.pSSubsLines);
458 pSSpecSubsLines = std::move(gProp.pSSpecSubsLines);
459 pSProgress = gProp.pSProgress;
460 nSPixelSzW = gProp.nSPixelSzW;
461 nSPixelSzH = gProp.nSPixelSzH;
462 nSHalfPixelSzW = gProp.nSHalfPixelSzW;
463 nSHalfPixelSzH = gProp.nSHalfPixelSzH;
464 nSMinDistPixelW = gProp.nSMinDistPixelW;
465 nSMinDistPixelH = gProp.nSMinDistPixelH ;
466 aSGlobalRetoucheColor = aGlobalRetoucheColor;
467 aSScaleX = gProp.aSScaleX;
468 aSScaleY = gProp.aSScaleY;
469
470 // Restoring globales to default
471 gProp.bSFlyMetafile = false;
472 gProp.pSFlyMetafileOut = nullptr;
473 gProp.pSRetoucheFly = nullptr;
474 gProp.pSRetoucheFly2 = nullptr;
475 gProp.nSPixelSzW = gProp.nSPixelSzH =
476 gProp.nSHalfPixelSzW = gProp.nSHalfPixelSzH =
477 gProp.nSMinDistPixelW = gProp.nSMinDistPixelH = 0;
478 gProp.aSScaleX = gProp.aSScaleY = 1.0;
479 gProp.pSProgress = nullptr;
480}
481
482SwSavePaintStatics::~SwSavePaintStatics()
483{
484 // Restoring globales to saved one
485 gProp.pSGlobalShell = pSGlobalShell;
486 gProp.bSFlyMetafile = bSFlyMetafile;
487 gProp.pSFlyMetafileOut = pSFlyMetafileOut;
488 gProp.pSRetoucheFly = pSRetoucheFly;
489 gProp.pSRetoucheFly2 = pSRetoucheFly2;
490 gProp.pSFlyOnlyDraw = pSFlyOnlyDraw;
491 gProp.pBLines = std::move(pBLines);
492 gProp.pSLines = std::move(pSLines);
493 gProp.pSSubsLines = std::move(pSSubsLines);
494 gProp.pSSpecSubsLines = std::move(pSSpecSubsLines);
495 gProp.pSProgress = pSProgress;
496 gProp.nSPixelSzW = nSPixelSzW;
497 gProp.nSPixelSzH = nSPixelSzH;
498 gProp.nSHalfPixelSzW = nSHalfPixelSzW;
499 gProp.nSHalfPixelSzH = nSHalfPixelSzH;
500 gProp.nSMinDistPixelW = nSMinDistPixelW;
501 gProp.nSMinDistPixelH = nSMinDistPixelH;
502 aGlobalRetoucheColor = aSGlobalRetoucheColor;
503 gProp.aSScaleX = aSScaleX;
504 gProp.aSScaleY = aSScaleY;
505}
506
507void BorderLines::AddBorderLines(const drawinglayer::primitive2d::Primitive2DContainer& rContainer)
508{
509 if(!rContainer.empty())
510 {
511 m_Lines.append(rContainer);
512 }
513}
514
515SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
516 const SwTabFrame *pT, const SubColFlags nSCol ) :
517 SwRect( rRect ),
518 nStyle( nStyl ),
519 pTab( pT ),
520 nSubColor( nSCol ),
521 bPainted( false ),
522 nLock( 0 )
523{
524 if ( pCol != nullptr )
525 aColor = *pCol;
526}
527
528bool SwLineRect::MakeUnion( const SwRect &rRect, SwPaintProperties const & properties)
529{
530 // It has already been tested outside, whether the rectangles have
531 // the same orientation (horizontal or vertical), color, etc.
532 if ( Height() > Width() ) //Vertical line
533 {
534 if ( Left() == rRect.Left() && Width() == rRect.Width() )
535 {
536 // Merge when there is no gap between the lines
537 const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
538 if ( Bottom() + nAdd >= rRect.Top() &&
539 Top() - nAdd <= rRect.Bottom() )
540 {
541 Bottom( std::max( Bottom(), rRect.Bottom() ) );
542 Top ( std::min( Top(), rRect.Top() ) );
543 return true;
544 }
545 }
546 }
547 else
548 {
549 if ( Top() == rRect.Top() && Height() == rRect.Height() )
550 {
551 // Merge when there is no gap between the lines
552 const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
553 if ( Right() + nAdd >= rRect.Left() &&
554 Left() - nAdd <= rRect.Right() )
555 {
556 Right( std::max( Right(), rRect.Right() ) );
557 Left ( std::min( Left(), rRect.Left() ) );
558 return true;
559 }
560 }
561 }
562 return false;
563}
564
565void SwLineRects::AddLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
566 const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const & properties )
567{
568 // Loop backwards because lines which can be combined, can usually be painted
569 // in the same context
570 for (reverse_iterator it = aLineRects.rbegin(); it != aLineRects.rend();
571 ++it)
572 {
573 SwLineRect &rLRect = *it;
574 // Test for the orientation, color, table
575 if ( rLRect.GetTab() == pTab &&
576 !rLRect.IsPainted() && rLRect.GetSubColor() == nSCol &&
577 (rLRect.Height() > rLRect.Width()) == (rRect.Height() > rRect.Width()) &&
578 (pCol && rLRect.GetColor() == *pCol) )
579 {
580 if ( rLRect.MakeUnion( rRect, properties ) )
581 return;
582 }
583 }
584 aLineRects.emplace_back( rRect, pCol, nStyle, pTab, nSCol );
585}
586
587void SwLineRects::ConnectEdges( OutputDevice const *pOut, SwPaintProperties const & properties )
588{
589 if ( pOut->GetOutDevType() != OUTDEV_PRINTER )
590 {
591 // I'm not doing anything for a too small zoom
592 if ( properties.aSScaleX < aEdgeScale || properties.aSScaleY < aEdgeScale )
593 return;
594 }
595
596 static const long nAdd = 20;
597
598 std::vector<SwLineRect*> aCheck;
599
600 for (size_t i = 0; i < aLineRects.size(); ++i)
601 {
602 SwLineRect &rL1 = aLineRects[i];
603 if ( !rL1.GetTab() || rL1.IsPainted() || rL1.IsLocked() )
604 continue;
605
606 aCheck.clear();
607
608 const bool bVert = rL1.Height() > rL1.Width();
609 long nL1a, nL1b, nL1c, nL1d;
610
611 if ( bVert )
612 {
613 nL1a = rL1.Top(); nL1b = rL1.Left();
614 nL1c = rL1.Right(); nL1d = rL1.Bottom();
615 }
616 else
617 {
618 nL1a = rL1.Left(); nL1b = rL1.Top();
619 nL1c = rL1.Bottom(); nL1d = rL1.Right();
620 }
621
622 // Collect all lines to possibly link with i1
623 for (iterator it2 = aLineRects.begin(); it2 != aLineRects.end(); ++it2)
624 {
625 SwLineRect &rL2 = *it2;
626 if ( rL2.GetTab() != rL1.GetTab() ||
627 rL2.IsPainted() ||
628 rL2.IsLocked() ||
629 (bVert == (rL2.Height() > rL2.Width())) )
630 continue;
631
632 long nL2a, nL2b, nL2c, nL2d;
633 if ( bVert )
634 {
635 nL2a = rL2.Top(); nL2b = rL2.Left();
636 nL2c = rL2.Right(); nL2d = rL2.Bottom();
637 }
638 else
639 {
640 nL2a = rL2.Left(); nL2b = rL2.Top();
641 nL2c = rL2.Bottom(); nL2d = rL2.Right();
642 }
643
644 if ( (nL1a - nAdd < nL2d && nL1d + nAdd > nL2a) &&
645 ((nL1b > nL2b && nL1c < nL2c) ||
646 (nL1c >= nL2c && nL1b - nAdd < nL2c) ||
647 (nL1b <= nL2b && nL1c + nAdd > nL2b)) )
648 {
649 aCheck.push_back( &rL2 );
650 }
651 }
652 if ( aCheck.size() < 2 )
653 continue;
654
655 bool bRemove = false;
656
657 // For each line test all following ones.
658 for ( size_t k = 0; !bRemove && k < aCheck.size(); ++k )
659 {
660 SwLineRect &rR1 = *aCheck[k];
661
662 for ( size_t k2 = k+1; !bRemove && k2 < aCheck.size(); ++k2 )
663 {
664 SwLineRect &rR2 = *aCheck[k2];
665 if ( bVert )
666 {
667 SwLineRect *pLA = nullptr;
668 SwLineRect *pLB = nullptr;
669 if ( rR1.Top() < rR2.Top() )
670 {
671 pLA = &rR1; pLB = &rR2;
672 }
673 else if ( rR1.Top() > rR2.Top() )
674 {
675 pLA = &rR2; pLB = &rR1;
676 }
677 // are k1 and k2 describing a double line?
678 if ( pLA && pLA->Bottom() + 60 > pLB->Top() )
679 {
680 if ( rL1.Top() < pLA->Top() )
681 {
682 if ( rL1.Bottom() == pLA->Bottom() )
683 continue; //Small mistake (where?)
684
685 SwRect aIns( rL1 );
686 aIns.Bottom( pLA->Bottom() );
687 if ( !rL1.IsInside( aIns ) )
688 continue;
689 aLineRects.emplace_back( aIns, &rL1.GetColor(),
690 SvxBorderLineStyle::SOLID,
691 rL1.GetTab(), SubColFlags::Tab );
692 if ( isFull() )
693 {
694 --i;
695 k = aCheck.size();
696 break;
697 }
698 }
699
700 if ( rL1.Bottom() > pLB->Bottom() )
701 rL1.Top( pLB->Top() ); // extend i1 on the top
702 else
703 bRemove = true; //stopping, remove i1
704 }
705 }
706 else
707 {
708 SwLineRect *pLA = nullptr;
709 SwLineRect *pLB = nullptr;
710 if ( rR1.Left() < rR2.Left() )
711 {
712 pLA = &rR1; pLB = &rR2;
713 }
714 else if ( rR1.Left() > rR2.Left() )
715 {
716 pLA = &rR2; pLB = &rR1;
717 }
718 // Is it double line?
719 if ( pLA && pLA->Right() + 60 > pLB->Left() )
720 {
721 if ( rL1.Left() < pLA->Left() )
722 {
723 if ( rL1.Right() == pLA->Right() )
724 continue; //small error
725
726 SwRect aIns( rL1 );
727 aIns.Right( pLA->Right() );
728 if ( !rL1.IsInside( aIns ) )
729 continue;
730 aLineRects.emplace_back( aIns, &rL1.GetColor(),
731 SvxBorderLineStyle::SOLID,
732 rL1.GetTab(), SubColFlags::Tab );
733 if ( isFull() )
734 {
735 --i;
736 k = aCheck.size();
737 break;
738 }
739 }
740 if ( rL1.Right() > pLB->Right() )
741 rL1.Left( pLB->Left() );
742 else
743 bRemove = true;
744 }
745 }
746 }
747 }
748 if ( bRemove )
749 {
750 aLineRects.erase(aLineRects.begin() + i);
751 --i;
752 }
753 }
754}
755
756void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const & properties )
757{
758 // All help lines that are covered by any border will be removed or split
759 for (size_t i = 0; i < aLineRects.size(); ++i)
760 {
761 // get a copy instead of a reference, because an <insert> may destroy
762 // the object due to a necessary array resize.
763 const SwLineRect aSubsLineRect(aLineRects[i]);
764
765 // add condition <aSubsLineRect.IsLocked()> in order to consider only
766 // border lines, which are *not* locked.
767 if ( aSubsLineRect.IsPainted() ||
768 aSubsLineRect.IsLocked() )
769 continue;
770
771 const bool bVerticalSubs = aSubsLineRect.Height() > aSubsLineRect.Width();
772 SwRect aSubsRect( aSubsLineRect );
773 if ( bVerticalSubs )
774 {
775 aSubsRect.AddLeft ( - (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
776 aSubsRect.AddRight ( properties.nSPixelSzW+properties.nSHalfPixelSzW );
777 }
778 else
779 {
780 aSubsRect.AddTop ( - (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
781 aSubsRect.AddBottom( properties.nSPixelSzH+properties.nSHalfPixelSzH );
782 }
783 for (const_iterator itK = rRects.aLineRects.begin(); itK != rRects.aLineRects.end(); ++itK)
784 {
785 const SwLineRect &rLine = *itK;
786
787 // do *not* consider painted or locked border lines.
788 // #i1837# - locked border lines have to be considered.
789 if ( rLine.IsLocked () )
790 continue;
791
792 if ( !bVerticalSubs == ( rLine.Height() > rLine.Width() ) ) //same direction?
793 continue;
794
795 if ( aSubsRect.IsOver( rLine ) )
796 {
797 if ( bVerticalSubs ) // Vertical?
798 {
799 if ( aSubsRect.Left() <= rLine.Right() &&
800 aSubsRect.Right() >= rLine.Left() )
801 {
802 long nTmp = rLine.Top()-(properties.nSPixelSzH+1);
803 if ( aSubsLineRect.Top() < nTmp )
804 {
805 SwRect aNewSubsRect( aSubsLineRect );
806 aNewSubsRect.Bottom( nTmp );
807 aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
808 aSubsLineRect.GetSubColor() );
809 }
810 nTmp = rLine.Bottom()+properties.nSPixelSzH+1;
811 if ( aSubsLineRect.Bottom() > nTmp )
812 {
813 SwRect aNewSubsRect( aSubsLineRect );
814 aNewSubsRect.Top( nTmp );
815 aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
816 aSubsLineRect.GetSubColor() );
817 }
818 aLineRects.erase(aLineRects.begin() + i);
819 --i;
820 break;
821 }
822 }
823 else // Horizontal
824 {
825 if ( aSubsRect.Top() <= rLine.Bottom() &&
826 aSubsRect.Bottom() >= rLine.Top() )
827 {
828 long nTmp = rLine.Left()-(properties.nSPixelSzW+1);
829 if ( aSubsLineRect.Left() < nTmp )
830 {
831 SwRect aNewSubsRect( aSubsLineRect );
832 aNewSubsRect.Right( nTmp );
833 aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
834 aSubsLineRect.GetSubColor() );
835 }
836 nTmp = rLine.Right()+properties.nSPixelSzW+1;
837 if ( aSubsLineRect.Right() > nTmp )
838 {
839 SwRect aNewSubsRect( aSubsLineRect );
840 aNewSubsRect.Left( nTmp );
841 aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
842 aSubsLineRect.GetSubColor() );
843 }
844 aLineRects.erase(aLineRects.begin() + i);
845 --i;
846 break;
847 }
848 }
849 }
850 }
851 }
852}
853
854void SwLineRects::LockLines( bool bLock )
855{
856 for (SwLineRect& rLRect : aLineRects)
857 rLRect.Lock( bLock );
858}
859
860static void lcl_DrawDashedRect( OutputDevice * pOut, SwLineRect const & rLRect )
861{
862 long startX = rLRect.Left( ), endX;
863 long startY = rLRect.Top( ), endY;
864
865 // Discriminate vertically stretched rect from horizontally stretched
866 // and restrict minimum nHalfLWidth to 1
867 long nHalfLWidth = std::max( static_cast<long>(std::min( rLRect.Width( ), rLRect.Height( ) ) / 2), 1L );
868
869 if ( rLRect.Height( ) > rLRect.Width( ) )
870 {
871 startX += nHalfLWidth;
872 endX = startX;
873 endY = startY + rLRect.Height( );
874 }
875 else
876 {
877 startY += nHalfLWidth;
878 endY = startY;
879 endX = startX + rLRect.Width( );
880 }
881
882 svtools::DrawLine( *pOut, Point( startX, startY ), Point( endX, endY ),
883 sal_uInt32( nHalfLWidth * 2 ), rLRect.GetStyle( ) );
884}
885
886void SwLineRects::PaintLines( OutputDevice *pOut, SwPaintProperties const &properties )
887{
888 // Paint the borders. Sadly two passes are needed.
889 // Once for the inside and once for the outside edges of tables
890 if ( aLineRects.size() == nLastCount )
891 return;
892
893 // #i16816# tagged pdf support
894 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
895
896 pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
897 pOut->SetFillColor();
898 pOut->SetLineColor();
899 ConnectEdges( pOut, properties );
900 const Color *pLast = nullptr;
901
902 bool bPaint2nd = false;
903 size_t nMinCount = aLineRects.size();
904
905 for ( size_t i = 0; i < aLineRects.size(); ++i )
906 {
907 SwLineRect &rLRect = aLineRects[i];
908
909 if ( rLRect.IsPainted() )
910 continue;
911
912 if ( rLRect.IsLocked() )
913 {
914 nMinCount = std::min( nMinCount, i );
915 continue;
916 }
917
918 // Paint it now or in the second pass?
919 bool bPaint = true;
920 if ( rLRect.GetTab() )
921 {
922 if ( rLRect.Height() > rLRect.Width() )
923 {
924 // Vertical edge, overlapping with the table edge?
925 SwTwips nLLeft = rLRect.Left() - 30,
926 nLRight = rLRect.Right() + 30,
927 nTLeft = rLRect.GetTab()->getFrameArea().Left() + rLRect.GetTab()->getFramePrintArea().Left(),
928 nTRight = rLRect.GetTab()->getFrameArea().Left() + rLRect.GetTab()->getFramePrintArea().Right();
929 if ( (nTLeft >= nLLeft && nTLeft <= nLRight) ||
930 (nTRight>= nLLeft && nTRight<= nLRight) )
931 bPaint = false;
932 }
933 else
934 {
935 // Horizontal edge, overlapping with the table edge?
936 SwTwips nLTop = rLRect.Top() - 30,
937 nLBottom = rLRect.Bottom() + 30,
938 nTTop = rLRect.GetTab()->getFrameArea().Top() + rLRect.GetTab()->getFramePrintArea().Top(),
939 nTBottom = rLRect.GetTab()->getFrameArea().Top() + rLRect.GetTab()->getFramePrintArea().Bottom();
940 if ( (nTTop >= nLTop && nTTop <= nLBottom) ||
941 (nTBottom >= nLTop && nTBottom <= nLBottom) )
942 bPaint = false;
943 }
944 }
945 if ( bPaint )
946 {
947 if ( !pLast || *pLast != rLRect.GetColor() )
948 {
949 pLast = &rLRect.GetColor();
950
951 DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
952 if( properties.pSGlobalShell->GetWin() &&
953 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
954 pOut->SetDrawMode( DrawModeFlags::Default );
955
956 pOut->SetLineColor( *pLast );
957 pOut->SetFillColor( *pLast );
958 pOut->SetDrawMode( nOldDrawMode );
959 }
960
961 if( !rLRect.IsEmpty() )
962 lcl_DrawDashedRect( pOut, rLRect );
963 rLRect.SetPainted();
964 }
965 else
966 bPaint2nd = true;
967 }
968 if ( bPaint2nd )
969 {
970 for ( size_t i = 0; i < aLineRects.size(); ++i )
971 {
972 SwLineRect &rLRect = aLineRects[i];
973 if ( rLRect.IsPainted() )
974 continue;
975
976 if ( rLRect.IsLocked() )
977 {
978 nMinCount = std::min( nMinCount, i );
979 continue;
980 }
981
982 if ( !pLast || *pLast != rLRect.GetColor() )
983 {
984 pLast = &rLRect.GetColor();
985
986 DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
987 if( properties.pSGlobalShell->GetWin() &&
988 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
989 {
990 pOut->SetDrawMode( DrawModeFlags::Default );
991 }
992
993 pOut->SetFillColor( *pLast );
994 pOut->SetDrawMode( nOldDrawMode );
995 }
996 if( !rLRect.IsEmpty() )
997 lcl_DrawDashedRect( pOut, rLRect );
998 rLRect.SetPainted();
999 }
1000 }
1001 nLastCount = nMinCount;
1002 pOut->Pop();
1003
1004}
1005
1006void SwSubsRects::PaintSubsidiary( OutputDevice *pOut,
1007 const SwLineRects *pRects,
1008 SwPaintProperties const & properties )
1009{
1010 if ( aLineRects.empty() )
1011 return;
1012
1013 // #i16816# tagged pdf support
1014 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
1015
1016 // Remove all help line that are almost covered (tables)
1017 for (size_type i = 0; i != aLineRects.size(); ++i)
1018 {
1019 SwLineRect &rLi = aLineRects[i];
1020 const bool bVerticalSubs = rLi.Height() > rLi.Width();
1021
1022 for (size_type k = i + 1; k != aLineRects.size(); ++k)
1023 {
1024 SwLineRect &rLk = aLineRects[k];
1025 if ( rLi.SSize() == rLk.SSize() )
1026 {
1027 if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) )
1028 {
1029 if ( bVerticalSubs )
1030 {
1031 long nLi = rLi.Right();
1032 long nLk = rLk.Right();
1033 if ( rLi.Top() == rLk.Top() &&
1034 ((nLi < rLk.Left() && nLi+21 > rLk.Left()) ||
1035 (nLk < rLi.Left() && nLk+21 > rLi.Left())))
1036 {
1037 aLineRects.erase(aLineRects.begin() + i);
1038 // don't continue with inner loop any more:
1039 // the array may shrink!
1040 --i;
1041 break;
1042 }
1043 }
1044 else
1045 {
1046 long nLi = rLi.Bottom();
1047 long nLk = rLk.Bottom();
1048 if ( rLi.Left() == rLk.Left() &&
1049 ((nLi < rLk.Top() && nLi+21 > rLk.Top()) ||
1050 (nLk < rLi.Top() && nLk+21 > rLi.Top())))
1051 {
1052 aLineRects.erase(aLineRects.begin() + i);
1053 // don't continue with inner loop any more:
1054 // the array may shrink!
1055 --i;
1056 break;
1057 }
1058 }
1059 }
1060 }
1061 }
1062 }
1063
1064 if ( pRects && (!pRects->aLineRects.empty()) )
1065 RemoveSuperfluousSubsidiaryLines( *pRects, properties );
1066
1067 if ( aLineRects.empty() )
1068 return;
1069
1070 pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
1071 pOut->SetLineColor();
1072
1073 // Reset draw mode in high contrast mode in order to get fill color
1074 // set at output device. Recover draw mode after draw of lines.
1075 // Necessary for the subsidiary lines painted by the fly frames.
1076 DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
1077 if( gProp.pSGlobalShell->GetWin() &&
1078 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1079 {
1080 pOut->SetDrawMode( DrawModeFlags::Default );
1081 }
1082
1083 for (SwLineRect& rLRect : aLineRects)
1084 {
1085 // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
1086 if ( !rLRect.IsPainted() &&
1087 !rLRect.IsLocked() )
1088 {
1089 const Color *pCol = nullptr;
1090 switch ( rLRect.GetSubColor() )
1091 {
1092 case SubColFlags::Page: pCol = &SwViewOption::GetDocBoundariesColor(); break;
1093 case SubColFlags::Fly: pCol = &SwViewOption::GetObjectBoundariesColor(); break;
1094 case SubColFlags::Tab: pCol = &SwViewOption::GetTableBoundariesColor(); break;
1095 case SubColFlags::Sect: pCol = &SwViewOption::GetSectionBoundColor(); break;
1096 }
1097
1098 if (pCol && pOut->GetFillColor() != *pCol)
1099 pOut->SetFillColor( *pCol );
1100 pOut->DrawRect( rLRect.SVRect() );
1101
1102 rLRect.SetPainted();
1103 }
1104 }
1105
1106 pOut->SetDrawMode( nOldDrawMode );
1107
1108 pOut->Pop();
1109}
1110
1111// Various functions that are use in this file.
1112
1113/**
1114 * Function <SwAlignRect(..)> is also used outside this file
1115 *
1116 * Correction: adjust rectangle on pixel level in order to make sure,
1117 * that the border "leaves its original pixel", if it has to
1118 * No prior adjustments for odd relation between pixel and twip
1119 */
1120void SwAlignRect( SwRect &rRect, const SwViewShell *pSh, const vcl::RenderContext* pRenderContext )
1121{
1122 if( !rRect.HasArea() )
1123 return;
1124
1125 // Make sure that view shell (parameter <pSh>) exists, if the output device
1126 // is taken from this view shell --> no output device, no alignment
1127 // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
1128 if ( !gProp.bSFlyMetafile && !pSh )
1129 {
1130 return;
1131 }
1132
1133 const vcl::RenderContext *pOut = gProp.bSFlyMetafile ?
1134 gProp.pSFlyMetafileOut.get() : pRenderContext;
1135
1136 // Hold original rectangle in pixel
1137 const tools::Rectangle aOrgPxRect = pOut->LogicToPixel( rRect.SVRect() );
1138 // Determine pixel-center rectangle in twip
1139 const SwRect aPxCenterRect( pOut->PixelToLogic( aOrgPxRect ) );
1140
1141 // Perform adjustments on pixel level.
1142 SwRect aAlignedPxRect( aOrgPxRect );
1143 if ( rRect.Top() > aPxCenterRect.Top() )
1144 {
1145 // 'leave pixel overlapping on top'
1146 aAlignedPxRect.AddTop( 1 );
1147 }
1148
1149 if ( rRect.Bottom() < aPxCenterRect.Bottom() )
1150 {
1151 // 'leave pixel overlapping on bottom'
1152 aAlignedPxRect.AddBottom( - 1 );
1153 }
1154
1155 if ( rRect.Left() > aPxCenterRect.Left() )
1156 {
1157 // 'leave pixel overlapping on left'
1158 aAlignedPxRect.AddLeft( 1 );
1159 }
1160
1161 if ( rRect.Right() < aPxCenterRect.Right() )
1162 {
1163 // 'leave pixel overlapping on right'
1164 aAlignedPxRect.AddRight( - 1 );
1165 }
1166
1167 // Consider negative width/height check, if aligned SwRect has negative width/height.
1168 // If Yes, adjust it to width/height = 0 twip.
1169 // NOTE: A SwRect with negative width/height can occur, if the width/height
1170 // of the given SwRect in twip was less than a pixel in twip and that
1171 // the alignment calculates that the aligned SwRect should not contain
1172 // the pixels the width/height is on.
1173 if ( aAlignedPxRect.Width() < 0 )
1174 {
1175 aAlignedPxRect.Width(0);
1176 }
1177 if ( aAlignedPxRect.Height() < 0 )
1178 {
1179 aAlignedPxRect.Height(0);
1180 }
1181 // Consider zero width/height for converting a rectangle from
1182 // pixel to logic it needs a width/height. Thus, set width/height
1183 // to one, if it's zero and correct this on the twip level after the conversion.
1184 bool bZeroWidth = false;
1185 if ( aAlignedPxRect.Width() == 0 )
1186 {
1187 aAlignedPxRect.Width(1);
1188 bZeroWidth = true;
1189 }
1190 bool bZeroHeight = false;
1191 if ( aAlignedPxRect.Height() == 0 )
1192 {
1193 aAlignedPxRect.Height(1);
1194 bZeroHeight = true;
1195 }
1196
1197 rRect = pOut->PixelToLogic( aAlignedPxRect.SVRect() );
1198
1199 // Consider zero width/height and adjust calculated aligned twip rectangle.
1200 // Reset width/height to zero; previous negative width/height haven't to be considered.
1201 if ( bZeroWidth )
1202 {
1203 rRect.Width(0);
1204 }
1205 if ( bZeroHeight )
1206 {
1207 rRect.Height(0);
1208 }
1209}
1210
1211/**
1212 * Method to pixel-align rectangle for drawing graphic object
1213 *
1214 * Because we are drawing graphics from the left-top-corner in conjunction
1215 * with size coordinates, these coordinates have to be calculated at a pixel
1216 * level.
1217 * Thus, we convert the rectangle to pixel and then convert to left-top-corner
1218 * and then get size of pixel rectangle back to logic.
1219 * This calculation is necessary, because there's a different between
1220 * the conversion from logic to pixel of a normal rectangle with its left-top-
1221 * and right-bottom-corner and the same conversion of the same rectangle
1222 * with left-top-corner and size.
1223 *
1224 * NOTE: Call this method before each <GraphicObject.Draw(...)>
1225*/
1226void SwAlignGrfRect( SwRect *pGrfRect, const vcl::RenderContext &rOut )
1227{
1228 tools::Rectangle aPxRect = rOut.LogicToPixel( pGrfRect->SVRect() );
1229 pGrfRect->Pos( rOut.PixelToLogic( aPxRect.TopLeft() ) );
1230 pGrfRect->SSize( rOut.PixelToLogic( aPxRect.GetSize() ) );
1231}
1232
1233static long lcl_AlignWidth( const long nWidth, SwPaintProperties const & properties )
1234{
1235 if ( nWidth )
1236 {
1237 const long nW = nWidth % properties.nSPixelSzW;
1238
1239 if ( !nW || nW > properties.nSHalfPixelSzW )
1240 return std::max(1L, nWidth - properties.nSHalfPixelSzW);
1241 }
1242 return nWidth;
1243}
1244
1245static long lcl_AlignHeight( const long nHeight, SwPaintProperties const & properties )
1246{
1247 if ( nHeight )
1248 {
1249 const long nH = nHeight % properties.nSPixelSzH;
1250
1251 if ( !nH || nH > properties.nSHalfPixelSzH )
1252 return std::max(1L, nHeight - properties.nSHalfPixelSzH);
1253 }
1254 return nHeight;
1255}
1256
1257/**
1258 * Calculate PrtArea plus surrounding plus shadow
1259 */
1260static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame,
1261 const SwBorderAttrs &rAttrs,
1262 const bool bShadow,
1263 SwPaintProperties const & properties)
1264{
1265 // Special handling for cell frames.
1266 // The printing area of a cell frame is completely enclosed in the frame area
1267 // and a cell frame has no shadow. Thus, for cell frames the calculated
1268 // area equals the frame area.
1269 // Notes: Borders of cell frames in R2L text direction will switch its side
1270 // - left border is painted on the right; right border on the left.
1271 // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
1272 if( pFrame->IsSctFrame() )
1273 {
1274 rRect = pFrame->getFramePrintArea();
1275 rRect.Pos() += pFrame->getFrameArea().Pos();
1276 }
1277 else if ( pFrame->IsCellFrame() )
1278 rRect = pFrame->getFrameArea();
1279 else
1280 {
1281 rRect = pFrame->getFramePrintArea();
1282 rRect.Pos() += pFrame->getFrameArea().Pos();
1283
1284 SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? (pFrame->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
1285
1286 const SvxBoxItem &rBox = rAttrs.GetBox();
1287 const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
1288 if ( bTop )
1289 {
1290 SwTwips nDiff = rBox.GetTop() ?
1291 rBox.CalcLineSpace( SvxBoxItemLine::TOP ) :
1292 rBox.GetDistance( SvxBoxItemLine::TOP );
1293 if( nDiff )
1294 (rRect.*fnRect->fnSubTop)( nDiff );
1295 }
1296
1297 const bool bBottom = 0 != (pFrame->*fnRect->fnGetBottomMargin)();
1298 if ( bBottom )
1299 {
1300 SwTwips nDiff = 0;
1301 // #i29550#
1302 if ( pFrame->IsTabFrame() &&
1303 static_cast<const SwTabFrame*>(pFrame)->IsCollapsingBorders() )
1304 {
1305 // For collapsing borders, we have to add the height of
1306 // the height of the last line
1307 nDiff = static_cast<const SwTabFrame*>(pFrame)->GetBottomLineSize();
1308 }
1309 else
1310 {
1311 nDiff = rBox.GetBottom() ?
1312 rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM ) :
1313 rBox.GetDistance( SvxBoxItemLine::BOTTOM );
1314 }
1315 if( nDiff )
1316 (rRect.*fnRect->fnAddBottom)( nDiff );
1317 }
1318
1319 if ( rBox.GetLeft() )
1320 (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( SvxBoxItemLine::LEFT ) );
1321 else
1322 (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( SvxBoxItemLine::LEFT ) );
1323
1324 if ( rBox.GetRight() )
1325 (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( SvxBoxItemLine::RIGHT ) );
1326 else
1327 (rRect.*fnRect->fnAddRight)( rBox.GetDistance( SvxBoxItemLine::RIGHT ) );
1328
1329 if ( bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
1330 {
1331 const SvxShadowItem &rShadow = rAttrs.GetShadow();
1332 if ( bTop )
1333 (rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
1334 (rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
1335 if ( bBottom )
1336 (rRect.*fnRect->fnAddBottom)
1337 (rShadow.CalcShadowSpace( SvxShadowItemSide::BOTTOM ));
1338 (rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
1339 }
1340 }
1341
1342 ::SwAlignRect( rRect, properties.pSGlobalShell, properties.pSGlobalShell ? properties.pSGlobalShell->GetOut() : nullptr );
1343}
1344
1345/**
1346 * Extend left/right border/shadow rectangle to bottom of previous frame/to
1347 * top of next frame, if border/shadow is joined with previous/next frame
1348 */
1349static void lcl_ExtendLeftAndRight( SwRect& _rRect,
1350 const SwFrame& _rFrame,
1351 const SwBorderAttrs& _rAttrs,
1352 const SwRectFn& _rRectFn )
1353{
1354 if ( _rAttrs.JoinedWithPrev( _rFrame ) )
1355 {
1356 const SwFrame* pPrevFrame = _rFrame.GetPrev();
1357 (_rRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
1358 }
1359 if ( _rAttrs.JoinedWithNext( _rFrame ) )
1360 {
1361 const SwFrame* pNextFrame = _rFrame.GetNext();
1362 (_rRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
1363 }
1364}
1365
1366/// Returns a range suitable for subtraction when lcl_SubtractFlys() is used.
1367/// Otherwise DrawFillAttributes() expands the clip path itself.
1368static basegfx::B2DRange lcl_ShrinkFly(const SwRect& rRect)
1369{
1370 static MapMode aMapMode(MapUnit::MapTwip);
1371 static const Size aSingleUnit = Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode);
1372
1373 double x1 = rRect.Left() + aSingleUnit.getWidth();
1374 double y1 = rRect.Top() + aSingleUnit.getHeight();
1375 double x2 = rRect.Right() - aSingleUnit.getWidth();
1376 double y2 = rRect.Bottom() - aSingleUnit.getHeight();
1377
1378 return basegfx::B2DRange(x1, y1, x2, y2);
1379}
1380
1381static void lcl_SubtractFlys( const SwFrame *pFrame, const SwPageFrame *pPage,
1382 const SwRect &rRect, SwRegionRects &rRegion, basegfx::utils::B2DClipState& rClipState, SwPaintProperties const & rProperties)
1383{
1384 const SwSortedObjs& rObjs = *pPage->GetSortedObjs();
1385 const SwFlyFrame* pSelfFly = pFrame->IsInFly() ? pFrame->FindFlyFrame() : gProp.pSRetoucheFly2;
1386 if (!gProp.pSRetoucheFly)
1387 gProp.pSRetoucheFly = gProp.pSRetoucheFly2;
1388
1389 for (size_t j = 0; (j < rObjs.size()) && !rRegion.empty(); ++j)
1390 {
1391 const SwAnchoredObject* pAnchoredObj = rObjs[j];
1392 const SdrObject* pSdrObj = pAnchoredObj->GetDrawObj();
1393
1394 // Do not consider invisible objects
1395 if (!pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj->GetLayer()))
1396 continue;
1397
1398 if (dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr)
1399 continue;
1400
1401 const SwFlyFrame *pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
1402
1403 if (pSelfFly == pFly || gProp.pSRetoucheFly == pFly || !rRect.IsOver(pFly->getFrameArea()))
1404 continue;
1405
1406 if (!pFly->GetFormat()->GetPrint().GetValue() &&
1407 (OUTDEV_PRINTER == gProp.pSGlobalShell->GetOut()->GetOutDevType() ||
1408 gProp.pSGlobalShell->IsPreview()))
1409 continue;
1410
1411 const bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly );
1412
1413 //For character bound Flys only examine those Flys in which it is not
1414 //anchored itself.
1415 //Why only for character bound ones you may ask? It never makes sense to
1416 //subtract frames in which it is anchored itself right?
1417 if (pSelfFly && pSelfFly->IsLowerOf(pFly))
1418 continue;
1419
1420 //Any why does it not apply for the RetoucheFly too?
1421 if (gProp.pSRetoucheFly && gProp.pSRetoucheFly->IsLowerOf(pFly))
1422 continue;
1423
1424#if OSL_DEBUG_LEVEL1 > 0
1425 //Flys who are anchored inside their own one, must have a bigger OrdNum
1426 //or be character bound.
1427 if (pSelfFly && bLowerOfSelf)
1428 {
1429 OSL_ENSURE( pFly->IsFlyInContentFrame() ||do { if (true && (!(pFly->IsFlyInContentFrame() ||
pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj
()->GetOrdNumDirect()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "1431" ": "), "%s", "Fly with wrong z-Order"); } } while
(false)
1430 pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(),do { if (true && (!(pFly->IsFlyInContentFrame() ||
pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj
()->GetOrdNumDirect()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "1431" ": "), "%s", "Fly with wrong z-Order"); } } while
(false)
1431 "Fly with wrong z-Order" )do { if (true && (!(pFly->IsFlyInContentFrame() ||
pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj
()->GetOrdNumDirect()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "1431" ": "), "%s", "Fly with wrong z-Order"); } } while
(false)
;
1432 }
1433#endif
1434
1435 bool bStopOnHell = true;
1436 if (pSelfFly)
1437 {
1438 const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
1439 if (pSdrObj->GetLayer() == pTmp->GetLayer())
1440 {
1441 if (pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect())
1442 //In the same layer we only observe those that are above.
1443 continue;
1444 }
1445 else
1446 {
1447 if (!bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue())
1448 //From other layers we are only interested in non
1449 //transparent ones or those that are internal
1450 continue;
1451 bStopOnHell = false;
1452 }
1453 }
1454 if (gProp.pSRetoucheFly)
1455 {
1456 const SdrObject *pTmp = gProp.pSRetoucheFly->GetVirtDrawObj();
1457 if ( pSdrObj->GetLayer() == pTmp->GetLayer() )
1458 {
1459 if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
1460 //In the same layer we only observe those that are above.
1461 continue;
1462 }
1463 else
1464 {
1465 if (!pFly->IsLowerOf( gProp.pSRetoucheFly ) && !pFly->GetFormat()->GetOpaque().GetValue())
1466 //From other layers we are only interested in non
1467 //transparent ones or those that are internal
1468 continue;
1469 bStopOnHell = false;
1470 }
1471 }
1472
1473 //If the content of the Fly is transparent, we subtract it only if it's
1474 //contained in the hell layer.
1475 const IDocumentDrawModelAccess& rIDDMA = pFly->GetFormat()->getIDocumentDrawModelAccess();
1476 bool bHell = pSdrObj->GetLayer() == rIDDMA.GetHellId();
1477 if ( (bStopOnHell && bHell) ||
1478 /// Change internal order of condition
1479 /// first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()"
1480 /// have not to be performed, if frame is in "Hell"
1481 ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTextFrame() &&
1482 (static_cast<SwNoTextFrame const*>(pFly->Lower())->IsTransparent() ||
1483 static_cast<SwNoTextFrame const*>(pFly->Lower())->HasAnimation() ||
1484 pFly->GetFormat()->GetSurround().IsContour()
1485 )
1486 )
1487 )
1488 continue;
1489
1490 // Own if-statements for transparent background/shadow of fly frames
1491 // in order to handle special conditions.
1492 if (pFly->IsBackgroundTransparent())
1493 {
1494 // Background <pFly> is transparent drawn. Thus normally, its region
1495 // have not to be subtracted from given region.
1496 // But, if method is called for a fly frame and
1497 // <pFly> is a direct lower of this fly frame and
1498 // <pFly> inherites its transparent background brush from its parent,
1499 // then <pFly> frame area have to be subtracted from given region.
1500 // NOTE: Because in Status Quo transparent backgrounds can only be
1501 // assigned to fly frames, the handle of this special case
1502 // avoids drawing of transparent areas more than once, if
1503 // a fly frame inherites a transparent background from its
1504 // parent fly frame.
1505 if (pFrame->IsFlyFrame() &&
1506 (pFly->GetAnchorFrame()->FindFlyFrame() == pFrame) &&
1507 pFly->GetFormat()->IsBackgroundBrushInherited()
1508 )
1509 {
1510 SwRect aRect;
1511 SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1512 const SwBorderAttrs &rAttrs = *aAccess.Get();
1513 ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1514 rRegion -= aRect;
1515 rClipState.subtractRange(lcl_ShrinkFly(aRect));
1516 continue;
1517 }
1518 else
1519 {
1520 continue;
1521 }
1522 }
1523
1524 if (bHell && pFly->GetAnchorFrame()->IsInFly())
1525 {
1526 //So the border won't get dismantled by the background of the other
1527 //Fly.
1528 SwRect aRect;
1529 SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
1530 const SwBorderAttrs &rAttrs = *aAccess.Get();
1531 ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
1532 rRegion -= aRect;
1533 rClipState.subtractRange(lcl_ShrinkFly(aRect));
1534 }
1535 else
1536 {
1537 SwRect aRect( pFly->getFramePrintArea() );
1538 aRect += pFly->getFrameArea().Pos();
1539 rRegion -= aRect;
1540 rClipState.subtractRange(lcl_ShrinkFly(aRect));
1541 }
1542 }
1543 if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
1544 gProp.pSRetoucheFly = nullptr;
1545}
1546
1547static void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1548 vcl::RenderContext* _pOut,
1549 const SwRect& _rAlignedPaintRect,
1550 const GraphicObject& _rGraphicObj,
1551 SwPaintProperties const & properties)
1552{
1553 /// determine color of background
1554 /// If color of background brush is not "no fill"/"auto fill" or
1555 /// <SwPaintProperties.bSFlyMetafile> is set, use color of background brush, otherwise
1556 /// use global retouche color.
1557 const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || properties.bSFlyMetafile )
1558 ? _rBackgrdBrush.GetColor()
1559 : aGlobalRetoucheColor );
1560
1561 /// determine, if background color have to be drawn transparent
1562 /// and calculate transparency percent value
1563 sal_Int8 nTransparencyPercent = 0;
1564 bool bDrawTransparent = false;
1565 if ( aColor.GetTransparency() != 0 )
1566 /// background color is transparent --> draw transparent.
1567 {
1568 bDrawTransparent = true;
1569 nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF;
1570 }
1571 else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) &&
1572 (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) )
1573 /// graphic is drawn transparent and background color is
1574 /// "no fill"/"auto fill" --> draw transparent
1575 {
1576 bDrawTransparent = true;
1577 nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF;
1578 }
1579
1580 if ( bDrawTransparent )
1581 {
1582 /// draw background transparent
1583 if( _pOut->GetFillColor() != aColor.GetRGBColor() )
1584 _pOut->SetFillColor( aColor.GetRGBColor() );
1585 tools::PolyPolygon aPoly( _rAlignedPaintRect.SVRect() );
1586 _pOut->DrawTransparent( aPoly, nTransparencyPercent );
1587 }
1588 else
1589 {
1590 /// draw background opaque
1591 if ( _pOut->GetFillColor() != aColor )
1592 _pOut->SetFillColor( aColor );
1593 _pOut->DrawRect( _rAlignedPaintRect.SVRect() );
1594 }
1595}
1596
1597/**
1598 * This is a local help method to draw a background for a graphic
1599 *
1600 * Under certain circumstances we have to draw a background for a graphic.
1601 * This method takes care of the conditions and draws the background with the
1602 * corresponding color.
1603 * Method introduced for bug fix #103876# in order to optimize drawing tiled
1604 * background graphics. Previously, this code was integrated in method
1605 * <lcl_DrawGraphic>.
1606 * Method implemented as an inline, checking the conditions and calling method
1607 * method <lcl_implDrawGraphicBackgrd(..)> for the intrinsic drawing.
1608 *
1609 * @param _rBackgrdBrush
1610 * background brush contain the color the background has to be drawn.
1611 *
1612 * @param _pOut
1613 * output device the background has to be drawn in.
1614 *
1615 * @param _rAlignedPaintRect
1616 * paint rectangle in the output device, which has to be drawn with the background.
1617 * rectangle have to be aligned by method ::SwAlignRect
1618 *
1619 * @param _rGraphicObj
1620 * graphic object, for which the background has to be drawn. Used for checking
1621 * the transparency of its bitmap, its type and if the graphic is drawn transparent
1622 *
1623 * @param _bNumberingGraphic
1624 * boolean indicating that graphic is used as a numbering.
1625 *
1626 * @param _bBackgrdAlreadyDrawn
1627 * boolean (optional; default: false) indicating, if the background is already drawn.
1628*/
1629static void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
1630 OutputDevice* _pOut,
1631 const SwRect& _rAlignedPaintRect,
1632 const GraphicObject& _rGraphicObj,
1633 bool _bNumberingGraphic,
1634 SwPaintProperties const & properties,
1635 bool _bBackgrdAlreadyDrawn = false)
1636{
1637 // draw background with background color, if
1638 // (1) graphic is not used as a numbering AND
1639 // (2) background is not already drawn AND
1640 // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
1641 if ( !_bNumberingGraphic &&
1642 !_bBackgrdAlreadyDrawn &&
1643 ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GraphicType::NONE )
1644 )
1645 {
1646 lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj, properties );
1647 }
1648}
1649
1650/**
1651 * NNOTE: the transparency of the background graphic is saved in
1652 * SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency()
1653 * and is considered in the drawing of the graphic
1654 *
1655 * Thus, to provide transparent background graphic for text frames nothing
1656 * has to be coded
1657 *
1658 * Use align rectangle for drawing graphic Pixel-align coordinates for
1659 * drawing graphic
1660 * Outsource code for drawing background of the graphic
1661 * with a background color in method <lcl_DrawGraphicBackgrd>
1662 *
1663 * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
1664 */
1665static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext *pOut,
1666 SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut,
1667 bool bGrfNum,
1668 SwPaintProperties const & properties,
1669 bool bBackgrdAlreadyDrawn )
1670 // add parameter <bBackgrdAlreadyDrawn> to indicate
1671 // that the background is already drawn.
1672{
1673 // Calculate align rectangle from parameter <rGrf> and use aligned
1674 // rectangle <aAlignedGrfRect> in the following code
1675 SwRect aAlignedGrfRect = rGrf;
1676 ::SwAlignRect( aAlignedGrfRect, &rSh, pOut );
1677
1678 // Change type from <bool> to <bool>.
1679 const bool bNotInside = !rOut.IsInside( aAlignedGrfRect );
1680 if ( bNotInside )
1681 {
1682 pOut->Push( PushFlags::CLIPREGION );
1683 pOut->IntersectClipRegion( rOut.SVRect() );
1684 }
1685
1686 GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
1687
1688 // Outsource drawing of background with a background color
1689 ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, properties, bBackgrdAlreadyDrawn );
1690
1691 // Because for drawing a graphic left-top-corner and size coordinates are
1692 // used, these coordinates have to be determined on pixel level.
1693 ::SwAlignGrfRect( &aAlignedGrfRect, *pOut );
1694
1695 const basegfx::B2DHomMatrix aGraphicTransform(
1696 basegfx::utils::createScaleTranslateB2DHomMatrix(
1697 aAlignedGrfRect.Width(), aAlignedGrfRect.Height(),
1698 aAlignedGrfRect.Left(), aAlignedGrfRect.Top()));
1699
1700 paintGraphicUsingPrimitivesHelper(
1701 *pOut,
1702 *pGrf,
1703 pGrf->GetAttr(),
1704 aGraphicTransform,
1705 OUString(),
1706 OUString(),
1707 OUString());
1708
1709 if ( bNotInside )
1710 pOut->Pop();
1711}
1712
1713bool DrawFillAttributes(
1714 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
1715 const SwRect& rOriginalLayoutRect,
1716 const SwRegionRects& rPaintRegion,
1717 const basegfx::utils::B2DClipState& rClipState,
1718 vcl::RenderContext& rOut)
1719{
1720 if(rFillAttributes && rFillAttributes->isUsed())
1721 {
1722 basegfx::B2DRange aPaintRange(
1723 rPaintRegion.GetOrigin().Left(),
1724 rPaintRegion.GetOrigin().Top(),
1725 rPaintRegion.GetOrigin().Right(),
1726 rPaintRegion.GetOrigin().Bottom());
1727
1728 if (!aPaintRange.isEmpty() &&
1729 !rPaintRegion.empty() &&
1730 !basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
1731 !basegfx::fTools::equalZero(aPaintRange.getHeight()))
1732 {
1733 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
1734
1735 // need to expand for correct AAed and non-AAed visualization as primitive.
1736 // This must probably be removed again when we will be able to get all Writer visualization
1737 // as primitives and Writer prepares all it's stuff in high precision coordinates (also
1738 // needs to avoid moving boundaries around to better show overlapping stuff...)
1739 if(aSvtOptionsDrawinglayer.IsAntiAliasing())
1740 {
1741 // if AAed in principle expand by 0.5 in all directions. Since painting edges of
1742 // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
1743 // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
1744 // artifacts. Checked experimentally - a little bit more in Y is needed, probably
1745 // due to still existing integer alignment and crunching in writer.
1746 static const double fExpandX = 0.55;
1747 static const double fExpandY = 0.70;
1748 const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX, fExpandY));
1749
1750 aPaintRange.expand(aPaintRange.getMinimum() - aSingleUnit);
1751 aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1752 }
1753 else
1754 {
1755 // if not AAed expand by one unit to bottom right due to the missing unit
1756 // from SwRect/Rectangle integer handling
1757 const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
1758
1759 aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
1760 }
1761
1762 const basegfx::B2DRange aDefineRange(
1763 rOriginalLayoutRect.Left(),
1764 rOriginalLayoutRect.Top(),
1765 rOriginalLayoutRect.Right(),
1766 rOriginalLayoutRect.Bottom());
1767
1768 const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rFillAttributes->getPrimitive2DSequence(
1769 aPaintRange,
1770 aDefineRange);
1771
1772 if(rSequence.size())
1773 {
1774 drawinglayer::primitive2d::Primitive2DContainer const*
1775 pPrimitives(&rSequence);
1776 drawinglayer::primitive2d::Primitive2DContainer primitives;
1777 // tdf#86578 the awful lcl_SubtractFlys hack
1778 if (rPaintRegion.size() > 1 || rPaintRegion[0] != rPaintRegion.GetOrigin())
1779 {
1780 basegfx::B2DPolyPolygon const& maskRegion(rClipState.getClipPoly());
1781 primitives.resize(1);
1782 primitives[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
1783 maskRegion, rSequence);
1784 pPrimitives = &primitives;
1785 }
1786 assert(pPrimitives && pPrimitives->size())(static_cast <bool> (pPrimitives && pPrimitives
->size()) ? void (0) : __assert_fail ("pPrimitives && pPrimitives->size()"
, "/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
, 1786, __extension__ __PRETTY_FUNCTION__))
;
1787
1788 const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
1789 basegfx::B2DHomMatrix(),
1790 rOut.GetViewTransformation(),
1791 aPaintRange,
1792 nullptr,
1793 0.0,
1794 uno::Sequence< beans::PropertyValue >());
1795 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1796 rOut,
1797 aViewInformation2D) );
1798 if(pProcessor)
1799 {
1800 pProcessor->process(*pPrimitives);
1801 return true;
1802 }
1803 }
1804 }
1805 }
1806
1807 return false;
1808}
1809
1810void DrawGraphic(
1811 const SvxBrushItem *pBrush,
1812 vcl::RenderContext *pOutDev,
1813 const SwRect &rOrg,
1814 const SwRect &rOut,
1815 const sal_uInt8 nGrfNum,
1816 const bool bConsiderBackgroundTransparency )
1817 // Add 6th parameter to indicate that method should
1818 // consider background transparency, saved in the color of the brush item
1819{
1820 SwViewShell &rSh = *gProp.pSGlobalShell;
1821 bool bReplaceGrfNum = GRFNUM_REPLACE2 == nGrfNum;
1822 bool bGrfNum = GRFNUM_NO0 != nGrfNum;
1823 Size aGrfSize;
1824 SvxGraphicPosition ePos = GPOS_NONE;
1825 if( pBrush && !bReplaceGrfNum )
1826 {
1827 if( rSh.GetViewOptions()->IsGraphic() )
1828 {
1829 OUString referer;
1830 SfxObjectShell * sh = rSh.GetDoc()->GetPersist();
1831 if (sh != nullptr && sh->HasName()) {
1832 referer = sh->GetMedium()->GetName();
1833 }
1834 const Graphic* pGrf = pBrush->GetGraphic(referer);
1835 if( pGrf && GraphicType::NONE != pGrf->GetType() )
1836 {
1837 ePos = pBrush->GetGraphicPos();
1838 if( pGrf->IsSupportedGraphic() )
1839 // don't the use the specific output device! Bug 94802
1840 aGrfSize = ::GetGraphicSizeTwip( *pGrf, nullptr );
1841 }
1842 }
1843 else
1844 bReplaceGrfNum = bGrfNum;
1845 }
1846
1847 SwRect aGrf;
1848 aGrf.SSize( aGrfSize );
1849 bool bDraw = true;
1850 bool bRetouche = true;
1851 switch ( ePos )
1852 {
1853 case GPOS_LT:
1854 aGrf.Pos() = rOrg.Pos();
1855 break;
1856
1857 case GPOS_MT:
1858 aGrf.Pos().setY( rOrg.Top() );
1859 aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1860 break;
1861
1862 case GPOS_RT:
1863 aGrf.Pos().setY( rOrg.Top() );
1864 aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1865 break;
1866
1867 case GPOS_LM:
1868 aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1869 aGrf.Pos().setX( rOrg.Left() );
1870 break;
1871
1872 case GPOS_MM:
1873 aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1874 aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1875 break;
1876
1877 case GPOS_RM:
1878 aGrf.Pos().setY( rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2 );
1879 aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1880 break;
1881
1882 case GPOS_LB:
1883 aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1884 aGrf.Pos().setX( rOrg.Left() );
1885 break;
1886
1887 case GPOS_MB:
1888 aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1889 aGrf.Pos().setX( rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2 );
1890 break;
1891
1892 case GPOS_RB:
1893 aGrf.Pos().setY( rOrg.Bottom() - aGrfSize.Height() );
1894 aGrf.Pos().setX( rOrg.Right() - aGrfSize.Width() );
1895 break;
1896
1897 case GPOS_AREA:
1898 aGrf = rOrg;
1899 // Despite the fact that the background graphic has to fill the complete
1900 // area, we already checked, whether the graphic will completely fill out
1901 // the region the <rOut> that is to be painted. Thus, nothing has to be
1902 // touched again.
1903 // E.g. this is the case for a Fly Frame without a background
1904 // brush positioned on the border of the page which inherited the background
1905 // brush from the page.
1906 bRetouche = !rOut.IsInside( aGrf );
1907 break;
1908
1909 case GPOS_TILED:
1910 {
1911 // draw background of tiled graphic before drawing tiled graphic in loop
1912 // determine graphic object
1913 GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject());
1914 // calculate aligned paint rectangle
1915 SwRect aAlignedPaintRect = rOut;
1916 ::SwAlignRect( aAlignedPaintRect, &rSh, pOutDev );
1917 // draw background color for aligned paint rectangle
1918 lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum, gProp );
1919
1920 // set left-top-corner of background graphic to left-top-corner of the
1921 // area, from which the background brush is determined.
1922 aGrf.Pos() = rOrg.Pos();
1923 // setup clipping at output device
1924 pOutDev->Push( PushFlags::CLIPREGION );
1925 pOutDev->IntersectClipRegion( rOut.SVRect() );
1926 // use new method <GraphicObject::DrawTiled(::)>
1927 {
1928 // calculate paint offset
1929 Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() );
1930 // draw background graphic tiled for aligned paint rectangle
1931 // #i42643#
1932 // For PDF export, every draw operation for bitmaps takes a
1933 // noticeable amount of place (~50 characters). Thus, optimize
1934 // between tile bitmap size and number of drawing operations here.
1935
1936 // A_out
1937 // n_chars = k1 * ---------- + k2 * A_bitmap
1938 // A_bitmap
1939
1940 // minimum n_chars is obtained for (derive for A_bitmap,
1941 // set to 0, take positive solution):
1942 // k1
1943 // A_bitmap = Sqrt( ---- A_out )
1944 // k2
1945
1946 // where k1 is the number of chars per draw operation, and
1947 // k2 is the number of chars per bitmap pixel.
1948 // This is approximately 50 and 7 for current PDF writer, respectively.
1949
1950 const double k1( 50 );
1951 const double k2( 7 );
1952 const Size aSize( aAlignedPaintRect.SSize() );
1953 const double Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() );
1954
1955 pGraphicObj->DrawTiled( pOutDev,
1956 aAlignedPaintRect.SVRect(),
1957 aGrf.SSize(),
1958 Size( aPaintOffset.X(), aPaintOffset.Y() ),
1959 std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
1960 }
1961 // reset clipping at output device
1962 pOutDev->Pop();
1963 // set <bDraw> and <bRetouche> to false, indicating that background
1964 // graphic and background are already drawn.
1965 bDraw = bRetouche = false;
1966 }
1967 break;
1968
1969 case GPOS_NONE:
1970 bDraw = false;
1971 break;
1972
1973 default: OSL_ENSURE( !pOutDev, "new Graphic position?" )do { if (true && (!(!pOutDev))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "1973" ": "), "%s", "new Graphic position?"); } } while (
false)
;
1974 }
1975
1976 /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of
1977 /// graphic is already drawn or not.
1978 bool bGrfBackgrdAlreadyDrawn = false;
1979 if ( bRetouche )
1980 {
1981 pOutDev->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
1982 pOutDev->SetLineColor();
1983
1984 // check, if an existing background graphic (not filling the complete
1985 // background) is transparent drawn and the background color is
1986 // "no fill" respectively "auto fill", if background transparency
1987 // has to be considered.
1988 // If YES, memorize transparency of background graphic.
1989 // check also, if background graphic bitmap is transparent.
1990 bool bTransparentGrfWithNoFillBackgrd = false;
1991 sal_Int32 nGrfTransparency = 0;
1992 bool bGrfIsTransparent = false;
1993 if ( (ePos != GPOS_NONE) &&
1994 (ePos != GPOS_TILED) && (ePos != GPOS_AREA)
1995 )
1996 {
1997 GraphicObject *pGrf = const_cast<GraphicObject*>(pBrush->GetGraphicObject());
1998 if ( bConsiderBackgroundTransparency )
1999 {
2000 GraphicAttr aGrfAttr = pGrf->GetAttr();
2001 if ( (aGrfAttr.GetTransparency() != 0) &&
2002 (pBrush->GetColor() == COL_TRANSPARENT)
2003 )
2004 {
2005 bTransparentGrfWithNoFillBackgrd = true;
2006 nGrfTransparency = aGrfAttr.GetTransparency();
2007 }
2008 }
2009 if ( pGrf->IsTransparent() )
2010 {
2011 bGrfIsTransparent = true;
2012 }
2013 }
2014
2015 // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
2016 // instead of checking, if transparency is not set.
2017 const Color aColor( pBrush &&
2018 ( (pBrush->GetColor() != COL_TRANSPARENT) ||
2019 gProp.bSFlyMetafile )
2020 ? pBrush->GetColor()
2021 : aGlobalRetoucheColor );
2022
2023 // determine, if background region have to be
2024 // drawn transparent.
2025 // background region has to be drawn transparent, if
2026 // background transparency have to be considered
2027 // AND
2028 // ( background color is transparent OR
2029 // background graphic is transparent and background color is "no fill"
2030 // )
2031
2032 enum DrawStyle {
2033 Default,
2034 Transparent,
2035 } eDrawStyle = Default;
2036
2037 if (bConsiderBackgroundTransparency &&
2038 ( ( aColor.GetTransparency() != 0) ||
2039 bTransparentGrfWithNoFillBackgrd ) )
2040 {
2041 eDrawStyle = Transparent;
2042 }
2043
2044 // #i75614# reset draw mode in high contrast mode in order to get fill color set
2045 const DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
2046 if ( gProp.pSGlobalShell->GetWin() &&
2047 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2048 {
2049 pOutDev->SetDrawMode( DrawModeFlags::Default );
2050 }
2051
2052 // If background region has to be drawn transparent, set only the RGB values of the background color as
2053 // the fill color for the output device.
2054 switch (eDrawStyle)
2055 {
2056 case Transparent:
2057 {
2058 if( pOutDev->GetFillColor() != aColor.GetRGBColor() )
2059 pOutDev->SetFillColor( aColor.GetRGBColor() );
2060 break;
2061 }
2062 default:
2063 {
2064 if( pOutDev->GetFillColor() != aColor )
2065 pOutDev->SetFillColor( aColor );
2066 break;
2067 }
2068 }
2069
2070 // #i75614#
2071 // restore draw mode
2072 pOutDev->SetDrawMode( nOldDrawMode );
2073
2074 switch (eDrawStyle)
2075 {
2076 case Transparent:
2077 {
2078 // background region have to be drawn transparent.
2079 // Thus, create a poly-polygon from the region and draw it with
2080 // the corresponding transparency percent.
2081 tools::PolyPolygon aDrawPoly( rOut.SVRect() );
2082 if ( aGrf.HasArea() )
2083 {
2084 if ( !bGrfIsTransparent )
2085 {
2086 // subtract area of background graphic from draw area
2087 // Consider only that part of the graphic area that is overlapping with draw area.
2088 SwRect aTmpGrf = aGrf;
2089 aTmpGrf.Intersection( rOut );
2090 if ( aTmpGrf.HasArea() )
2091 {
2092 tools::Polygon aGrfPoly( aTmpGrf.SVRect() );
2093 aDrawPoly.Insert( aGrfPoly );
2094 }
2095 }
2096 else
2097 bGrfBackgrdAlreadyDrawn = true;
2098 }
2099 // calculate transparency percent:
2100 // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
2101 // If there is a background graphic with a background color "no fill"/"auto fill",
2102 // the transparency value is taken from the background graphic,
2103 // otherwise take the transparency value from the color.
2104 sal_Int8 nTransparencyPercent = static_cast<sal_Int8>(
2105 (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency()
2106 )*100 + 0x7F)/0xFF);
2107 // draw poly-polygon transparent
2108 pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent );
2109
2110 break;
2111 }
2112 case Default:
2113 default:
2114 {
2115 SwRegionRects aRegion( rOut, 4 );
2116 if ( !bGrfIsTransparent )
2117 aRegion -= aGrf;
2118 else
2119 bGrfBackgrdAlreadyDrawn = true;
2120 // loop rectangles of background region, which has to be drawn
2121 for( size_t i = 0; i < aRegion.size(); ++i )
2122 {
2123 pOutDev->DrawRect( aRegion[i].SVRect() );
2124 }
2125 }
2126 }
2127 pOutDev ->Pop();
2128 }
2129
2130 if( bDraw && aGrf.IsOver( rOut ) )
2131 lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, bGrfNum, gProp,
2132 bGrfBackgrdAlreadyDrawn );
2133
2134 if( bReplaceGrfNum )
2135 {
2136 const BitmapEx& rBmp = rSh.GetReplacementBitmap(false);
2137 vcl::Font aTmp( pOutDev->GetFont() );
2138 Graphic::DrawEx(pOutDev, OUString(), aTmp, rBmp, rOrg.Pos(), rOrg.SSize());
2139 }
2140}
2141
2142/**
2143 * Local helper for SwRootFrame::PaintSwFrame(..) - Adjust given rectangle to pixel size
2144 *
2145 * By OD at 27.09.2002 for #103636#
2146 * In order to avoid paint errors caused by multiple alignments (e.g. ::SwAlignRect(..))
2147 * and other changes to the to be painted rectangle, this method is called for the
2148 * rectangle to be painted in order to adjust it to the pixel it is overlapping
2149*/
2150static void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const vcl::RenderContext &aOut )
2151{
2152 // local constant object of class <Size> to determine number of Twips
2153 // representing a pixel.
2154 const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) );
2155
2156 // local object of class <Rectangle> in Twip coordinates
2157 // calculated from given rectangle aligned to pixel centers.
2158 const tools::Rectangle aPxCenterRect = aOut.PixelToLogic(
2159 aOut.LogicToPixel( io_aSwRect.SVRect() ) );
2160
2161 // local constant object of class <Rectangle> representing given rectangle
2162 // in pixel.
2163 const tools::Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2164
2165 // calculate adjusted rectangle from pixel centered rectangle.
2166 // Due to rounding differences <aPxCenterRect> doesn't exactly represents
2167 // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
2168 // Afterwards, adjust calculated Twip-positions of the all borders.
2169 tools::Rectangle aSizedRect = aPxCenterRect;
2170 aSizedRect.AdjustLeft( -(aTwipToPxSize.Width()/2 + 1) );
2171 aSizedRect.AdjustRight( aTwipToPxSize.Width()/2 + 1 );
2172 aSizedRect.AdjustTop( -(aTwipToPxSize.Height()/2 + 1) );
2173 aSizedRect.AdjustBottom(aTwipToPxSize.Height()/2 + 1);
2174
2175 // adjust left()
2176 while ( aOut.LogicToPixel(aSizedRect).Left() < aOrgPxRect.Left() )
2177 {
2178 aSizedRect.AdjustLeft( 1 );
2179 }
2180 // adjust right()
2181 while ( aOut.LogicToPixel(aSizedRect).Right() > aOrgPxRect.Right() )
2182 {
2183 aSizedRect.AdjustRight( -1 );
2184 }
2185 // adjust top()
2186 while ( aOut.LogicToPixel(aSizedRect).Top() < aOrgPxRect.Top() )
2187 {
2188 aSizedRect.AdjustTop( 1 );
2189 }
2190 // adjust bottom()
2191 while ( aOut.LogicToPixel(aSizedRect).Bottom() > aOrgPxRect.Bottom() )
2192 {
2193 aSizedRect.AdjustBottom( -1 );
2194 }
2195
2196 io_aSwRect = SwRect( aSizedRect );
2197
2198#if OSL_DEBUG_LEVEL1 > 0
2199 tools::Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
2200 tools::Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2201 OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect,do { if (true && (!(aTestOrgPxRect == aTestNewPxRect)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2202" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size"
); } } while (false)
2202 "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size")do { if (true && (!(aTestOrgPxRect == aTestNewPxRect)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2202" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size"
); } } while (false)
;
2203 // check Left()
2204 aSizedRect.AdjustLeft( -1 );
2205 aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2206 OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1),do { if (true && (!(aTestOrgPxRect.Left() >= (aTestNewPxRect
.Left()+1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2207" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted"
); } } while (false)
2207 "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted")do { if (true && (!(aTestOrgPxRect.Left() >= (aTestNewPxRect
.Left()+1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2207" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted"
); } } while (false)
;
2208 aSizedRect.AdjustLeft( 1 );
2209 // check Right()
2210 aSizedRect.AdjustRight( 1 );
2211 aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2212 OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1),do { if (true && (!(aTestOrgPxRect.Right() <= (aTestNewPxRect
.Right()-1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2213" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted"
); } } while (false)
2213 "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted")do { if (true && (!(aTestOrgPxRect.Right() <= (aTestNewPxRect
.Right()-1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2213" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted"
); } } while (false)
;
2214 aSizedRect.AdjustRight( -1 );
2215 // check Top()
2216 aSizedRect.AdjustTop( -1 );
2217 aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2218 OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1),do { if (true && (!(aTestOrgPxRect.Top() >= (aTestNewPxRect
.Top()+1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2219" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted"
); } } while (false)
2219 "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted")do { if (true && (!(aTestOrgPxRect.Top() >= (aTestNewPxRect
.Top()+1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2219" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted"
); } } while (false)
;
2220 aSizedRect.AdjustTop( 1 );
2221 // check Bottom()
2222 aSizedRect.AdjustBottom( 1 );
2223 aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
2224 OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1),do { if (true && (!(aTestOrgPxRect.Bottom() <= (aTestNewPxRect
.Bottom()-1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2225" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted"
); } } while (false)
2225 "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted")do { if (true && (!(aTestOrgPxRect.Bottom() <= (aTestNewPxRect
.Bottom()-1)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2225" ": "), "%s", "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted"
); } } while (false)
;
2226 aSizedRect.AdjustBottom( -1 );
2227#endif
2228}
2229
2230// FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
2231
2232namespace {
2233
2234struct SwLineEntry
2235{
2236 SwTwips mnKey;
2237 SwTwips mnStartPos;
2238 SwTwips mnEndPos;
2239
2240 svx::frame::Style maAttribute;
2241
2242 enum OverlapType { NO_OVERLAP, OVERLAP1, OVERLAP2, OVERLAP3 };
2243
2244public:
2245 SwLineEntry( SwTwips nKey,
2246 SwTwips nStartPos,
2247 SwTwips nEndPos,
2248 const svx::frame::Style& rAttribute );
2249
2250 OverlapType Overlaps( const SwLineEntry& rComp ) const;
2251};
2252
2253}
2254
2255SwLineEntry::SwLineEntry( SwTwips nKey,
2256 SwTwips nStartPos,
2257 SwTwips nEndPos,
2258 const svx::frame::Style& rAttribute )
2259 : mnKey( nKey ),
2260 mnStartPos( nStartPos ),
2261 mnEndPos( nEndPos ),
2262 maAttribute( rAttribute )
2263{
2264}
2265
2266/*
2267
2268 1. ---------- rOld
2269 ---------- rNew
2270
2271 2. ---------- rOld
2272 ------------- rNew
2273
2274 3. ------- rOld
2275 ------------- rNew
2276
2277 4. ------------- rOld
2278 ---------- rNew
2279
2280 5. ---------- rOld
2281 ---- rNew
2282
2283 6. ---------- rOld
2284 ---------- rNew
2285
2286 7. ------------- rOld
2287 ---------- rNew
2288
2289 8. ---------- rOld
2290 ------------- rNew
2291
2292 9. ---------- rOld
2293 ---------- rNew
2294*/
2295
2296SwLineEntry::OverlapType SwLineEntry::Overlaps( const SwLineEntry& rNew ) const
2297{
2298 SwLineEntry::OverlapType eRet = OVERLAP3;
2299
2300 if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos )
2301 eRet = NO_OVERLAP;
2302
2303 // 1, 2, 3
2304 else if ( mnEndPos < rNew.mnEndPos )
2305 eRet = OVERLAP1;
2306
2307 // 4, 5, 6, 7
2308 else if (mnStartPos <= rNew.mnStartPos)
2309 eRet = OVERLAP2;
2310
2311 // 8, 9
2312 return eRet;
2313}
2314
2315namespace {
2316
2317struct lt_SwLineEntry
2318{
2319 bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const
2320 {
2321 return e1.mnStartPos < e2.mnStartPos;
2322 }
2323};
2324
2325}
2326
2327typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet;
2328typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap;
2329
2330namespace {
2331
2332class SwTabFramePainter
2333{
2334 SwLineEntryMap maVertLines;
2335 SwLineEntryMap maHoriLines;
2336 const SwTabFrame& mrTabFrame;
2337
2338 void Insert( SwLineEntry&, bool bHori );
2339 void Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect &rPaintArea);
2340 void HandleFrame(const SwLayoutFrame& rFrame, const SwRect& rPaintArea);
2341 void FindStylesForLine( const Point&,
2342 const Point&,
2343 svx::frame::Style*,
2344 bool bHori ) const;
2345
2346public:
2347 explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
2348
2349 void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const;
2350};
2351
2352}
2353
2354SwTabFramePainter::SwTabFramePainter( const SwTabFrame& rTabFrame )
2355 : mrTabFrame( rTabFrame )
2356{
2357 SwRect aPaintArea = rTabFrame.GetUpper()->GetPaintArea();
2358 HandleFrame(rTabFrame, aPaintArea);
2359}
2360
2361void SwTabFramePainter::HandleFrame(const SwLayoutFrame& rLayoutFrame, const SwRect& rPaintArea)
2362{
2363 // Add border lines of cell frames. Skip covered cells. Skip cells
2364 // in special row span row, which do not have a negative row span:
2365 if ( rLayoutFrame.IsCellFrame() && !rLayoutFrame.IsCoveredCell() )
2366 {
2367 const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rLayoutFrame);
2368 const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pThisCell->GetUpper());
2369 const long nRowSpan = pThisCell->GetTabBox()->getRowSpan();
2370 if ( !pRowFrame->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 )
2371 {
2372 SwBorderAttrAccess aAccess( SwFrame::GetCache(), &rLayoutFrame );
2373 const SwBorderAttrs& rAttrs = *aAccess.Get();
2374 const SvxBoxItem& rBox = rAttrs.GetBox();
2375 Insert(rLayoutFrame, rBox, rPaintArea);
2376 }
2377 }
2378
2379 // Recurse into lower layout frames, but do not recurse into lower tabframes.
2380 const SwFrame* pLower = rLayoutFrame.Lower();
2381 while ( pLower )
2382 {
2383 const SwLayoutFrame* pLowerLayFrame = dynamic_cast<const SwLayoutFrame*>(pLower);
2384 if ( pLowerLayFrame && !pLowerLayFrame->IsTabFrame() )
2385 HandleFrame(*pLowerLayFrame, rPaintArea);
2386
2387 pLower = pLower->GetNext();
2388 }
2389}
2390
2391void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) const
2392{
2393 // #i16816# tagged pdf support
2394 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev );
2395
2396 SwLineEntryMap::const_iterator aIter = maHoriLines.begin();
2397 bool bHori = true;
2398
2399 // color for subsidiary lines:
2400 const Color& rCol( SwViewOption::GetTableBoundariesColor() );
2401
2402 // high contrast mode:
2403 // overrides the color of non-subsidiary lines.
2404 const Color* pHCColor = nullptr;
2405 DrawModeFlags nOldDrawMode = rDev.GetDrawMode();
2406 if( gProp.pSGlobalShell->GetWin() &&
2407 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2408 {
2409 pHCColor = &SwViewOption::GetFontColor();
2410 rDev.SetDrawMode( DrawModeFlags::Default );
2411 }
2412
2413 const SwFrame* pUpper = mrTabFrame.GetUpper();
2414 SwRect aUpper( pUpper->getFramePrintArea() );
2415 aUpper.Pos() += pUpper->getFrameArea().Pos();
2416 SwRect aUpperAligned( aUpper );
2417 ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
2418
2419 // prepare SdrFrameBorderDataVector
2420 std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
2421 std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
2422
2423 while ( true )
2424 {
2425 if ( bHori && aIter == maHoriLines.end() )
2426 {
2427 aIter = maVertLines.begin();
2428 bHori = false;
2429 }
2430
2431 if ( !bHori && aIter == maVertLines.end() )
2432 break;
2433
2434 const SwLineEntrySet& rEntrySet = (*aIter).second;
2435 for (const SwLineEntry& rEntry : rEntrySet)
2436 {
2437 const svx::frame::Style& rEntryStyle( rEntry.maAttribute );
2438
2439 Point aStart, aEnd;
2440 if ( bHori )
2441 {
2442 aStart.setX( rEntry.mnStartPos );
2443 aStart.setY( rEntry.mnKey );
2444 aEnd.setX( rEntry.mnEndPos );
2445 aEnd.setY( rEntry.mnKey );
2446 }
2447 else
2448 {
2449 aStart.setX( rEntry.mnKey );
2450 aStart.setY( rEntry.mnStartPos );
2451 aEnd.setX( rEntry.mnKey );
2452 aEnd.setY( rEntry.mnEndPos );
2453 }
2454
2455 svx::frame::Style aStyles[ 7 ];
2456 aStyles[ 0 ] = rEntryStyle;
2457 FindStylesForLine( aStart, aEnd, aStyles, bHori );
2458 SwRect aRepaintRect( aStart, aEnd );
2459
2460 // the repaint rectangle has to be moved a bit for the centered lines:
2461 SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth();
2462 if ( bHori )
2463 {
2464 aRepaintRect.Height( 2 * nRepaintRectSize );
2465 aRepaintRect.Pos().AdjustY( -nRepaintRectSize );
2466
2467 // To decide on visibility it is also necessary to expand the RepaintRect
2468 // to left/right according existing BorderLine overlap matchings, else there
2469 // will be repaint errors when scrolling in e.t TripleLine BorderLines.
2470 // aStyles[1] == aLFromT, aStyles[3] == aLFromB, aStyles[4] == aRFromT, aStyles[6] == aRFromB
2471 if(aStyles[1].IsUsed() || aStyles[3].IsUsed() || aStyles[4].IsUsed() || aStyles[6].IsUsed())
2472 {
2473 const double fLineWidthMaxLeft(std::max(aStyles[1].GetWidth(), aStyles[3].GetWidth()));
2474 const double fLineWidthMaxRight(std::max(aStyles[4].GetWidth(), aStyles[6].GetWidth()));
2475 aRepaintRect.Width(aRepaintRect.Width() + (fLineWidthMaxLeft + fLineWidthMaxRight));
2476 aRepaintRect.Pos().AdjustX( -fLineWidthMaxLeft );
2477 }
2478 }
2479 else
2480 {
2481 aRepaintRect.Width( 2 * nRepaintRectSize );
2482 aRepaintRect.Pos().AdjustX( -nRepaintRectSize );
2483
2484 // Accordingly to horizontal case, but for top/bottom
2485 // aStyles[3] == aTFromR, aStyles[1] == aTFromL, aStyles[6] == aBFromR, aStyles[4] == aBFromL
2486 if(aStyles[3].IsUsed() || aStyles[1].IsUsed() || aStyles[6].IsUsed() || aStyles[4].IsUsed())
2487 {
2488 const double fLineWidthMaxTop(std::max(aStyles[3].GetWidth(), aStyles[1].GetWidth()));
2489 const double fLineWidthMaxBottom(std::max(aStyles[6].GetWidth(), aStyles[4].GetWidth()));
2490 aRepaintRect.Height(aRepaintRect.Height() + (fLineWidthMaxTop + fLineWidthMaxBottom));
2491 aRepaintRect.Pos().AdjustY( -fLineWidthMaxTop );
2492 }
2493 }
2494
2495 if (!rRect.IsOver(aRepaintRect))
2496 {
2497 continue;
2498 }
2499
2500 // subsidiary lines
2501 const Color* pTmpColor = nullptr;
2502 if (0 == aStyles[ 0 ].GetWidth())
2503 {
2504 if (isTableBoundariesEnabled() && gProp.pSGlobalShell->GetWin())
2505 aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 );
2506 else
2507 aStyles[0].SetType(SvxBorderLineStyle::NONE);
2508 }
2509 else
2510 pTmpColor = pHCColor;
2511
2512 // The (twip) positions will be adjusted to meet these requirements:
2513 // 1. The y coordinates are located in the middle of the pixel grid
2514 // 2. The x coordinated are located at the beginning of the pixel grid
2515 // This is done, because the horizontal lines are painted "at
2516 // beginning", whereas the vertical lines are painted "centered".
2517 // By making the line sizes a multiple of one pixel size, we can
2518 // assure that all lines having the same twip size have the same
2519 // pixel size, independent of their position on the screen.
2520 Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel(aStart) );
2521 Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel(aEnd) );
2522
2523 if (gProp.pSGlobalShell->GetWin())
2524 {
2525 // The table borders do not use SwAlignRect, but all the other frames do.
2526 // Therefore we tweak the outer borders a bit to achieve that the outer
2527 // borders match the subsidiary lines of the upper:
2528 if (aStart.X() == aUpper.Left())
2529 aPaintStart.setX( aUpperAligned.Left() );
2530 else if (aStart.X() == aUpper.Right_())
2531 aPaintStart.setX( aUpperAligned.Right_() );
2532 if (aStart.Y() == aUpper.Top())
2533 aPaintStart.setY( aUpperAligned.Top() );
2534 else if (aStart.Y() == aUpper.Bottom_())
2535 aPaintStart.setY( aUpperAligned.Bottom_() );
2536
2537 if (aEnd.X() == aUpper.Left())
2538 aPaintEnd.setX( aUpperAligned.Left() );
2539 else if (aEnd.X() == aUpper.Right_())
2540 aPaintEnd.setX( aUpperAligned.Right_() );
2541 if (aEnd.Y() == aUpper.Top())
2542 aPaintEnd.setY( aUpperAligned.Top() );
2543 else if (aEnd.Y() == aUpper.Bottom_())
2544 aPaintEnd.setY( aUpperAligned.Bottom_() );
2545 }
2546
2547 if(aStyles[0].IsUsed())
2548 {
2549 if (bHori)
2550 {
2551 const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2552 const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2553
2554 if(!aX.equalZero())
2555 {
2556 const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX));
2557 aData->emplace_back(
2558 aOrigin,
2559 aX,
2560 aStyles[0],
2561 pTmpColor);
2562 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
2563
2564 rInstance.addSdrConnectStyleData(true, aStyles[1], -aY, true); // aLFromT
2565 rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aLFromL
2566 rInstance.addSdrConnectStyleData(true, aStyles[3], aY, false); // aLFromB
2567
2568 rInstance.addSdrConnectStyleData(false, aStyles[4], -aY, true); // aRFromT
2569 rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aRFromR
2570 rInstance.addSdrConnectStyleData(false, aStyles[6], aY, false); // aRFromB
2571 }
2572 }
2573 else // vertical
2574 {
2575 const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
2576 const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
2577
2578 if(!aX.equalZero())
2579 {
2580 const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX));
2581 aData->emplace_back(
2582 aOrigin,
2583 aX,
2584 aStyles[0],
2585 pTmpColor);
2586 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
2587
2588 rInstance.addSdrConnectStyleData(true, aStyles[3], -aY, false); // aTFromR
2589 rInstance.addSdrConnectStyleData(true, aStyles[2], -aX, true); // aTFromT
2590 rInstance.addSdrConnectStyleData(true, aStyles[1], aY, true); // aTFromL
2591
2592 rInstance.addSdrConnectStyleData(false, aStyles[6], -aY, false); // aBFromR
2593 rInstance.addSdrConnectStyleData(false, aStyles[5], aX, false); // aBFromB
2594 rInstance.addSdrConnectStyleData(false, aStyles[4], aY, true); // aBFromL
2595 }
2596 }
2597 }
2598 }
2599 ++aIter;
2600 }
2601
2602 // create instance of SdrFrameBorderPrimitive2D if
2603 // SdrFrameBorderDataVector is used
2604 if(!aData->empty())
2605 {
2606 drawinglayer::primitive2d::Primitive2DContainer aSequence;
2607 aSequence.append(
2608 drawinglayer::primitive2d::Primitive2DReference(
2609 new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
2610 aData,
2611 true))); // force visualization to minimal one discrete unit (pixel)
2612 // paint
2613 mrTabFrame.ProcessPrimitives(aSequence);
2614 }
2615
2616 // restore output device:
2617 rDev.SetDrawMode( nOldDrawMode );
2618}
2619
2620/**
2621 * Finds the lines that join the line defined by (StartPoint, EndPoint) in either
2622 * StartPoint or Endpoint. The styles of these lines are required for DR's magic
2623 * line painting functions
2624 */
2625void SwTabFramePainter::FindStylesForLine( const Point& rStartPoint,
2626 const Point& rEndPoint,
2627 svx::frame::Style* pStyles,
2628 bool bHori ) const
2629{
2630 // pStyles[ 1 ] = bHori ? aLFromT : TFromL
2631 // pStyles[ 2 ] = bHori ? aLFromL : TFromT,
2632 // pStyles[ 3 ] = bHori ? aLFromB : TFromR,
2633 // pStyles[ 4 ] = bHori ? aRFromT : BFromL,
2634 // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
2635 // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
2636
2637 SwLineEntryMap::const_iterator aMapIter = maVertLines.find( rStartPoint.X() );
2638 OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" )do { if (true && (!(aMapIter != maVertLines.end()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2638" ": "), "%s", "FindStylesForLine: Error"); } } while
(false)
;
2639 const SwLineEntrySet& rVertSet = (*aMapIter).second;
2640
2641 for ( const SwLineEntry& rEntry : rVertSet )
2642 {
2643 if ( bHori )
2644 {
2645 if ( rStartPoint.Y() == rEntry.mnStartPos )
2646 pStyles[ 3 ] = rEntry.maAttribute;
2647 else if ( rStartPoint.Y() == rEntry.mnEndPos )
2648 pStyles[ 1 ] = rEntry.maAttribute;
2649 }
2650 else
2651 {
2652 if ( rStartPoint.Y() == rEntry.mnEndPos )
2653 pStyles[ 2 ] = rEntry.maAttribute;
2654 else if ( rEndPoint.Y() == rEntry.mnStartPos )
2655 pStyles[ 5 ] = rEntry.maAttribute;
2656 }
2657 }
2658
2659 aMapIter = maHoriLines.find( rStartPoint.Y() );
2660 OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" )do { if (true && (!(aMapIter != maHoriLines.end()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2660" ": "), "%s", "FindStylesForLine: Error"); } } while
(false)
;
2661 const SwLineEntrySet& rHoriSet = (*aMapIter).second;
2662
2663 for ( const SwLineEntry& rEntry : rHoriSet )
2664 {
2665 if ( bHori )
2666 {
2667 if ( rStartPoint.X() == rEntry.mnEndPos )
2668 pStyles[ 2 ] = rEntry.maAttribute;
2669 else if ( rEndPoint.X() == rEntry.mnStartPos )
2670 pStyles[ 5 ] = rEntry.maAttribute;
2671 }
2672 else
2673 {
2674 if ( rStartPoint.X() == rEntry.mnEndPos )
2675 pStyles[ 1 ] = rEntry.maAttribute;
2676 else if ( rStartPoint.X() == rEntry.mnStartPos )
2677 pStyles[ 3 ] = rEntry.maAttribute;
2678 }
2679 }
2680
2681 if ( bHori )
2682 {
2683 aMapIter = maVertLines.find( rEndPoint.X() );
2684 OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" )do { if (true && (!(aMapIter != maVertLines.end()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2684" ": "), "%s", "FindStylesForLine: Error"); } } while
(false)
;
2685 const SwLineEntrySet& rVertSet2 = (*aMapIter).second;
2686
2687 for ( const SwLineEntry& rEntry : rVertSet2 )
2688 {
2689 if ( rEndPoint.Y() == rEntry.mnStartPos )
2690 pStyles[ 6 ] = rEntry.maAttribute;
2691 else if ( rEndPoint.Y() == rEntry.mnEndPos )
2692 pStyles[ 4 ] = rEntry.maAttribute;
2693 }
2694 }
2695 else
2696 {
2697 aMapIter = maHoriLines.find( rEndPoint.Y() );
2698 OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" )do { if (true && (!(aMapIter != maHoriLines.end()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2698" ": "), "%s", "FindStylesForLine: Error"); } } while
(false)
;
2699 const SwLineEntrySet& rHoriSet2 = (*aMapIter).second;
2700
2701 for ( const SwLineEntry& rEntry : rHoriSet2 )
2702 {
2703 if ( rEndPoint.X() == rEntry.mnEndPos )
2704 pStyles[ 4 ] = rEntry.maAttribute;
2705 else if ( rEndPoint.X() == rEntry.mnStartPos )
2706 pStyles[ 6 ] = rEntry.maAttribute;
2707 }
2708 }
2709}
2710
2711/**
2712 * Special case: #i9860#
2713 * first line in follow table without repeated headlines
2714 */
2715static bool lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
2716 SwTabFrame const& rTabFrame, SwFrame const& rFrame, SvxBoxItem const& rBoxItem)
2717{
2718 SwRowFrame const*const pThisRowFrame =
2719 dynamic_cast<const SwRowFrame*>(rFrame.GetUpper());
2720 return (pThisRowFrame
2721 && (pThisRowFrame->GetUpper() == &rTabFrame)
2722 && rTabFrame.IsFollow()
2723 && !rTabFrame.GetTable()->GetRowsToRepeat()
2724 && ( !pThisRowFrame->GetPrev()
2725 || static_cast<const SwRowFrame*>(pThisRowFrame->GetPrev())
2726 ->IsRowSpanLine())
2727 && !rBoxItem.GetTop()
2728 && rBoxItem.GetBottom());
2729}
2730
2731void SwTabFramePainter::Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const SwRect& rPaintArea)
2732{
2733 // build 4 line entries for the 4 borders:
2734 SwRect aBorderRect = rFrame.getFrameArea();
2735
2736 aBorderRect.Intersection(rPaintArea);
2737
2738 bool const bBottomAsTop(lcl_IsFirstRowInFollowTableWithoutRepeatedHeadlines(
2739 mrTabFrame, rFrame, rBoxItem));
2740 bool const bVert = mrTabFrame.IsVertical();
2741 bool const bR2L = mrTabFrame.IsRightToLeft();
2742
2743 bool bWordTableCell = false;
2744 SwViewShell* pShell = rFrame.getRootFrame()->GetCurrShell();
2745 if (pShell)
2746 {
2747 const IDocumentSettingAccess& rIDSA = pShell->GetDoc()->getIDocumentSettingAccess();
2748 bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
2749 }
2750
2751 // no scaling needed, it's all in the primitives and the target device
2752 svx::frame::Style aL(rBoxItem.GetLeft(), 1.0);
2753 aL.SetWordTableCell(bWordTableCell);
2754 svx::frame::Style aR(rBoxItem.GetRight(), 1.0);
2755 aR.SetWordTableCell(bWordTableCell);
2756 svx::frame::Style aT(rBoxItem.GetTop(), 1.0);
2757 aT.SetWordTableCell(bWordTableCell);
2758 svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
2759 aB.SetWordTableCell(bWordTableCell);
2760
2761 aR.MirrorSelf();
2762 aB.MirrorSelf();
2763
2764 const SwTwips nLeft = aBorderRect.Left_();
2765 const SwTwips nRight = aBorderRect.Right_();
2766 const SwTwips nTop = aBorderRect.Top_();
2767 const SwTwips nBottom = aBorderRect.Bottom_();
2768
2769 aL.SetRefMode( svx::frame::RefMode::Centered );
2770 aR.SetRefMode( svx::frame::RefMode::Centered );
2771 aT.SetRefMode( !bVert ? svx::frame::RefMode::Begin : svx::frame::RefMode::End );
2772 aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : svx::frame::RefMode::End );
2773
2774 SwLineEntry aLeft (nLeft, nTop, nBottom,
2775 bVert ? aB : (bR2L ? aR : aL));
2776 SwLineEntry aRight (nRight, nTop, nBottom,
2777 bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
2778 SwLineEntry aTop (nTop, nLeft, nRight,
2779 bVert ? aL : (bBottomAsTop ? aB : aT));
2780 SwLineEntry aBottom(nBottom, nLeft, nRight,
2781 bVert ? aR : aB);
2782
2783 Insert( aLeft, false );
2784 Insert( aRight, false );
2785 Insert( aTop, true );
2786 Insert( aBottom, true );
2787}
2788
2789void SwTabFramePainter::Insert( SwLineEntry& rNew, bool bHori )
2790{
2791 // get all lines from structure, that have key entry of pLE
2792 SwLineEntryMap* pLine2 = bHori ? &maHoriLines : &maVertLines;
2793 const SwTwips nKey = rNew.mnKey;
2794 SwLineEntryMap::iterator aMapIter = pLine2->find( nKey );
2795
2796 SwLineEntrySet* pLineSet = aMapIter != pLine2->end() ? &((*aMapIter).second) : nullptr;
2797 if ( !pLineSet )
2798 {
2799 SwLineEntrySet aNewSet;
2800 (*pLine2)[ nKey ] = aNewSet;
2801 pLineSet = &(*pLine2)[ nKey ];
2802 }
2803 SwLineEntrySet::iterator aIter = pLineSet->begin();
2804
2805 while ( aIter != pLineSet->end() && rNew.mnStartPos < rNew.mnEndPos )
2806 {
2807 const SwLineEntry& rOld = *aIter;
2808 const SwLineEntry::OverlapType nOverlapType = rOld.Overlaps( rNew );
2809
2810 const svx::frame::Style& rOldAttr = rOld.maAttribute;
2811 const svx::frame::Style& rNewAttr = rNew.maAttribute;
2812 const svx::frame::Style& rCmpAttr = std::max(rNewAttr, rOldAttr);
2813
2814 if ( SwLineEntry::OVERLAP1 == nOverlapType )
2815 {
2816 OSL_ENSURE( rNew.mnStartPos >= rOld.mnStartPos, "Overlap type 3? How this?" )do { if (true && (!(rNew.mnStartPos >= rOld.mnStartPos
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2816" ": "), "%s", "Overlap type 3? How this?"); } } while
(false)
;
2817
2818 // new left segment
2819 const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2820
2821 // new middle segment
2822 const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rOld.mnEndPos, rCmpAttr );
2823
2824 // new right segment
2825 rNew.mnStartPos = rOld.mnEndPos;
2826
2827 // update current lines set
2828 pLineSet->erase( aIter );
2829 if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2830 if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2831
2832 aIter = pLineSet->begin();
2833
2834 continue; // start over
2835 }
2836 else if ( SwLineEntry::OVERLAP2 == nOverlapType )
2837 {
2838 // new left segment
2839 const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr );
2840
2841 // new middle segment
2842 const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rNew.mnEndPos, rCmpAttr );
2843
2844 // new right segment
2845 const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2846
2847 // update current lines set
2848 pLineSet->erase( aIter );
2849 if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2850 if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2851 if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2852
2853 rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2854
2855 break; // we are finished
2856 }
2857 else if ( SwLineEntry::OVERLAP3 == nOverlapType )
2858 {
2859 // new left segment
2860 const SwLineEntry aLeft( nKey, rNew.mnStartPos, rOld.mnStartPos, rNewAttr );
2861
2862 // new middle segment
2863 const SwLineEntry aMiddle( nKey, rOld.mnStartPos, rNew.mnEndPos, rCmpAttr );
2864
2865 // new right segment
2866 const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr );
2867
2868 // update current lines set
2869 pLineSet->erase( aIter );
2870 if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft );
2871 if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle );
2872 if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight );
2873
2874 rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted!
2875
2876 break; // we are finished
2877 }
2878
2879 ++aIter;
2880 }
2881
2882 if ( rNew.mnStartPos < rNew.mnEndPos ) // insert rest
2883 pLineSet->insert( rNew );
2884}
2885
2886/**
2887 * FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES END
2888 * --> OD #i76669#
2889 */
2890namespace
2891{
2892 class SwViewObjectContactRedirector : public sdr::contact::ViewObjectContactRedirector
2893 {
2894 private:
2895 const SwViewShell& mrViewShell;
2896
2897 public:
2898 explicit SwViewObjectContactRedirector( const SwViewShell& rSh )
2899 : mrViewShell( rSh )
2900 {};
2901
2902 virtual drawinglayer::primitive2d::Primitive2DContainer createRedirectedPrimitive2DSequence(
2903 const sdr::contact::ViewObjectContact& rOriginal,
2904 const sdr::contact::DisplayInfo& rDisplayInfo) override
2905 {
2906 bool bPaint( true );
2907
2908 SdrObject* pObj = rOriginal.GetViewContact().TryToGetSdrObject();
2909 if ( pObj )
1
Assuming 'pObj' is non-null
2
Taking true branch
2910 {
2911 bPaint = SwFlyFrame::IsPaint( pObj, &mrViewShell );
3
Calling 'SwFlyFrame::IsPaint'
2912 }
2913
2914 if ( !bPaint )
2915 {
2916 return drawinglayer::primitive2d::Primitive2DContainer();
2917 }
2918
2919 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
2920 rOriginal, rDisplayInfo );
2921 }
2922 };
2923
2924} // end of anonymous namespace
2925// <--
2926
2927/**
2928 * Paint once for every visible page which is touched by Rect
2929 *
2930 * 1. Paint borders and backgrounds
2931 * 2. Paint the draw layer (frames and drawing objects) that is
2932 * below the document (hell)
2933 * 3. Paint the document content (text)
2934 * 4. Paint the draw layer that is above the document
2935|*/
2936void SwRootFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const pPrintData) const
2937{
2938 OSL_ENSURE( Lower() && Lower()->IsPageFrame(), "Lower of root is no page." )do { if (true && (!(Lower() && Lower()->IsPageFrame
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "2938" ": "), "%s", "Lower of root is no page."); } } while
(false)
;
2939
2940 PROTOCOL( this, PROT::FileInit, DbgAction::NONE, nullptr)
2941
2942 bool bResetRootPaint = false;
2943 SwViewShell *pSh = mpCurrShell;
2944
2945 if ( pSh->GetWin() )
2946 {
2947 if ( pSh->GetOut() == pSh->GetWin() && !pSh->GetWin()->IsVisible() )
2948 {
2949 return;
2950 }
2951 if (SwRootFrame::s_isInPaint)
2952 {
2953 SwPaintQueue::Add( pSh, rRect );
2954 return;
2955 }
2956 }
2957 else
2958 SwRootFrame::s_isInPaint = bResetRootPaint = true;
2959
2960 std::unique_ptr<SwSavePaintStatics> pStatics;
2961 if ( gProp.pSGlobalShell )
2962 pStatics.reset(new SwSavePaintStatics());
2963 gProp.pSGlobalShell = pSh;
2964
2965 if( !pSh->GetWin() )
2966 gProp.pSProgress = SfxProgress::GetActiveProgress( static_cast<SfxObjectShell*>(pSh->GetDoc()->GetDocShell()) );
2967
2968 ::SwCalcPixStatics( pSh->GetOut() );
2969 aGlobalRetoucheColor = pSh->Imp()->GetRetoucheColor();
2970
2971 // Copy rRect; for one, rRect could become dangling during the below action, and for another it
2972 // needs to be copied to aRect anyway as that is modified further down below:
2973 SwRect aRect( rRect );
2974
2975 //Trigger an action to clear things up if needed.
2976 //Using this trick we can ensure that all values are valid in all paints -
2977 //no problems, no special case(s).
2978 // #i92745#
2979 // Extend check on certain states of the 'current' <SwViewShell> instance to
2980 // all existing <SwViewShell> instances.
2981 bool bPerformLayoutAction( true );
2982 {
2983 for(SwViewShell& rTmpViewShell : pSh->GetRingContainer())
2984 {
2985 if ( rTmpViewShell.IsInEndAction() ||
2986 rTmpViewShell.IsPaintInProgress() ||
2987 ( rTmpViewShell.Imp()->IsAction() &&
2988 rTmpViewShell.Imp()->GetLayAction().IsActionInProgress() ) )
2989 {
2990 bPerformLayoutAction = false;
2991 }
2992
2993 if(!bPerformLayoutAction)
2994 break;
2995 }
2996 }
2997 if ( bPerformLayoutAction )
2998 {
2999 const_cast<SwRootFrame*>(this)->ResetTurbo();
3000 SwLayAction aAction( const_cast<SwRootFrame*>(this), pSh->Imp() );
3001 aAction.SetPaint( false );
3002 aAction.SetComplete( false );
3003 aAction.SetReschedule( gProp.pSProgress != nullptr );
3004 aAction.Action(&rRenderContext);
3005 ResetTurboFlag();
3006 if ( !pSh->ActionPend() )
3007 pSh->Imp()->DelRegion();
3008 }
3009
3010 aRect.Intersection( pSh->VisArea() );
3011
3012 const bool bExtraData = ::IsExtraData( GetFormat()->GetDoc() );
3013
3014 gProp.pSLines.reset(new SwLineRects); // Container for borders.
3015
3016 // #104289#. During painting, something (OLE) can
3017 // load the linguistic, which in turn can cause a reformat
3018 // of the document. Dangerous! We better set this flag to
3019 // avoid the reformat.
3020 const bool bOldAction = IsCallbackActionEnabled();
3021 const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( false );
3022
3023 const SwPageFrame *pPage = pSh->Imp()->GetFirstVisPage(&rRenderContext);
3024
3025 // #126222. The positions of headers and footers of the previous
3026 // pages have to be updated, else these headers and footers could
3027 // get visible at a wrong position.
3028 const SwPageFrame *pPageDeco = static_cast<const SwPageFrame*>(pPage->GetPrev());
3029 while (pPageDeco)
3030 {
3031 pPageDeco->PaintDecorators();
3032 OSL_ENSURE(!pPageDeco->GetPrev() || pPageDeco->GetPrev()->IsPageFrame(),do { if (true && (!(!pPageDeco->GetPrev() || pPageDeco
->GetPrev()->IsPageFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "3033" ": "), "%s", "Neighbour of page is not a page.");
} } while (false)
3033 "Neighbour of page is not a page.")do { if (true && (!(!pPageDeco->GetPrev() || pPageDeco
->GetPrev()->IsPageFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "3033" ": "), "%s", "Neighbour of page is not a page.");
} } while (false)
;
3034 pPageDeco = static_cast<const SwPageFrame*>(pPageDeco->GetPrev());
3035 }
3036
3037 const bool bBookMode = gProp.pSGlobalShell->GetViewOptions()->IsViewLayoutBookMode();
3038 if ( bBookMode && pPage->GetPrev() && static_cast<const SwPageFrame*>(pPage->GetPrev())->IsEmptyPage() )
3039 pPage = static_cast<const SwPageFrame*>(pPage->GetPrev());
3040
3041 // #i68597#
3042 const bool bGridPainting(pSh->GetWin() && pSh->Imp()->HasDrawView() && pSh->Imp()->GetDrawView()->IsGridVisible());
3043
3044 // Hide all page break controls before showing them again
3045 SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3046 if ( pWrtSh )
3047 {
3048 SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3049 SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3050 const SwPageFrame* pHiddenPage = pPage;
3051 while ( pHiddenPage->GetPrev() != nullptr )
3052 {
3053 pHiddenPage = static_cast< const SwPageFrame* >( pHiddenPage->GetPrev() );
3054 SwFrameControlPtr pControl = rMngr.GetControl( FrameControlType::PageBreak, pHiddenPage );
3055 if ( pControl )
3056 pControl->ShowAll( false );
3057 }
3058 }
3059
3060 // #i76669#
3061 SwViewObjectContactRedirector aSwRedirector( *pSh );
3062
3063 while ( pPage )
3064 {
3065 const bool bPaintRightShadow = pPage->IsRightShadowNeeded();
3066 const bool bPaintLeftShadow = pPage->IsLeftShadowNeeded();
3067 const bool bRightSidebar = pPage->SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT;
3068
3069 if ( !pPage->IsEmptyPage() )
3070 {
3071 SwRect aPaintRect;
3072 SwPageFrame::GetBorderAndShadowBoundRect( pPage->getFrameArea(), pSh, &rRenderContext, aPaintRect,
3073 bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3074
3075 if ( aRect.IsOver( aPaintRect ) )
3076 {
3077 if ( pSh->GetWin() )
3078 {
3079 gProp.pSSubsLines.reset(new SwSubsRects);
3080 gProp.pSSpecSubsLines.reset(new SwSubsRects);
3081 }
3082 gProp.pBLines.reset(new BorderLines);
3083
3084 aPaintRect.Intersection_( aRect );
3085
3086 if ( bExtraData &&
3087 pSh->GetWin() && pSh->IsInEndAction() )
3088 {
3089 // enlarge paint rectangle to complete page width, subtract
3090 // current paint area and invalidate the resulting region.
3091 SwRectFnSet aRectFnSet(pPage);
3092 SwRect aPageRectTemp( aPaintRect );
3093 aRectFnSet.SetLeftAndWidth( aPageRectTemp,
3094 aRectFnSet.GetLeft(pPage->getFrameArea()),
3095 aRectFnSet.GetWidth(pPage->getFrameArea()) );
3096 aPageRectTemp.Intersection_( pSh->VisArea() );
3097 vcl::Region aPageRectRegion( aPageRectTemp.SVRect() );
3098 aPageRectRegion.Exclude( aPaintRect.SVRect() );
3099 pSh->GetWin()->Invalidate( aPageRectRegion, InvalidateFlags::Children );
3100 }
3101
3102 // #i80793#
3103 // enlarge paint rectangle for objects overlapping the same pixel
3104 // in all cases and before the DrawingLayer overlay is initialized.
3105 lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3106
3107 // #i68597#
3108 // moved paint pre-process for DrawingLayer overlay here since the above
3109 // code dependent from bExtraData may expand the PaintRect
3110 {
3111 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3112 // really be used but handled by SwViewShell::ImplEndAction already
3113 const vcl::Region aDLRegion(aPaintRect.SVRect());
3114 pSh->DLPrePaint2(aDLRegion);
3115 }
3116
3117 if(OUTDEV_WINDOW == gProp.pSGlobalShell->GetOut()->GetOutDevType())
3118 {
3119 // changed method SwLayVout::Enter(..)
3120 // 2nd parameter is no longer <const> and will be set to the
3121 // rectangle the virtual output device is calculated from <aPaintRect>,
3122 // if the virtual output is used.
3123 s_pVout->Enter(pSh, aPaintRect, !s_isNoVirDev);
3124
3125 // Adjust paint rectangle to pixel size
3126 // Thus, all objects overlapping on pixel level with the unadjusted
3127 // paint rectangle will be considered in the paint.
3128 lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) );
3129 }
3130
3131 // maybe this can be put in the above scope. Since we are not sure, just leave it ATM
3132 s_pVout->SetOrgRect( aPaintRect );
3133
3134 // determine background color of page for <PaintLayer> method
3135 // calls, paint <hell> or <heaven>
3136 const Color aPageBackgrdColor(pPage->GetDrawBackgrdColor());
3137
3138 pPage->PaintBaBo( aPaintRect, pPage );
3139
3140 if ( pSh->Imp()->HasDrawView() )
3141 {
3142 gProp.pSLines->LockLines( true );
3143 const IDocumentDrawModelAccess& rIDDMA = pSh->getIDocumentDrawModelAccess();
3144 pSh->Imp()->PaintLayer( rIDDMA.GetHellId(),
3145 pPrintData,
3146 *pPage, pPage->getFrameArea(),
3147 &aPageBackgrdColor,
3148 pPage->IsRightToLeft(),
3149 &aSwRedirector );
3150 gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3151 gProp.pSLines->LockLines( false );
3152 }
3153
3154 if ( pSh->GetDoc()->GetDocumentSettingManager().get( DocumentSettingId::BACKGROUND_PARA_OVER_DRAWINGS ) )
3155 pPage->PaintBaBo( aPaintRect, pPage, /*bOnlyTextBackground=*/true );
3156
3157 if( pSh->GetWin() )
3158 {
3159 // collect sub-lines
3160 pPage->RefreshSubsidiary( aPaintRect );
3161 // paint special sub-lines
3162 gProp.pSSpecSubsLines->PaintSubsidiary( pSh->GetOut(), nullptr, gProp );
3163 }
3164
3165 pPage->PaintSwFrame( rRenderContext, aPaintRect );
3166
3167 // no paint of page border and shadow, if writer is in place mode.
3168 if( pSh->GetWin() && pSh->GetDoc()->GetDocShell() &&
3169 !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3170 {
3171 SwPageFrame::PaintBorderAndShadow( pPage->getFrameArea(), pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3172 SwPageFrame::PaintNotesSidebar( pPage->getFrameArea(), pSh, pPage->GetPhyPageNum(), bRightSidebar);
3173 }
3174
3175 gProp.pSLines->PaintLines( pSh->GetOut(), gProp );
3176 if ( pSh->GetWin() )
3177 {
3178 gProp.pSSubsLines->PaintSubsidiary( pSh->GetOut(), gProp.pSLines.get(), gProp );
3179 gProp.pSSubsLines.reset();
3180 gProp.pSSpecSubsLines.reset();
3181 }
3182 // fdo#42750: delay painting these until after subsidiary lines
3183 // fdo#45562: delay painting these until after hell layer
3184 // fdo#47717: but do it before heaven layer
3185 ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
3186
3187 if ( pSh->Imp()->HasDrawView() )
3188 {
3189 pSh->Imp()->PaintLayer( pSh->GetDoc()->getIDocumentDrawModelAccess().GetHeavenId(),
3190 pPrintData,
3191 *pPage, pPage->getFrameArea(),
3192 &aPageBackgrdColor,
3193 pPage->IsRightToLeft(),
3194 &aSwRedirector );
3195 }
3196
3197 if ( bExtraData )
3198 pPage->RefreshExtraData( aPaintRect );
3199
3200 gProp.pBLines.reset();
3201 s_pVout->Leave();
3202
3203 // #i68597#
3204 // needed to move grid painting inside Begin/EndDrawLayer bounds and to change
3205 // output rect for it accordingly
3206 if(bGridPainting)
3207 {
3208 SdrPaintView* pPaintView = pSh->Imp()->GetDrawView();
3209 SdrPageView* pPageView = pPaintView->GetSdrPageView();
3210 pPageView->DrawPageViewGrid(*pSh->GetOut(), aPaintRect.SVRect(), SwViewOption::GetTextGridColor() );
3211 }
3212
3213 // #i68597#
3214 // moved paint post-process for DrawingLayer overlay here, see above
3215 {
3216 pSh->DLPostPaint2(true);
3217 }
3218 }
3219
3220 pPage->PaintDecorators( );
3221 pPage->PaintBreak();
3222 }
3223 else if ( bBookMode && pSh->GetWin() && !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() )
3224 {
3225 // paint empty page
3226 SwRect aPaintRect;
3227 SwRect aEmptyPageRect( pPage->getFrameArea() );
3228
3229 // code from vprint.cxx
3230 const SwPageFrame& rFormatPage = pPage->GetFormatPage();
3231 aEmptyPageRect.SSize( rFormatPage.getFrameArea().SSize() );
3232
3233 SwPageFrame::GetBorderAndShadowBoundRect( aEmptyPageRect, pSh, &rRenderContext, aPaintRect,
3234 bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3235 aPaintRect.Intersection_( aRect );
3236
3237 if ( aRect.IsOver( aEmptyPageRect ) )
3238 {
3239 // #i75172# if called from SwViewShell::ImplEndAction it should no longer
3240 // really be used but handled by SwViewShell::ImplEndAction already
3241 {
3242 const vcl::Region aDLRegion(aPaintRect.SVRect());
3243 pSh->DLPrePaint2(aDLRegion);
3244 }
3245
3246 if( pSh->GetOut()->GetFillColor() != aGlobalRetoucheColor )
3247 pSh->GetOut()->SetFillColor( aGlobalRetoucheColor );
3248 // No line color
3249 pSh->GetOut()->SetLineColor();
3250 // Use aligned page rectangle
3251 {
3252 SwRect aTmpPageRect( aEmptyPageRect );
3253 ::SwAlignRect( aTmpPageRect, pSh, &rRenderContext );
3254 aEmptyPageRect = aTmpPageRect;
3255 }
3256
3257 pSh->GetOut()->DrawRect( aEmptyPageRect.SVRect() );
3258
3259 // paint empty page text
3260 const vcl::Font& rEmptyPageFont = SwPageFrame::GetEmptyPageFont();
3261 const vcl::Font aOldFont( pSh->GetOut()->GetFont() );
3262
3263 pSh->GetOut()->SetFont( rEmptyPageFont );
3264 pSh->GetOut()->DrawText( aEmptyPageRect.SVRect(), SwResId( STR_EMPTYPAGEreinterpret_cast<char const *>("STR_EMPTYPAGE" "\004" u8"blank page"
)
),
3265 DrawTextFlags::VCenter |
3266 DrawTextFlags::Center |
3267 DrawTextFlags::Clip );
3268
3269 pSh->GetOut()->SetFont( aOldFont );
3270 // paint shadow and border for empty page
3271 SwPageFrame::PaintBorderAndShadow( aEmptyPageRect, pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
3272 SwPageFrame::PaintNotesSidebar( aEmptyPageRect, pSh, pPage->GetPhyPageNum(), bRightSidebar);
3273
3274 {
3275 pSh->DLPostPaint2(true);
3276 }
3277 }
3278 }
3279
3280 OSL_ENSURE( !pPage->GetNext() || pPage->GetNext()->IsPageFrame(),do { if (true && (!(!pPage->GetNext() || pPage->
GetNext()->IsPageFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "3281" ": "), "%s", "Neighbour of page is not a page.");
} } while (false)
3281 "Neighbour of page is not a page." )do { if (true && (!(!pPage->GetNext() || pPage->
GetNext()->IsPageFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "3281" ": "), "%s", "Neighbour of page is not a page.");
} } while (false)
;
3282 pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
3283 }
3284
3285 gProp.pSLines.reset();
3286
3287 if ( bResetRootPaint )
3288 SwRootFrame::s_isInPaint = false;
3289 if ( pStatics )
3290 pStatics.reset();
3291 else
3292 {
3293 gProp.pSProgress = nullptr;
3294 gProp.pSGlobalShell = nullptr;
3295 }
3296
3297 const_cast<SwRootFrame*>(this)->SetCallbackActionEnabled( bOldAction );
3298}
3299
3300static void lcl_EmergencyFormatFootnoteCont( SwFootnoteContFrame *pCont )
3301{
3302 vcl::RenderContext* pRenderContext = pCont->getRootFrame()->GetCurrShell()->GetOut();
3303
3304 //It's possible that the Cont will get destroyed.
3305 SwContentFrame *pCnt = pCont->ContainsContent();
3306 while ( pCnt && pCnt->IsInFootnote() )
3307 {
3308 pCnt->Calc(pRenderContext);
3309 pCnt = pCnt->GetNextContentFrame();
3310 }
3311}
3312
3313namespace {
3314
3315class SwShortCut
3316{
3317 SwRectDist fnCheck;
3318 long nLimit;
3319public:
3320 SwShortCut( const SwFrame& rFrame, const SwRect& rRect );
3321 bool Stop( const SwRect& rRect ) const
3322 { return (rRect.*fnCheck)( nLimit ) > 0; }
3323};
3324
3325}
3326
3327SwShortCut::SwShortCut( const SwFrame& rFrame, const SwRect& rRect )
3328{
3329 bool bVert = rFrame.IsVertical();
3330 bool bR2L = rFrame.IsRightToLeft();
3331 if( rFrame.IsNeighbourFrame() && bVert == bR2L )
3332 {
3333 if( bVert )
3334 {
3335 fnCheck = &SwRect::GetBottomDistance;
3336 nLimit = rRect.Top();
3337 }
3338 else
3339 {
3340 fnCheck = &SwRect::GetLeftDistance;
3341 nLimit = rRect.Left() + rRect.Width();
3342 }
3343 }
3344 else if( bVert == rFrame.IsNeighbourFrame() )
3345 {
3346 fnCheck = &SwRect::GetTopDistance;
3347 nLimit = rRect.Top() + rRect.Height();
3348 }
3349 else
3350 {
3351 if ( rFrame.IsVertLR() )
3352 {
3353 fnCheck = &SwRect::GetLeftDistance;
3354 nLimit = rRect.Right();
3355 }
3356 else
3357 {
3358 fnCheck = &SwRect::GetRightDistance;
3359 nLimit = rRect.Left();
3360 }
3361 }
3362}
3363
3364void SwLayoutFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3365{
3366 // #i16816# tagged pdf support
3367 Frame_Info aFrameInfo( *this );
3368 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, &aFrameInfo, nullptr, rRenderContext );
3369
3370 const SwFrame *pFrame = Lower();
3371 if ( !pFrame )
3372 return;
3373
3374 SwFrameDeleteGuard g(const_cast<SwLayoutFrame*>(this)); // lock because Calc() and recursion
3375 SwShortCut aShortCut( *pFrame, rRect );
3376 bool bCnt = pFrame->IsContentFrame();
3377 if ( bCnt )
3378 pFrame->Calc(&rRenderContext);
3379
3380 if ( pFrame->IsFootnoteContFrame() )
3381 {
3382 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame)) );
3383 pFrame = Lower();
3384 }
3385
3386 const SwPageFrame *pPage = nullptr;
3387 bool bWin = gProp.pSGlobalShell->GetWin() != nullptr;
3388 if (comphelper::LibreOfficeKit::isTiledPainting())
3389 // Tiled rendering is similar to printing in this case: painting transparently multiple
3390 // times will result in darker colors: avoid that.
3391 bWin = false;
3392
3393 while ( IsAnLower( pFrame ) )
3394 {
3395 SwRect aPaintRect( pFrame->GetPaintArea() );
3396 if( aShortCut.Stop( aPaintRect ) )
3397 break;
3398 if ( bCnt && gProp.pSProgress )
3399 SfxProgress::Reschedule();
3400
3401 //We need to retouch if a frame explicitly requests it.
3402 //First do the retouch, because this could flatten the borders.
3403 if ( pFrame->IsRetouche() )
3404 {
3405 if ( pFrame->IsRetoucheFrame() && bWin && !pFrame->GetNext() )
3406 {
3407 if ( !pPage )
3408 pPage = FindPageFrame();
3409 pFrame->Retouch( pPage, rRect );
3410 }
3411 pFrame->ResetRetouche();
3412 }
3413
3414 if ( rRect.IsOver( aPaintRect ) )
3415 {
3416 if ( bCnt && pFrame->IsCompletePaint() &&
3417 !rRect.IsInside( aPaintRect ) && Application::AnyInput( VclInputFlags::KEYBOARD ) )
3418 {
3419 //fix(8104): It may happen, that the processing wasn't complete
3420 //but some parts of the paragraph were still repainted.
3421 //This could lead to the situation, that other parts of the
3422 //paragraph won't be repainted at all. The only solution seems
3423 //to be an invalidation of the window.
3424 //To not make it too severe the rectangle is limited by
3425 //painting the desired part and only invalidating the
3426 //remaining paragraph parts.
3427 if ( aPaintRect.Left() == rRect.Left() &&
3428 aPaintRect.Right() == rRect.Right() )
3429 {
3430 aPaintRect.Bottom( rRect.Top() - 1 );
3431 if ( aPaintRect.Height() > 0 )
3432 gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3433 aPaintRect.Top( rRect.Bottom() + 1 );
3434 aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3435 if ( aPaintRect.Height() > 0 )
3436 gProp.pSGlobalShell->InvalidateWindows(aPaintRect);
3437 aPaintRect.Top( pFrame->getFrameArea().Top() );
3438 aPaintRect.Bottom( pFrame->getFrameArea().Bottom() );
3439 }
3440 else
3441 {
3442 gProp.pSGlobalShell->InvalidateWindows( aPaintRect );
3443 pFrame = pFrame->GetNext();
3444 if ( pFrame )
3445 {
3446 bCnt = pFrame->IsContentFrame();
3447 if ( bCnt )
3448 pFrame->Calc(&rRenderContext);
3449 }
3450 continue;
3451 }
3452 }
3453 pFrame->ResetCompletePaint();
3454 aPaintRect.Intersection_( rRect );
3455
3456 pFrame->PaintSwFrame( rRenderContext, aPaintRect );
3457
3458 if ( Lower() && Lower()->IsColumnFrame() )
3459 {
3460 //Paint the column separator line if needed. The page is
3461 //responsible for the page frame - not the upper.
3462 const SwFrameFormat *pFormat = GetUpper() && GetUpper()->IsPageFrame()
3463 ? GetUpper()->GetFormat()
3464 : GetFormat();
3465 const SwFormatCol &rCol = pFormat->GetCol();
3466 if ( rCol.GetLineAdj() != COLADJ_NONE )
3467 {
3468 if ( !pPage )
3469 pPage = pFrame->FindPageFrame();
3470
3471 PaintColLines( aPaintRect, rCol, pPage );
3472 }
3473 }
3474 }
3475 if ( !bCnt && pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame() )
3476 ::lcl_EmergencyFormatFootnoteCont( const_cast<SwFootnoteContFrame*>(static_cast<const SwFootnoteContFrame*>(pFrame->GetNext())) );
3477
3478 pFrame = pFrame->GetNext();
3479
3480 if ( pFrame )
3481 {
3482 bCnt = pFrame->IsContentFrame();
3483 if ( bCnt )
3484 pFrame->Calc(&rRenderContext);
3485 }
3486 }
3487}
3488
3489static drawinglayer::primitive2d::Primitive2DContainer lcl_CreateDashedIndicatorPrimitive(
3490 const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
3491 basegfx::BColor aColor )
3492{
3493 drawinglayer::primitive2d::Primitive2DContainer aSeq( 1 );
3494
3495 std::vector< double > aStrokePattern;
3496 basegfx::B2DPolygon aLinePolygon;
3497 aLinePolygon.append(rStart);
3498 aLinePolygon.append(rEnd);
3499
3500 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
3501 if ( rSettings.GetHighContrastMode( ) )
3502 {
3503 // Only a solid line in high contrast mode
3504 aColor = rSettings.GetDialogTextColor().getBColor();
3505 }
3506 else
3507 {
3508 // Get a color for the contrast
3509 basegfx::BColor aHslLine = basegfx::utils::rgb2hsl( aColor );
3510 double nLuminance = aHslLine.getZ() * 2.5;
3511 if ( nLuminance == 0 )
3512 nLuminance = 0.5;
3513 else if ( nLuminance >= 1.0 )
3514 nLuminance = aHslLine.getZ() * 0.4;
3515 aHslLine.setZ( nLuminance );
3516 const basegfx::BColor aOtherColor = basegfx::utils::hsl2rgb( aHslLine );
3517
3518 // Compute the plain line
3519 drawinglayer::primitive2d::PolygonHairlinePrimitive2D * pPlainLine =
3520 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
3521 aLinePolygon, aOtherColor );
3522
3523 aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( pPlainLine );
3524
3525 // Dashed line in twips
3526 aStrokePattern.push_back( 40 );
3527 aStrokePattern.push_back( 40 );
3528
3529 aSeq.resize( 2 );
3530 }
3531
3532 // Compute the dashed line primitive
3533 drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D * pLine =
3534 new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D (
3535 basegfx::B2DPolyPolygon( aLinePolygon ),
3536 drawinglayer::attribute::LineAttribute( aColor ),
3537 drawinglayer::attribute::StrokeAttribute( aStrokePattern ) );
3538
3539 aSeq[ aSeq.size( ) - 1 ] = drawinglayer::primitive2d::Primitive2DReference( pLine );
3540
3541 return aSeq;
3542}
3543
3544void SwPageFrame::PaintBreak( ) const
3545{
3546 if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
3547 gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() ||
3548 gProp.pSGlobalShell->GetViewOptions()->IsReadonly() ||
3549 gProp.pSGlobalShell->IsPreview() )
3550 return;
3551
3552 const SwFrame* pBodyFrame = Lower();
3553 while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3554 pBodyFrame = pBodyFrame->GetNext();
3555
3556 if ( pBodyFrame )
3557 {
3558 const SwLayoutFrame* pLayBody = static_cast< const SwLayoutFrame* >( pBodyFrame );
3559 const SwFlowFrame *pFlowFrame = pLayBody->ContainsContent();
3560
3561 // Test if the first node is a table
3562 const SwFrame* pFirstFrame = pLayBody->Lower();
3563 if ( pFirstFrame && pFirstFrame->IsTabFrame() )
3564 pFlowFrame = static_cast< const SwTabFrame* >( pFirstFrame );
3565
3566 SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3567 if ( pWrtSh )
3568 {
3569 SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3570 SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
3571
3572 if ( pFlowFrame && pFlowFrame->IsPageBreak( true ) )
3573 rMngr.SetPageBreakControl( this );
3574 else
3575 rMngr.RemoveControlsByType( FrameControlType::PageBreak, this );
3576 }
3577 }
3578 SwLayoutFrame::PaintBreak( );
3579}
3580
3581void SwColumnFrame::PaintBreak( ) const
3582{
3583 if ( gProp.pSGlobalShell->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
3584 gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() ||
3585 gProp.pSGlobalShell->GetViewOptions()->IsReadonly() ||
3586 gProp.pSGlobalShell->IsPreview() )
3587 return;
3588
3589 const SwFrame* pBodyFrame = Lower();
3590 while ( pBodyFrame && !pBodyFrame->IsBodyFrame() )
3591 pBodyFrame = pBodyFrame->GetNext();
3592
3593 if ( !pBodyFrame )
3594 return;
3595
3596 const SwContentFrame *pCnt = static_cast< const SwLayoutFrame* >( pBodyFrame )->ContainsContent();
3597 if ( !(pCnt && pCnt->IsColBreak( true )) )
3598 return;
3599
3600 // Paint the break only if:
3601 // * Not in header footer edition, to avoid conflicts with the
3602 // header/footer marker
3603 // * Non-printing characters are shown, as this is more consistent
3604 // with other formatting marks
3605 if ( !(!gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) &&
3606 !gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) &&
3607 gProp.pSGlobalShell->GetViewOptions()->IsLineBreak()) )
3608 return;
3609
3610 SwRect aRect( pCnt->getFramePrintArea() );
3611 aRect.Pos() += pCnt->getFrameArea().Pos();
3612
3613 // Draw the line
3614 basegfx::B2DPoint aStart( double( aRect.Left() ), aRect.Top() );
3615 basegfx::B2DPoint aEnd( double( aRect.Right() ), aRect.Top() );
3616 double nWidth = aRect.Width();
3617 if ( IsVertical( ) )
3618 {
3619 aStart = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Top() ) );
3620 aEnd = basegfx::B2DPoint( double( aRect.Right() ), double( aRect.Bottom() ) );
3621 nWidth = aRect.Height();
3622 }
3623
3624 basegfx::BColor aLineColor = SwViewOption::GetPageBreakColor().getBColor();
3625
3626 drawinglayer::primitive2d::Primitive2DContainer aSeq =
3627 lcl_CreateDashedIndicatorPrimitive( aStart, aEnd, aLineColor );
3628
3629 // Add the text above
3630 OUString aBreakText = SwResId(STR_COLUMN_BREAKreinterpret_cast<char const *>("STR_COLUMN_BREAK" "\004"
u8"Manual Column Break")
);
3631
3632 basegfx::B2DVector aFontSize;
3633 OutputDevice* pOut = gProp.pSGlobalShell->GetOut();
3634 vcl::Font aFont = pOut->GetSettings().GetStyleSettings().GetToolFont();
3635 aFont.SetFontHeight( 8 * 20 );
3636 pOut->SetFont( aFont );
3637 drawinglayer::attribute::FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(
3638 aFontSize, aFont, IsRightToLeft(), false );
3639
3640 tools::Rectangle aTextRect;
3641 pOut->GetTextBoundRect( aTextRect, aBreakText );
3642 long nTextOff = ( nWidth - aTextRect.GetWidth() ) / 2;
3643
3644 basegfx::B2DHomMatrix aTextMatrix( basegfx::utils::createScaleTranslateB2DHomMatrix(
3645 aFontSize.getX(), aFontSize.getY(),
3646 aRect.Left() + nTextOff, aRect.Top() ) );
3647 if ( IsVertical() )
3648 {
3649 aTextMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix (
3650 aFontSize.getX(), aFontSize.getY(), 0.0, M_PI_21.57079632679489661923,
3651 aRect.Right(), aRect.Top() + nTextOff );
3652 }
3653
3654 drawinglayer::primitive2d::TextSimplePortionPrimitive2D * pText =
3655 new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
3656 aTextMatrix,
3657 aBreakText, 0, aBreakText.getLength(),
3658 std::vector< double >(),
3659 aFontAttr,
3660 lang::Locale(),
3661 aLineColor );
3662 aSeq.push_back( drawinglayer::primitive2d::Primitive2DReference( pText ) );
3663
3664 ProcessPrimitives( aSeq );
3665}
3666
3667void SwLayoutFrame::PaintBreak( ) const
3668{
3669 const SwFrame* pFrame = Lower();
3670 while ( pFrame )
3671 {
3672 if ( pFrame->IsLayoutFrame() )
3673 static_cast< const SwLayoutFrame*>( pFrame )->PaintBreak( );
3674 pFrame = pFrame->GetNext();
3675 }
3676}
3677
3678void SwPageFrame::PaintDecorators( ) const
3679{
3680 SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
3681 if ( !pWrtSh )
3682 return;
3683
3684 SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
3685
3686 const SwLayoutFrame* pBody = FindBodyCont();
3687 if ( !pBody )
3688 return;
3689
3690 SwRect aBodyRect( pBody->getFrameArea() );
3691
3692 if ( !(gProp.pSGlobalShell->GetOut()->GetOutDevType() != OUTDEV_PRINTER &&
3693 !gProp.pSGlobalShell->GetViewOptions()->IsPDFExport() &&
3694 !gProp.pSGlobalShell->IsPreview() &&
3695 !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() &&
3696 !gProp.pSGlobalShell->GetViewOptions()->getBrowseMode() &&
3697 ( gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) ||
3698 gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) )) )
3699 return;
3700
3701 bool bRtl = AllSettings::GetLayoutRTL();
3702 const SwRect& rVisArea = gProp.pSGlobalShell->VisArea();
3703 long nXOff = std::min( aBodyRect.Right(), rVisArea.Right() );
3704 if ( bRtl )
3705 nXOff = std::max( aBodyRect.Left(), rVisArea.Left() );
3706
3707 // Header
3708 if ( gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Header ) )
3709 {
3710 const SwFrame* pHeaderFrame = Lower();
3711 if ( !pHeaderFrame->IsHeaderFrame() )
3712 pHeaderFrame = nullptr;
3713
3714 long nHeaderYOff = aBodyRect.Top();
3715 Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nHeaderYOff ) );
3716 rEditWin.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Header, nOutputOff );
3717 }
3718
3719 // Footer
3720 if ( !gProp.pSGlobalShell->IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
3721 return;
3722
3723 const SwFrame* pFootnoteContFrame = Lower();
3724 while ( pFootnoteContFrame )
3725 {
3726 if ( pFootnoteContFrame->IsFootnoteContFrame() )
3727 aBodyRect.AddBottom( pFootnoteContFrame->getFrameArea().Bottom() - aBodyRect.Bottom() );
3728 pFootnoteContFrame = pFootnoteContFrame->GetNext();
3729 }
3730
3731 long nFooterYOff = aBodyRect.Bottom();
3732 Point nOutputOff = rEditWin.LogicToPixel( Point( nXOff, nFooterYOff ) );
3733 rEditWin.GetFrameControlsManager().SetHeaderFooterControl( this, FrameControlType::Footer, nOutputOff );
3734}
3735
3736/**
3737 * For feature #99657#
3738 *
3739 * OD 12.08.2002
3740 * determines, if background of fly frame has to be drawn transparent
3741 * declaration found in /core/inc/flyfrm.cxx
3742 *
3743 * OD 08.10.2002 #103898# - If the background of the fly frame itself is not
3744 * transparent and the background is inherited from its parent/grandparent,
3745 * the background brush, used for drawing, has to be investigated for transparency.
3746 *
3747 * @return true, if background is transparent drawn
3748*/
3749bool SwFlyFrame::IsBackgroundTransparent() const
3750{
3751 bool bBackgroundTransparent = GetFormat()->IsBackgroundTransparent();
3752 if ( !bBackgroundTransparent &&
3753 GetFormat()->IsBackgroundBrushInherited() )
3754 {
3755 const SvxBrushItem* pBackgrdBrush = nullptr;
3756 const Color* pSectionTOXColor = nullptr;
3757 SwRect aDummyRect;
3758 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
3759
3760 if ( GetBackgroundBrush( aFillAttributes, pBackgrdBrush, pSectionTOXColor, aDummyRect, false, /*bConsiderTextBox=*/false) )
3761 {
3762 if ( pSectionTOXColor &&
3763 (pSectionTOXColor->GetTransparency() != 0) &&
3764 (*pSectionTOXColor != COL_TRANSPARENT) )
3765 {
3766 bBackgroundTransparent = true;
3767 }
3768 else if(aFillAttributes && aFillAttributes->isUsed())
3769 {
3770 bBackgroundTransparent = aFillAttributes->isTransparent();
3771 }
3772 else if ( pBackgrdBrush )
3773 {
3774 if ( (pBackgrdBrush->GetColor().GetTransparency() != 0) &&
3775 (pBackgrdBrush->GetColor() != COL_TRANSPARENT) )
3776 {
3777 bBackgroundTransparent = true;
3778 }
3779 else
3780 {
3781 const GraphicObject *pTmpGrf =
3782 pBackgrdBrush->GetGraphicObject();
3783 if ( pTmpGrf &&
3784 (pTmpGrf->GetAttr().GetTransparency() != 0)
3785 )
3786 {
3787 bBackgroundTransparent = true;
3788 }
3789 }
3790 }
3791 }
3792 }
3793
3794 return bBackgroundTransparent;
3795};
3796
3797bool SwFlyFrame::IsPaint( SdrObject *pObj, const SwViewShell *pSh )
3798{
3799 SdrObjUserCall *pUserCall = GetUserCall(pObj);
3800
3801 if ( nullptr == pUserCall )
4
Assuming the condition is false
5
Taking false branch
30
Assuming the condition is false
31
Taking false branch
3802 return true;
3803
3804 //Attribute dependent, don't paint for printer or Preview
3805 bool bPaint = gProp.pSFlyOnlyDraw ||
6
Assuming field 'pSFlyOnlyDraw' is non-null
32
Assuming field 'pSFlyOnlyDraw' is non-null
3806 static_cast<SwContact*>(pUserCall)->GetFormat()->GetPrint().GetValue();
3807 if ( !bPaint
6.1
'bPaint' is true
32.1
'bPaint' is true
6.1
'bPaint' is true
32.1
'bPaint' is true
)
7
Taking false branch
33
Taking false branch
3808 bPaint = pSh->GetWin() && !pSh->IsPreview();
3809
3810 if ( bPaint
7.1
'bPaint' is true
33.1
'bPaint' is true
7.1
'bPaint' is true
33.1
'bPaint' is true
)
8
Taking true branch
34
Taking true branch
3811 {
3812 //The paint may be prevented by the superior Flys.
3813 SwFrame *pAnch = nullptr;
3814 if ( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr ) // i#117962#
9
Taking true branch
35
Assuming pointer value is null
36
Taking false branch
3815 {
3816 bPaint = false;
3817 }
3818 if ( dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) != nullptr )
10
Taking true branch
37
Taking false branch
3819 {
3820 SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
3821 if ( gProp.pSFlyOnlyDraw
10.1
Field 'pSFlyOnlyDraw' is non-null
10.1
Field 'pSFlyOnlyDraw' is non-null
&& gProp.pSFlyOnlyDraw == pFly )
11
Assuming 'pFly' is not equal to field 'pSFlyOnlyDraw'
12
Taking false branch
3822 return true;
3823
3824 //Try to avoid displaying the intermediate stage, Flys which don't
3825 //overlap with the page on which they are anchored won't be
3826 //painted.
3827 //HACK: exception: printing of frames in tables, those can overlap
3828 //a page once in a while when dealing with oversized tables (HTML).
3829 SwPageFrame *pPage = pFly->FindPageFrame();
13
Calling 'SwFrame::FindPageFrame'
16
Returning from 'SwFrame::FindPageFrame'
3830 if ( pPage
16.1
'pPage' is non-null
16.1
'pPage' is non-null
&& pPage->getFrameArea().IsOver( pFly->getFrameArea() ) )
17
Assuming the condition is true
18
Taking true branch
3831 {
3832 pAnch = pFly->AnchorFrame();
3833 }
3834
3835 }
3836 else
3837 {
3838 // Consider 'virtual' drawing objects
3839 SwDrawContact* pDrawContact = dynamic_cast<SwDrawContact*>(pUserCall);
3840 pAnch = pDrawContact
37.1
'pDrawContact' is non-null
37.1
'pDrawContact' is non-null
? pDrawContact->GetAnchorFrame(pObj) : nullptr;
38
'?' condition is true
3841 if ( pAnch )
39
Assuming 'pAnch' is non-null
40
Taking true branch
3842 {
3843 if ( !pAnch->isFrameAreaPositionValid() )
41
Assuming the condition is false
42
Taking false branch
3844 pAnch = nullptr;
3845 else if ( pSh->GetOut() == pSh->getIDocumentDeviceAccess().getPrinter( false ))
43
Assuming the condition is true
44
Taking true branch
3846 {
3847 //HACK: we have to omit some of the objects for printing,
3848 //otherwise they would be printed twice.
3849 //The objects should get printed if the TableHack is active
3850 //right now. Afterwards they must not be printed if the
3851 //page over which they float position wise gets printed.
3852 const SwPageFrame *pPage = pAnch->FindPageFrame();
3853 if ( !pPage->getFrameArea().IsOver( pObj->GetCurrentBoundRect() ) )
45
Called C++ object pointer is null
3854 pAnch = nullptr;
3855 }
3856 }
3857 else
3858 {
3859 if ( dynamic_cast< const SdrObjGroup *>( pObj ) == nullptr )
3860 {
3861 OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "3861" ": "), "%s", "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?"
); } } while (false)
;
3862 }
3863 }
3864 }
3865 if ( pAnch )
19
Assuming 'pAnch' is non-null
20
Taking true branch
3866 {
3867 if ( pAnch->IsInFly() )
21
Calling 'SwFrame::IsInFly'
25
Returning from 'SwFrame::IsInFly'
26
Assuming the condition is true
27
Taking true branch
3868 bPaint = SwFlyFrame::IsPaint( pAnch->FindFlyFrame()->GetVirtDrawObj(),
28
Passing value via 1st parameter 'pObj'
29
Calling 'SwFlyFrame::IsPaint'
3869 pSh );
3870 else if ( gProp.pSFlyOnlyDraw )
3871 bPaint = false;
3872 }
3873 else
3874 bPaint = false;
3875 }
3876 return bPaint;
3877}
3878
3879void SwCellFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3880{
3881 if ( GetLayoutRowSpan() >= 1 )
3882 SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
3883}
3884
3885namespace {
3886
3887struct BorderLinesGuard
3888{
3889 explicit BorderLinesGuard() : m_pBorderLines(std::move(gProp.pBLines))
3890 {
3891 gProp.pBLines.reset(new BorderLines);
3892 }
3893 ~BorderLinesGuard()
3894 {
3895 gProp.pBLines = std::move(m_pBorderLines);
3896 }
3897private:
3898 std::unique_ptr<BorderLines> m_pBorderLines;
3899};
3900
3901}
3902
3903void SwFlyFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
3904{
3905 //optimize thumbnail generation and store procedure to improve odt saving performance, #i120030#
3906 SwViewShell *pShell = getRootFrame()->GetCurrShell();
3907 if (pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocShell())
3908 {
3909 bool bInGenerateThumbnail = pShell->GetDoc()->GetDocShell()->IsInGenerateAndStoreThumbnail();
3910 if (bInGenerateThumbnail)
3911 {
3912 const SwRect& aVisRect = pShell->VisArea();
3913 if (!aVisRect.IsOver(getFrameArea()))
3914 return;
3915 }
3916 }
3917
3918 //because of the overlapping of frames and drawing objects the flys have to
3919 //paint their borders (and those of the internal ones) directly.
3920 //e.g. #33066#
3921 gProp.pSLines->LockLines(true);
3922 BorderLinesGuard blg; // this should not paint borders added from PaintBaBo
3923
3924 SwRect aRect( rRect );
3925 aRect.Intersection_( getFrameArea() );
3926
3927 rRenderContext.Push( PushFlags::CLIPREGION );
3928 rRenderContext.SetClipRegion();
3929 const SwPageFrame* pPage = FindPageFrame();
3930
3931 const SwNoTextFrame *pNoText = Lower() && Lower()->IsNoTextFrame()
3932 ? static_cast<const SwNoTextFrame*>(Lower()) : nullptr;
3933
3934 bool bIsChart = false; //#i102950# don't paint additional borders for charts
3935 //check whether we have a chart
3936 if(pNoText)
3937 {
3938 const SwNoTextNode* pNoTNd = dynamic_cast<const SwNoTextNode*>(pNoText->GetNode());
3939 if( pNoTNd )
3940 {
3941 SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTNd->GetOLENode());
3942 if( pOLENd && pOLENd->GetOLEObj().GetObject().IsChart() )
3943 bIsChart = true;
3944 }
3945 }
3946
3947 {
3948 bool bContour = GetFormat()->GetSurround().IsContour();
3949 tools::PolyPolygon aPoly;
3950 if ( bContour )
3951 {
3952 // add 2nd parameter with value <true>
3953 // to indicate that method is called for paint in order to avoid
3954 // load of the intrinsic graphic.
3955 bContour = GetContour( aPoly, true );
3956 }
3957
3958 // #i47804# - distinguish complete background paint
3959 // and margin paint.
3960 // paint complete background for Writer text fly frames
3961 bool bPaintCompleteBack( !pNoText );
3962 // paint complete background for transparent graphic and contour,
3963 // if own background color exists.
3964 const bool bIsGraphicTransparent = pNoText && pNoText->IsTransparent();
3965 if ( !bPaintCompleteBack &&
3966 ( bIsGraphicTransparent|| bContour ) )
3967 {
3968 const SwFrameFormat* pSwFrameFormat = dynamic_cast< const SwFrameFormat* >(GetFormat());
3969
3970 if (pSwFrameFormat && pSwFrameFormat->supportsFullDrawingLayerFillAttributeSet())
3971 {
3972 // check for transparency
3973 const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(pSwFrameFormat->getSdrAllFillAttributesHelper());
3974
3975 // check if the new fill attributes are used
3976 if(aFillAttributes && aFillAttributes->isUsed())
3977 {
3978 bPaintCompleteBack = true;
3979 }
3980 }
3981 else
3982 {
3983 std::unique_ptr<SvxBrushItem> aBack = GetFormat()->makeBackgroundBrushItem();
3984 // to determine, if background has to be painted, by checking, if
3985 // background color is not COL_TRANSPARENT ("no fill"/"auto fill")
3986 // or a background graphic exists.
3987 bPaintCompleteBack = aBack &&
3988 ((aBack->GetColor() != COL_TRANSPARENT) ||
3989 aBack->GetGraphicPos() != GPOS_NONE);
3990 }
3991 }
3992 // paint of margin needed.
3993 const bool bPaintMarginOnly( !bPaintCompleteBack &&
3994 getFramePrintArea().SSize() != getFrameArea().SSize() );
3995
3996 // #i47804# - paint background of parent fly frame
3997 // for transparent graphics in layer Hell, if parent fly frame isn't
3998 // in layer Hell. It's only painted the intersection between the
3999 // parent fly frame area and the paint area <aRect>
4000 const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
4001
4002 if (bIsGraphicTransparent &&
4003 GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS) &&
4004 GetVirtDrawObj()->GetLayer() == rIDDMA.GetHellId() &&
4005 GetAnchorFrame()->FindFlyFrame() )
4006 {
4007 const SwFlyFrame* pParentFlyFrame = GetAnchorFrame()->FindFlyFrame();
4008 if ( pParentFlyFrame->GetDrawObj()->GetLayer() !=
4009 rIDDMA.GetHellId() )
4010 {
4011 SwFlyFrame* pOldRet = gProp.pSRetoucheFly2;
4012 gProp.pSRetoucheFly2 = const_cast<SwFlyFrame*>(this);
4013
4014 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pParentFlyFrame );
4015 const SwBorderAttrs &rAttrs = *aAccess.Get();
4016 SwRect aPaintRect( aRect );
4017 aPaintRect.Intersection_( pParentFlyFrame->getFrameArea() );
4018 pParentFlyFrame->PaintSwFrameBackground( aPaintRect, pPage, rAttrs );
4019
4020 gProp.pSRetoucheFly2 = pOldRet;
4021 }
4022 }
4023
4024 if ( bPaintCompleteBack || bPaintMarginOnly )
4025 {
4026 //#24926# JP 01.02.96, PaintBaBo is here partially so PaintSwFrameShadowAndBorder
4027 //receives the original Rect but PaintSwFrameBackground only the limited
4028 //one.
4029
4030 rRenderContext.Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
4031 rRenderContext.SetLineColor();
4032
4033 pPage = FindPageFrame();
4034
4035 SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4036 const SwBorderAttrs &rAttrs = *aAccess.Get();
4037
4038 // paint background
4039 {
4040 SwRegionRects aRegion( aRect );
4041 // #i80822#
4042 // suppress painting of background in printing area for
4043 // non-transparent graphics.
4044 if ( bPaintMarginOnly ||
4045 ( pNoText && !bIsGraphicTransparent ) )
4046 {
4047 //What we actually want to paint is the small stripe between
4048 //PrtArea and outer border.
4049 SwRect aTmp( getFramePrintArea() ); aTmp += getFrameArea().Pos();
4050 aRegion -= aTmp;
4051 }
4052 if ( bContour )
4053 {
4054 rRenderContext.Push();
4055 // #i80822#
4056 // apply clip region under the same conditions, which are
4057 // used in <SwNoTextFrame::PaintSwFrame(..)> to set the clip region
4058 // for painting the graphic/OLE. Thus, the clip region is
4059 // also applied for the PDF export.
4060 SwViewShell *pSh = getRootFrame()->GetCurrShell();
4061
4062 if ( !rRenderContext.GetConnectMetaFile() || !pSh || !pSh->GetWin() )
4063 {
4064 rRenderContext.SetClipRegion(vcl::Region(aPoly));
4065 }
4066
4067 for ( size_t i = 0; i < aRegion.size(); ++i )
4068 {
4069 PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4070 }
4071
4072 rRenderContext.Pop();
4073 }
4074 else
4075 {
4076 for ( size_t i = 0; i < aRegion.size(); ++i )
4077 {
4078 PaintSwFrameBackground( aRegion[i], pPage, rAttrs, false, true );
4079 }
4080 }
4081 }
4082
4083 // paint border before painting background
4084 PaintSwFrameShadowAndBorder(rRect, pPage, rAttrs);
4085
4086 rRenderContext.Pop();
4087 }
4088 }
4089
4090 // fly frame will paint it's subsidiary lines and
4091 // the subsidiary lines of its lowers on its own, due to overlapping with
4092 // other fly frames or other objects.
4093 if( gProp.pSGlobalShell->GetWin()
4094 && !bIsChart ) //#i102950# don't paint additional borders for charts
4095 {
4096 bool bSubsLineRectsCreated;
4097 if ( gProp.pSSubsLines )
4098 {
4099 // Lock already existing subsidiary lines
4100 gProp.pSSubsLines->LockLines( true );
4101 bSubsLineRectsCreated = false;
4102 }
4103 else
4104 {
4105 // create new subsidiary lines
4106 gProp.pSSubsLines.reset(new SwSubsRects);
4107 bSubsLineRectsCreated = true;
4108 }
4109
4110 bool bSpecSubsLineRectsCreated;
4111 if ( gProp.pSSpecSubsLines )
4112 {
4113 // Lock already existing special subsidiary lines
4114 gProp.pSSpecSubsLines->LockLines( true );
4115 bSpecSubsLineRectsCreated = false;
4116 }
4117 else
4118 {
4119 // create new special subsidiary lines
4120 gProp.pSSpecSubsLines.reset(new SwSubsRects);
4121 bSpecSubsLineRectsCreated = true;
4122 }
4123 // Add subsidiary lines of fly frame and its lowers
4124 RefreshLaySubsidiary( pPage, aRect );
4125 // paint subsidiary lines of fly frame and its lowers
4126 gProp.pSSpecSubsLines->PaintSubsidiary( &rRenderContext, nullptr, gProp );
4127 gProp.pSSubsLines->PaintSubsidiary(&rRenderContext, gProp.pSLines.get(), gProp);
4128 if ( !bSubsLineRectsCreated )
4129 // unlock subsidiary lines
4130 gProp.pSSubsLines->LockLines( false );
4131 else
4132 {
4133 // delete created subsidiary lines container
4134 gProp.pSSubsLines.reset();
4135 }
4136
4137 if ( !bSpecSubsLineRectsCreated )
4138 // unlock special subsidiary lines
4139 gProp.pSSpecSubsLines->LockLines( false );
4140 else
4141 {
4142 // delete created special subsidiary lines container
4143 gProp.pSSpecSubsLines.reset();
4144 }
4145 }
4146
4147 SwLayoutFrame::PaintSwFrame( rRenderContext, aRect );
4148
4149 Validate();
4150
4151 // first paint lines added by fly frame paint
4152 // and then unlock other lines.
4153 gProp.pSLines->PaintLines( &rRenderContext, gProp );
4154 gProp.pSLines->LockLines( false );
4155 // have to paint frame borders added in heaven layer here...
4156 ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
4157
4158 PaintDecorators();
4159
4160 rRenderContext.Pop();
4161
4162 if ( gProp.pSProgress && pNoText )
4163 SfxProgress::Reschedule();
4164}
4165
4166void SwFlyFrame::PaintDecorators() const
4167{
4168 // Show the un-float button
4169 SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
4170 if ( pWrtSh )
4171 {
4172 UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
4173 }
4174}
4175
4176void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
4177{
4178 const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions();
4179 if (pViewOption->IsTable())
4180 {
4181 // #i29550#
4182 if ( IsCollapsingBorders() )
4183 {
4184 SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(this) );
4185 const SwBorderAttrs &rAttrs = *aAccess.Get();
4186
4187 // paint shadow
4188 if ( rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
4189 {
4190 SwRect aRect;
4191 ::lcl_CalcBorderRect( aRect, this, rAttrs, true, gProp );
4192 PaintShadow( rRect, aRect, rAttrs );
4193 }
4194
4195 SwTabFramePainter aHelper(*this);
4196 aHelper.PaintLines(rRenderContext, rRect);
4197 }
4198
4199 SwLayoutFrame::PaintSwFrame( rRenderContext, rRect );
4200 }
4201 // #i6467# - no light grey rectangle for page preview
4202 else if ( gProp.pSGlobalShell->GetWin() && !gProp.pSGlobalShell->IsPreview() )
4203 {
4204 // #i6467# - intersect output rectangle with table frame
4205 SwRect aTabRect( getFramePrintArea() );
4206 aTabRect.Pos() += getFrameArea().Pos();
4207 SwRect aTabOutRect( rRect );
4208 aTabOutRect.Intersection( aTabRect );
4209 SwViewOption::DrawRect( &rRenderContext, aTabOutRect, COL_LIGHTGRAY );
4210 }
4211 const_cast<SwTabFrame*>(this)->ResetComplete();
4212}
4213
4214/**
4215 * Paint border shadow
4216 *
4217 * @param[in] rRect aligned rect to clip the result
4218 * @param[in,out] rOutRect full painting area as input
4219 * painting area reduced by shadow space for border and background as output
4220 * @param[in] rShadow includes shadow attributes
4221 * @param[in] bDrawFullShadowRectangle paint full rect of shadow
4222 * @param[in] bTop paint top part of the shadow
4223 * @param[in] bBottom paint bottom part of the shadow
4224 * @param[in] bLeft paint left part of the shadow
4225 * @param[in] bRight paint right part of the shadow
4226**/
4227static void lcl_PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4228 const SvxShadowItem& rShadow, const bool bDrawFullShadowRectangle,
4229 const bool bTop, const bool bBottom,
4230 const bool bLeft, const bool bRight,
4231 SwPaintProperties const & properties)
4232{
4233 const long nWidth = ::lcl_AlignWidth ( rShadow.GetWidth(), properties );
4234 const long nHeight = ::lcl_AlignHeight( rShadow.GetWidth(), properties );
4235
4236 SwRects aRegion;
4237 SwRect aOut( rOutRect );
4238
4239 switch ( rShadow.GetLocation() )
4240 {
4241 case SvxShadowLocation::BottomRight:
4242 {
4243 if ( bDrawFullShadowRectangle )
4244 {
4245 // draw full shadow rectangle
4246 aOut.Top( rOutRect.Top() + nHeight );
4247 aOut.Left( rOutRect.Left() + nWidth );
4248 aRegion.push_back( aOut );
4249 }
4250 else
4251 {
4252 if( bBottom )
4253 {
4254 aOut.Top( rOutRect.Bottom() - nHeight );
4255 if( bLeft )
4256 aOut.Left( rOutRect.Left() + nWidth );
4257 aRegion.push_back( aOut );
4258 }
4259 if( bRight )
4260 {
4261 aOut.Left( rOutRect.Right() - nWidth );
4262 if( bTop )
4263 aOut.Top( rOutRect.Top() + nHeight );
4264 else
4265 aOut.Top( rOutRect.Top() );
4266 if( bBottom )
4267 aOut.Bottom( rOutRect.Bottom() - nHeight );
4268 aRegion.push_back( aOut );
4269 }
4270 }
4271
4272 if( bRight )
4273 rOutRect.AddRight(- nWidth );
4274 if( bBottom )
4275 rOutRect.AddBottom(- nHeight );
4276 }
4277 break;
4278 case SvxShadowLocation::TopLeft:
4279 {
4280 if ( bDrawFullShadowRectangle )
4281 {
4282 // draw full shadow rectangle
4283 aOut.Bottom( rOutRect.Bottom() - nHeight );
4284 aOut.Right( rOutRect.Right() - nWidth );
4285 aRegion.push_back( aOut );
4286 }
4287 else
4288 {
4289 if( bTop )
4290 {
4291 aOut.Bottom( rOutRect.Top() + nHeight );
4292 if( bRight )
4293 aOut.Right( rOutRect.Right() - nWidth );
4294 aRegion.push_back( aOut );
4295 }
4296 if( bLeft )
4297 {
4298 aOut.Right( rOutRect.Left() + nWidth );
4299 if( bBottom )
4300 aOut.Bottom( rOutRect.Bottom() - nHeight );
4301 else
4302 aOut.Bottom( rOutRect.Bottom() );
4303 if( bTop )
4304 aOut.Top( rOutRect.Top() + nHeight );
4305 aRegion.push_back( aOut );
4306 }
4307 }
4308
4309 if( bLeft )
4310 rOutRect.AddLeft( nWidth );
4311 if( bTop )
4312 rOutRect.AddTop( nHeight );
4313 }
4314 break;
4315 case SvxShadowLocation::TopRight:
4316 {
4317 if ( bDrawFullShadowRectangle )
4318 {
4319 // draw full shadow rectangle
4320 aOut.Bottom( rOutRect.Bottom() - nHeight);
4321 aOut.Left( rOutRect.Left() + nWidth );
4322 aRegion.push_back( aOut );
4323 }
4324 else
4325 {
4326 if( bTop )
4327 {
4328 aOut.Bottom( rOutRect.Top() + nHeight );
4329 if( bLeft )
4330 aOut.Left( rOutRect.Left() + nWidth );
4331 aRegion.push_back( aOut );
4332 }
4333 if( bRight )
4334 {
4335 aOut.Left( rOutRect.Right() - nWidth );
4336 if( bBottom )
4337 aOut.Bottom( rOutRect.Bottom() - nHeight );
4338 else
4339 aOut.Bottom( rOutRect.Bottom() );
4340 if( bTop )
4341 aOut.Top( rOutRect.Top() + nHeight );
4342 aRegion.push_back( aOut );
4343 }
4344 }
4345
4346 if( bRight )
4347 rOutRect.AddRight( - nWidth );
4348 if( bTop )
4349 rOutRect.AddTop( nHeight );
4350 }
4351 break;
4352 case SvxShadowLocation::BottomLeft:
4353 {
4354 if ( bDrawFullShadowRectangle )
4355 {
4356 // draw full shadow rectangle
4357 aOut.Top( rOutRect.Top() + nHeight );
4358 aOut.Right( rOutRect.Right() - nWidth );
4359 aRegion.push_back( aOut );
4360 }
4361 else
4362 {
4363 if( bBottom )
4364 {
4365 aOut.Top( rOutRect.Bottom()- nHeight );
4366 if( bRight )
4367 aOut.Right( rOutRect.Right() - nWidth );
4368 aRegion.push_back( aOut );
4369 }
4370 if( bLeft )
4371 {
4372 aOut.Right( rOutRect.Left() + nWidth );
4373 if( bTop )
4374 aOut.Top( rOutRect.Top() + nHeight );
4375 else
4376 aOut.Top( rOutRect.Top() );
4377 if( bBottom )
4378 aOut.Bottom( rOutRect.Bottom() - nHeight );
4379 aRegion.push_back( aOut );
4380 }
4381 }
4382
4383 if( bLeft )
4384 rOutRect.AddLeft( nWidth );
4385 if( bBottom )
4386 rOutRect.AddBottom( - nHeight );
4387 }
4388 break;
4389 default:
4390 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
, 4390, __extension__ __PRETTY_FUNCTION__))
;
4391 break;
4392 }
4393
4394 vcl::RenderContext *pOut = properties.pSGlobalShell->GetOut();
4395
4396 DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
4397 Color aShadowColor( rShadow.GetColor().GetRGBColor() );
4398 if( !aRegion.empty() && properties.pSGlobalShell->GetWin() &&
4399 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4400 {
4401 // In high contrast mode, the output device has already set the
4402 // DrawModeFlags::SettingsFill flag. This causes the SetFillColor function
4403 // to ignore the setting of a new color. Therefore we have to reset
4404 // the drawing mode
4405 pOut->SetDrawMode( DrawModeFlags::Default );
4406 aShadowColor = SwViewOption::GetFontColor();
4407 }
4408
4409 if ( pOut->GetFillColor() != aShadowColor )
4410 pOut->SetFillColor( aShadowColor );
4411
4412 pOut->SetLineColor();
4413
4414 pOut->SetDrawMode( nOldDrawMode );
4415
4416 for (const SwRect & rOut : aRegion)
4417 {
4418 aOut = rOut;
4419 if ( rRect.IsOver( aOut ) && aOut.Height() > 0 && aOut.Width() > 0 )
4420 {
4421 aOut.Intersection_( rRect );
4422 pOut->DrawRect( aOut.SVRect() );
4423 }
4424 }
4425}
4426
4427/**
4428 * Paints a shadow if the format requests so.
4429 *
4430 * The shadow is always painted on the outer edge of the OutRect.
4431 * If needed, the OutRect is shrunk so the painting of the border can be
4432 * done on it.
4433 *
4434 * @note: draw full shadow rectangle for frames with transparent drawn backgrounds (OD 23.08.2002 #99657#)
4435 */
4436void SwFrame::PaintShadow( const SwRect& rRect, SwRect& rOutRect,
4437 const SwBorderAttrs &rAttrs ) const
4438{
4439 SvxShadowItem rShadow = rAttrs.GetShadow();
4440
4441 const bool bCnt = IsContentFrame();
4442 const bool bTop = !bCnt || rAttrs.GetTopLine ( *(this) );
4443 const bool bBottom = !bCnt || rAttrs.GetBottomLine( *(this) );
4444
4445 if( IsVertical() )
4446 {
4447 switch( rShadow.GetLocation() )
4448 {
4449 case SvxShadowLocation::BottomRight: rShadow.SetLocation(SvxShadowLocation::BottomLeft); break;
4450 case SvxShadowLocation::TopLeft: rShadow.SetLocation(SvxShadowLocation::TopRight); break;
4451 case SvxShadowLocation::TopRight: rShadow.SetLocation(SvxShadowLocation::BottomRight); break;
4452 case SvxShadowLocation::BottomLeft: rShadow.SetLocation(SvxShadowLocation::TopLeft); break;
4453 default: break;
4454 }
4455 }
4456
4457 // determine, if full shadow rectangle have to be drawn or only two shadow rectangles beside the frame.
4458 // draw full shadow rectangle, if frame background is drawn transparent.
4459 // Status Quo:
4460 // SwLayoutFrame can have transparent drawn backgrounds. Thus,
4461 // "asked" their frame format.
4462 const bool bDrawFullShadowRectangle =
4463 ( IsLayoutFrame() &&
4464 static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent()
4465 );
4466
4467 SwRectFnSet aRectFnSet(this);
4468 ::lcl_ExtendLeftAndRight( rOutRect, *(this), rAttrs, aRectFnSet.FnRect() );
4469
4470 lcl_PaintShadow(rRect, rOutRect, rShadow, bDrawFullShadowRectangle, bTop, bBottom, true, true, gProp);
4471}
4472
4473void SwFrame::PaintBorderLine( const SwRect& rRect,
4474 const SwRect& rOutRect,
4475 const SwPageFrame * pPage,
4476 const Color *pColor,
4477 const SvxBorderLineStyle nStyle ) const
4478{
4479 if ( !rOutRect.IsOver( rRect ) )
4480 return;
4481
4482 SwRect aOut( rOutRect );
4483 aOut.Intersection_( rRect );
4484
4485 const SwTabFrame *pTab = IsCellFrame() ? FindTabFrame() : nullptr;
4486 SubColFlags nSubCol = ( IsCellFrame() || IsRowFrame() )
4487 ? SubColFlags::Tab
4488 : ( IsInSct()
4489 ? SubColFlags::Sect
4490 : ( IsInFly() ? SubColFlags::Fly : SubColFlags::Page ) );
4491 if( pColor && gProp.pSGlobalShell->GetWin() &&
4492 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
4493 {
4494 pColor = &SwViewOption::GetFontColor();
4495 }
4496
4497 if (pPage->GetSortedObjs() &&
4498 pPage->GetFormat()->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS))
4499 {
4500 SwRegionRects aRegion( aOut, 4 );
4501 basegfx::utils::B2DClipState aClipState;
4502 ::lcl_SubtractFlys( this, pPage, aOut, aRegion, aClipState, gProp );
4503 for ( size_t i = 0; i < aRegion.size(); ++i )
4504 gProp.pSLines->AddLineRect( aRegion[i], pColor, nStyle, pTab, nSubCol, gProp );
4505 }
4506 else
4507 gProp.pSLines->AddLineRect( aOut, pColor, nStyle, pTab, nSubCol, gProp );
4508}
4509
4510namespace drawinglayer::primitive2d
4511{
4512 namespace {
4513
4514 class SwBorderRectanglePrimitive2D : public BufferedDecompositionPrimitive2D
4515 {
4516 private:
4517 /// the transformation defining the geometry of this BorderRectangle
4518 basegfx::B2DHomMatrix maB2DHomMatrix;
4519
4520 /// the four styles to be used
4521 svx::frame::Style maStyleTop;
4522 svx::frame::Style maStyleRight;
4523 svx::frame::Style maStyleBottom;
4524 svx::frame::Style maStyleLeft;
4525
4526 protected:
4527 /// local decomposition.
4528 virtual void create2DDecomposition(
4529 Primitive2DContainer& rContainer,
4530 const geometry::ViewInformation2D& rViewInformation) const override;
4531
4532 public:
4533 /// constructor
4534 SwBorderRectanglePrimitive2D(
4535 const basegfx::B2DHomMatrix& rB2DHomMatrix,
4536 const svx::frame::Style& rStyleTop,
4537 const svx::frame::Style& rStyleRight,
4538 const svx::frame::Style& rStyleBottom,
4539 const svx::frame::Style& rStyleLeft);
4540
4541 /// data read access
4542 const basegfx::B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; }
4543 const svx::frame::Style& getStyleTop() const { return maStyleTop; }
4544 const svx::frame::Style& getStyleRight() const { return maStyleRight; }
4545 const svx::frame::Style& getStyleBottom() const { return maStyleBottom; }
4546 const svx::frame::Style& getStyleLeft() const { return maStyleLeft; }
4547
4548 /// compare operator
4549 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
4550
4551 /// get range
4552 virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
4553
4554 /// provide unique ID
4555 virtual sal_uInt32 getPrimitive2DID() const override;
4556 };
4557
4558 }
4559
4560 void SwBorderRectanglePrimitive2D::create2DDecomposition(
4561 Primitive2DContainer& rContainer,
4562 const geometry::ViewInformation2D& /*rViewInformation*/) const
4563 {
4564 basegfx::B2DPoint aTopLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 0.0));
4565 basegfx::B2DPoint aTopRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 0.0));
4566 basegfx::B2DPoint aBottomLeft(getB2DHomMatrix() * basegfx::B2DPoint(0.0, 1.0));
4567 basegfx::B2DPoint aBottomRight(getB2DHomMatrix() * basegfx::B2DPoint(1.0, 1.0));
4568
4569 // prepare SdrFrameBorderDataVector
4570 std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
4571 std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
4572
4573 if(getStyleTop().IsUsed())
4574 {
4575 // move top left/right inwards half border width
4576 basegfx::B2DVector aDown(getB2DHomMatrix() * basegfx::B2DVector(0.0, 1.0));
4577 aDown.setLength(getStyleTop().GetWidth() * 0.5);
4578 aTopLeft += aDown;
4579 aTopRight += aDown;
4580 }
4581
4582 if(getStyleBottom().IsUsed())
4583 {
4584 // move bottom left/right inwards half border width
4585 basegfx::B2DVector aUp(getB2DHomMatrix() * basegfx::B2DVector(0.0, -1.0));
4586 aUp.setLength(getStyleBottom().GetWidth() * 0.5);
4587 aBottomLeft += aUp;
4588 aBottomRight += aUp;
4589 }
4590
4591 if(getStyleLeft().IsUsed())
4592 {
4593 // move left top/bottom inwards half border width
4594 basegfx::B2DVector aRight(getB2DHomMatrix() * basegfx::B2DVector(1.0, 0.0));
4595 aRight.setLength(getStyleLeft().GetWidth() * 0.5);
4596 aTopLeft += aRight;
4597 aBottomLeft += aRight;
4598 }
4599
4600 if(getStyleRight().IsUsed())
4601 {
4602 // move right top/bottom inwards half border width
4603 basegfx::B2DVector aLeft(getB2DHomMatrix() * basegfx::B2DVector(-1.0, 0.0));
4604 aLeft.setLength(getStyleRight().GetWidth() * 0.5);
4605 aTopRight += aLeft;
4606 aBottomRight += aLeft;
4607 }
4608
4609 // go round-robin, from TopLeft to TopRight, down, left and back up. That
4610 // way, the borders will not need to be mirrored in any way
4611 if(getStyleTop().IsUsed())
4612 {
4613 // create BorderPrimitive(s) for top border
4614 const basegfx::B2DVector aVector(aTopRight - aTopLeft);
4615 aData->emplace_back(
4616 aTopLeft,
4617 aVector,
4618 getStyleTop(),
4619 nullptr);
4620 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4621
4622 if(getStyleLeft().IsUsed())
4623 {
4624 rInstance.addSdrConnectStyleData(true, getStyleLeft(), basegfx::B2DVector(aBottomLeft - aTopLeft), false);
4625 }
4626
4627 if(getStyleRight().IsUsed())
4628 {
4629 rInstance.addSdrConnectStyleData(false, getStyleRight(), basegfx::B2DVector(aBottomRight - aTopRight), false);
4630 }
4631 }
4632
4633 if(getStyleRight().IsUsed())
4634 {
4635 // create BorderPrimitive(s) for right border
4636 const basegfx::B2DVector aVector(aBottomRight - aTopRight);
4637 aData->emplace_back(
4638 aTopRight,
4639 aVector,
4640 getStyleRight(),
4641 nullptr);
4642 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4643
4644 if(getStyleTop().IsUsed())
4645 {
4646 rInstance.addSdrConnectStyleData(true, getStyleTop(), basegfx::B2DVector(aTopLeft - aTopRight), false);
4647 }
4648
4649 if(getStyleBottom().IsUsed())
4650 {
4651 rInstance.addSdrConnectStyleData(false, getStyleBottom(), basegfx::B2DVector(aBottomLeft - aBottomRight), false);
4652 }
4653 }
4654
4655 if(getStyleBottom().IsUsed())
4656 {
4657 // create BorderPrimitive(s) for bottom border
4658 const basegfx::B2DVector aVector(aBottomLeft - aBottomRight);
4659 aData->emplace_back(
4660 aBottomRight,
4661 aVector,
4662 getStyleBottom(),
4663 nullptr);
4664 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4665
4666 if(getStyleRight().IsUsed())
4667 {
4668 rInstance.addSdrConnectStyleData(true, getStyleRight(), basegfx::B2DVector(aTopRight - aBottomRight), false);
4669 }
4670
4671 if(getStyleLeft().IsUsed())
4672 {
4673 rInstance.addSdrConnectStyleData(false, getStyleLeft(), basegfx::B2DVector(aTopLeft - aBottomLeft), false);
4674 }
4675 }
4676
4677 if(getStyleLeft().IsUsed())
4678 {
4679 // create BorderPrimitive(s) for left border
4680 const basegfx::B2DVector aVector(aTopLeft - aBottomLeft);
4681 aData->emplace_back(
4682 aBottomLeft,
4683 aVector,
4684 getStyleLeft(),
4685 nullptr);
4686 drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());
4687
4688 if(getStyleBottom().IsUsed())
4689 {
4690 rInstance.addSdrConnectStyleData(true, getStyleBottom(), basegfx::B2DVector(aBottomRight - aBottomLeft), false);
4691 }
4692
4693 if(getStyleTop().IsUsed())
4694 {
4695 rInstance.addSdrConnectStyleData(false, getStyleTop(), basegfx::B2DVector(aTopRight - aTopLeft), false);
4696 }
4697 }
4698
4699 // create instance of SdrFrameBorderPrimitive2D if
4700 // SdrFrameBorderDataVector is used
4701 if(!aData->empty())
4702 {
4703 rContainer.append(
4704 drawinglayer::primitive2d::Primitive2DReference(
4705 new drawinglayer::primitive2d::SdrFrameBorderPrimitive2D(
4706 aData,
4707 true))); // force visualization to minimal one discrete unit (pixel)
4708 }
4709 }
4710
4711 SwBorderRectanglePrimitive2D::SwBorderRectanglePrimitive2D(
4712 const basegfx::B2DHomMatrix& rB2DHomMatrix,
4713 const svx::frame::Style& rStyleTop,
4714 const svx::frame::Style& rStyleRight,
4715 const svx::frame::Style& rStyleBottom,
4716 const svx::frame::Style& rStyleLeft)
4717 : BufferedDecompositionPrimitive2D(),
4718 maB2DHomMatrix(rB2DHomMatrix),
4719 maStyleTop(rStyleTop),
4720 maStyleRight(rStyleRight),
4721 maStyleBottom(rStyleBottom),
4722 maStyleLeft(rStyleLeft)
4723 {
4724 }
4725
4726 bool SwBorderRectanglePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
4727 {
4728 if(BasePrimitive2D::operator==(rPrimitive))
4729 {
4730 const SwBorderRectanglePrimitive2D& rCompare = static_cast<const SwBorderRectanglePrimitive2D&>(rPrimitive);
4731
4732 return (getB2DHomMatrix() == rCompare.getB2DHomMatrix() &&
4733 getStyleTop() == rCompare.getStyleTop() &&
4734 getStyleRight() == rCompare.getStyleRight() &&
4735 getStyleBottom() == rCompare.getStyleBottom() &&
4736 getStyleLeft() == rCompare.getStyleLeft());
4737 }
4738
4739 return false;
4740 }
4741
4742 basegfx::B2DRange SwBorderRectanglePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
4743 {
4744 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
4745
4746 aRetval.transform(getB2DHomMatrix());
4747 return aRetval;
4748 }
4749
4750 // provide unique ID
4751 ImplPrimitive2DIDBlock(SwBorderRectanglePrimitive2D, PRIMITIVE2D_ID_SWBORDERRECTANGLERIMITIVE)sal_uInt32 SwBorderRectanglePrimitive2D::getPrimitive2DID() const
{ return ((3 << 16)| 3); }
4752
4753} // end of namespace drawinglayer::primitive2d
4754
4755namespace {
4756
4757editeng::SvxBorderLine const * get_ptr(std::optional<editeng::SvxBorderLine> const & opt) {
4758 return opt ? &*opt : nullptr;
4759}
4760
4761}
4762
4763void PaintCharacterBorder(
4764 const SwFont& rFont,
4765 const SwRect& rPaintArea,
4766 const bool bVerticalLayout,
4767 const bool bVerticalLayoutLRBT,
4768 const bool bJoinWithPrev,
4769 const bool bJoinWithNext )
4770{
4771 SwRect aAlignedRect(rPaintArea);
4772 SwAlignRect(aAlignedRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut());
4773
4774 bool bTop = true;
4775 bool bBottom = true;
4776 bool bLeft = true;
4777 bool bRight = true;
4778
4779 switch (rFont.GetOrientation(bVerticalLayout, bVerticalLayoutLRBT))
4780 {
4781 case 0 :
4782 bLeft = !bJoinWithPrev;
4783 bRight = !bJoinWithNext;
4784 break;
4785 case 900 :
4786 bBottom = !bJoinWithPrev;
4787 bTop = !bJoinWithNext;
4788 break;
4789 case 1800 :
4790 bRight = !bJoinWithPrev;
4791 bLeft = !bJoinWithNext;
4792 break;
4793 case 2700 :
4794 bTop = !bJoinWithPrev;
4795 bBottom = !bJoinWithNext;
4796 break;
4797 }
4798
4799 // Paint shadow (reduce painting rect)
4800 {
4801 const SvxShadowItem aShadow(
4802 0, &rFont.GetShadowColor(), rFont.GetShadowWidth(),
4803 rFont.GetAbsShadowLocation(bVerticalLayout, bVerticalLayoutLRBT));
4804
4805 if( aShadow.GetLocation() != SvxShadowLocation::NONE )
4806 {
4807 lcl_PaintShadow( rPaintArea, aAlignedRect, aShadow,
4808 false, bTop, bBottom, bLeft, bRight, gProp);
4809 }
4810 }
4811
4812 const basegfx::B2DHomMatrix aBorderTransform(
4813 basegfx::utils::createScaleTranslateB2DHomMatrix(
4814 aAlignedRect.Width(), aAlignedRect.Height(),
4815 aAlignedRect.Left(), aAlignedRect.Top()));
4816 const svx::frame::Style aStyleTop(
4817 bTop ? get_ptr(rFont.GetAbsTopBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4818 1.0);
4819 const svx::frame::Style aStyleRight(
4820 bRight ? get_ptr(rFont.GetAbsRightBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4821 1.0);
4822 const svx::frame::Style aStyleBottom(
4823 bBottom ? get_ptr(rFont.GetAbsBottomBorder(bVerticalLayout, bVerticalLayoutLRBT))
4824 : nullptr,
4825 1.0);
4826 const svx::frame::Style aStyleLeft(
4827 bLeft ? get_ptr(rFont.GetAbsLeftBorder(bVerticalLayout, bVerticalLayoutLRBT)) : nullptr,
4828 1.0);
4829 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
4830
4831 aBorderLineTarget.append(
4832 drawinglayer::primitive2d::Primitive2DReference(
4833 new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
4834 aBorderTransform,
4835 aStyleTop,
4836 aStyleRight,
4837 aStyleBottom,
4838 aStyleLeft)));
4839 gProp.pBLines->AddBorderLines(aBorderLineTarget);
4840}
4841
4842/// #i15844#
4843static const SwFrame* lcl_HasNextCell( const SwFrame& rFrame )
4844{
4845 OSL_ENSURE( rFrame.IsCellFrame(),do { if (true && (!(rFrame.IsCellFrame()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "4846" ": "), "%s", "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame"
); } } while (false)
4846 "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame" )do { if (true && (!(rFrame.IsCellFrame()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "4846" ": "), "%s", "lcl_HasNextCell( const SwFrame& rFrame ) should be called with SwCellFrame"
); } } while (false)
;
4847
4848 const SwFrame* pTmpFrame = &rFrame;
4849 do
4850 {
4851 if ( pTmpFrame->GetNext() )
4852 return pTmpFrame->GetNext();
4853
4854 pTmpFrame = pTmpFrame->GetUpper()->GetUpper();
4855 }
4856 while ( pTmpFrame->IsCellFrame() );
4857
4858 return nullptr;
4859}
4860
4861/**
4862 * Determine cell frame, from which the border attributes
4863 * for paint of top/bottom border has to be used.
4864 *
4865 * OD 21.02.2003 #b4779636#, #107692#
4866 *
4867 * @param _pCellFrame
4868 * input parameter - constant pointer to cell frame for which the cell frame
4869 * for the border attributes has to be determined.
4870 *
4871 * @param _rCellBorderAttrs
4872 * input parameter - constant reference to the border attributes of cell frame
4873 * <_pCellFrame>.
4874 *
4875 * @param _bTop
4876 * input parameter - boolean, that controls, if cell frame for top border or
4877 * for bottom border has to be determined.
4878 *
4879 * @return constant pointer to cell frame, for which the border attributes has
4880 * to be used
4881 */
4882static const SwFrame* lcl_GetCellFrameForBorderAttrs( const SwFrame* _pCellFrame,
4883 const SwBorderAttrs& _rCellBorderAttrs,
4884 const bool _bTop )
4885{
4886 OSL_ENSURE( _pCellFrame, "No cell frame available, dying soon" )do { if (true && (!(_pCellFrame))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "4886" ": "), "%s", "No cell frame available, dying soon"
); } } while (false)
;
4887
4888 // determine, if cell frame is at bottom/top border of a table frame and
4889 // the table frame has/is a follow.
4890 const SwFrame* pTmpFrame = _pCellFrame;
4891 bool bCellAtBorder = true;
4892 bool bCellAtLeftBorder = !_pCellFrame->GetPrev();
4893 bool bCellAtRightBorder = !_pCellFrame->GetNext();
4894 while( !pTmpFrame->IsRowFrame() || !pTmpFrame->GetUpper()->IsTabFrame() )
4895 {
4896 pTmpFrame = pTmpFrame->GetUpper();
4897 if ( pTmpFrame->IsRowFrame() &&
4898 (_bTop ? pTmpFrame->GetPrev() : pTmpFrame->GetNext())
4899 )
4900 {
4901 bCellAtBorder = false;
4902 }
4903 if ( pTmpFrame->IsCellFrame() )
4904 {
4905 if ( pTmpFrame->GetPrev() )
4906 {
4907 bCellAtLeftBorder = false;
4908 }
4909 if ( pTmpFrame->GetNext() )
4910 {
4911 bCellAtRightBorder = false;
4912 }
4913 }
4914 }
4915 OSL_ENSURE( pTmpFrame && pTmpFrame->IsRowFrame(), "No RowFrame available" )do { if (true && (!(pTmpFrame && pTmpFrame->
IsRowFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "4915" ": "), "%s", "No RowFrame available"); } } while (
false)
;
4916
4917 const SwLayoutFrame* pParentRowFrame = static_cast<const SwLayoutFrame*>(pTmpFrame);
4918 const SwTabFrame* pParentTabFrame =
4919 static_cast<const SwTabFrame*>(pParentRowFrame->GetUpper());
4920
4921 const bool bCellNeedsAttribute = bCellAtBorder &&
4922 ( _bTop ?
4923 // bCellInFirstRowWithMaster
4924 ( !pParentRowFrame->GetPrev() &&
4925 pParentTabFrame->IsFollow() &&
4926 0 == pParentTabFrame->GetTable()->GetRowsToRepeat() ) :
4927 // bCellInLastRowWithFollow
4928 ( !pParentRowFrame->GetNext() &&
4929 pParentTabFrame->GetFollow() )
4930 );
4931
4932 const SwFrame* pRet = _pCellFrame;
4933 if ( bCellNeedsAttribute )
4934 {
4935 // determine, if cell frame has no borders inside the table.
4936 const SwFrame* pNextCell = nullptr;
4937 bool bNoBordersInside = false;
4938
4939 if ( bCellAtLeftBorder && ( nullptr != ( pNextCell = lcl_HasNextCell( *_pCellFrame ) ) ) )
4940 {
4941 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pNextCell );
4942 const SwBorderAttrs &rBorderAttrs = *aAccess.Get();
4943 const SvxBoxItem& rBorderBox = rBorderAttrs.GetBox();
4944 bCellAtRightBorder = !lcl_HasNextCell( *pNextCell );
4945 bNoBordersInside =
4946 ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4947 !rBorderBox.GetLeft() &&
4948 ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4949 ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4950 }
4951 else
4952 {
4953 const SvxBoxItem& rBorderBox = _rCellBorderAttrs.GetBox();
4954 bNoBordersInside =
4955 ( !rBorderBox.GetTop() || !pParentRowFrame->GetPrev() ) &&
4956 ( !rBorderBox.GetLeft() || bCellAtLeftBorder ) &&
4957 ( !rBorderBox.GetRight() || bCellAtRightBorder ) &&
4958 ( !rBorderBox.GetBottom() || !pParentRowFrame->GetNext() );
4959 }
4960
4961 if ( bNoBordersInside )
4962 {
4963 if ( _bTop && !_rCellBorderAttrs.GetBox().GetTop() )
4964 {
4965 //-hack
4966 // Cell frame has no top border and no border inside the table, but
4967 // it is at the top border of a table frame, which is a follow.
4968 // Thus, use border attributes of cell frame in first row of complete table.
4969 // First, determine first table frame of complete table.
4970 SwTabFrame* pMasterTabFrame = pParentTabFrame->FindMaster( true );
4971 // determine first row of complete table.
4972 const SwFrame* pFirstRow = pMasterTabFrame->GetLower();
4973 // return first cell in first row
4974 SwFrame* pLowerCell = const_cast<SwFrame*>(pFirstRow->GetLower());
4975 while ( !pLowerCell->IsCellFrame() ||
4976 ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
4977 )
4978 {
4979 pLowerCell = pLowerCell->GetLower();
4980 }
4981 OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" )do { if (true && (!(pLowerCell && pLowerCell->
IsCellFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "4981" ": "), "%s", "No CellFrame available"); } } while
(false)
;
4982 pRet = pLowerCell;
4983 }
4984 else if ( !_bTop && !_rCellBorderAttrs.GetBox().GetBottom() )
4985 {
4986 //-hack
4987 // Cell frame has no bottom border and no border inside the table,
4988 // but it is at the bottom border of a table frame, which has a follow.
4989 // Thus, use border attributes of cell frame in last row of complete table.
4990 // First, determine last table frame of complete table.
4991 SwTabFrame* pLastTabFrame = const_cast<SwTabFrame*>(pParentTabFrame->GetFollow());
4992 while ( pLastTabFrame->GetFollow() )
4993 {
4994 pLastTabFrame = pLastTabFrame->GetFollow();
4995 }
4996 // determine last row of complete table.
4997 SwFrame* pLastRow = pLastTabFrame->GetLastLower();
4998 // return first bottom border cell in last row
4999 SwFrame* pLowerCell = pLastRow->GetLower();
5000 while ( !pLowerCell->IsCellFrame() ||
5001 ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrame() )
5002 )
5003 {
5004 if ( pLowerCell->IsRowFrame() )
5005 {
5006 while ( pLowerCell->GetNext() )
5007 {
5008 pLowerCell = pLowerCell->GetNext();
5009 }
5010 }
5011 pLowerCell = pLowerCell->GetLower();
5012 }
5013 OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrame(), "No CellFrame available" )do { if (true && (!(pLowerCell && pLowerCell->
IsCellFrame()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5013" ": "), "%s", "No CellFrame available"); } } while
(false)
;
5014 pRet = pLowerCell;
5015 }
5016 }
5017 }
5018
5019 return pRet;
5020}
5021
5022std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> SwFrame::CreateProcessor2D( ) const
5023{
5024 basegfx::B2DRange aViewRange;
5025
5026 SdrPage *pDrawPage = getRootFrame()->GetCurrShell()->Imp()->GetPageView()->GetPage();
5027 const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
5028 basegfx::B2DHomMatrix( ),
5029 getRootFrame()->GetCurrShell()->GetOut()->GetViewTransformation(),
5030 aViewRange,
5031 GetXDrawPageForSdrPage( pDrawPage ),
5032 0.0,
5033 uno::Sequence< beans::PropertyValue >() );
5034
5035 return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
5036 *getRootFrame()->GetCurrShell()->GetOut(),
5037 aNewViewInfos );
5038}
5039
5040void SwFrame::ProcessPrimitives( const drawinglayer::primitive2d::Primitive2DContainer& rSequence ) const
5041{
5042 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D = CreateProcessor2D();
5043 if ( pProcessor2D )
5044 {
5045 pProcessor2D->process( rSequence );
5046 }
5047}
5048
5049/// Paints shadows and borders
5050void SwFrame::PaintSwFrameShadowAndBorder(
5051 const SwRect& rRect,
5052 const SwPageFrame* /*pPage*/,
5053 const SwBorderAttrs& rAttrs) const
5054{
5055 // There's nothing (Row,Body,Footnote,Root,Column,NoText) need to do here
5056 if (GetType() & (SwFrameType::NoTxt|SwFrameType::Row|SwFrameType::Body|SwFrameType::Ftn|SwFrameType::Column|SwFrameType::Root))
5057 return;
5058
5059 if (IsCellFrame() && !gProp.pSGlobalShell->GetViewOptions()->IsTable())
5060 return;
5061
5062 // #i29550#
5063 if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
5064 {
5065 const SwTabFrame* pTabFrame = FindTabFrame();
5066 if ( pTabFrame->IsCollapsingBorders() )
5067 return;
5068
5069 if ( pTabFrame->GetTable()->IsNewModel() && ( !IsCellFrame() || IsCoveredCell() ) )
5070 return;
5071 }
5072
5073 const bool bLine = rAttrs.IsLine();
5074 const bool bShadow = rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE;
5075
5076 // - flag to control,
5077 //-hack has to be used.
5078 const bool bb4779636HackActive = true;
5079
5080 const SwFrame* pCellFrameForBottomBorderAttrs = nullptr;
5081 const SwFrame* pCellFrameForTopBorderAttrs = nullptr;
5082 bool bFoundCellForTopOrBorderAttrs = false;
5083 if ( bb4779636HackActive && IsCellFrame() )
5084 {
5085 pCellFrameForBottomBorderAttrs = lcl_GetCellFrameForBorderAttrs( this, rAttrs, false );
5086 if ( pCellFrameForBottomBorderAttrs != this )
5087 bFoundCellForTopOrBorderAttrs = true;
5088 pCellFrameForTopBorderAttrs = lcl_GetCellFrameForBorderAttrs( this, rAttrs, true );
5089 if ( pCellFrameForTopBorderAttrs != this )
5090 bFoundCellForTopOrBorderAttrs = true;
5091 }
5092
5093 // - add condition <bFoundCellForTopOrBorderAttrs>
5094 //-hack
5095 if ( !(bLine || bShadow || bFoundCellForTopOrBorderAttrs) )
5096 return;
5097
5098 //If the rectangle is completely inside the PrtArea, no border needs to
5099 //be painted.
5100 //For the PrtArea the aligned value needs to be used, otherwise it could
5101 //happen, that some parts won't be processed.
5102 SwRect aRect( getFramePrintArea() );
5103 aRect += getFrameArea().Pos();
5104 ::SwAlignRect( aRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
5105 // new local boolean variable in order to
5106 // suspend border paint under special cases - see below.
5107 // NOTE: This is a fix for the implementation of feature #99657#.
5108 bool bDrawOnlyShadowForTransparentFrame = false;
5109 if ( aRect.IsInside( rRect ) )
5110 {
5111 // paint shadow, if background is transparent.
5112 // Because of introduced transparent background for fly frame #99657#,
5113 // the shadow have to be drawn if the background is transparent,
5114 // in spite the fact that the paint rectangle <rRect> lies fully
5115 // in the printing area.
5116 // NOTE to chosen solution:
5117 // On transparent background, continue processing, but suspend
5118 // drawing of border by setting <bDrawOnlyShadowForTransparentFrame>
5119 // to true.
5120 if ( IsLayoutFrame() &&
5121 static_cast<const SwLayoutFrame*>(this)->GetFormat()->IsBackgroundTransparent() )
5122 {
5123 bDrawOnlyShadowForTransparentFrame = true;
5124 }
5125 else
5126 {
5127 return;
5128 }
5129 }
5130
5131 ::lcl_CalcBorderRect( aRect, this, rAttrs, true, gProp );
5132 rAttrs.SetGetCacheLine( true );
5133
5134 if(bShadow)
5135 {
5136 PaintShadow(rRect, aRect, rAttrs);
5137 }
5138
5139 // suspend drawing of border
5140 // add condition < NOT bDrawOnlyShadowForTransparentFrame > - see above
5141 // - add condition <bFoundCellForTopOrBorderAttrs>
5142 //-hack.
5143 if((bLine || bFoundCellForTopOrBorderAttrs) && !bDrawOnlyShadowForTransparentFrame)
5144 {
5145 // define SvxBorderLine(s) to use
5146 const SvxBoxItem& rBox(rAttrs.GetBox());
5147 const SvxBorderLine* pLeftBorder(rBox.GetLeft());
5148 const SvxBorderLine* pRightBorder(rBox.GetRight());
5149 const SvxBorderLine* pTopBorder(rBox.GetTop());
5150 const SvxBorderLine* pBottomBorder(rBox.GetBottom());
5151
5152 // if R2L, exchange Right/Left
5153 const bool bR2L(IsCellFrame() && IsRightToLeft());
5154
5155 if(bR2L)
5156 {
5157 std::swap(pLeftBorder, pRightBorder);
5158 }
5159
5160 // if ContentFrame and joined Prev/Next, reset top/bottom as needed
5161 if(IsContentFrame())
5162 {
5163 const SwFrame* pDirRefFrame(IsCellFrame() ? FindTabFrame() : this);
5164 const SwRectFnSet aRectFnSet(pDirRefFrame);
5165 const SwRectFn& _rRectFn(aRectFnSet.FnRect());
5166
5167 if(rAttrs.JoinedWithPrev(*this))
5168 {
5169 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5170 // existing gap to previous frame
5171 const SwFrame* pPrevFrame(GetPrev());
5172 (aRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
5173
5174 // ...and disable top border paint/creation
5175 pTopBorder = nullptr;
5176 }
5177
5178 if(rAttrs.JoinedWithNext(*this))
5179 {
5180 // tdf#115296 re-add adaptation of vert distance to close the evtl.
5181 // existing gap to next frame
5182 const SwFrame* pNextFrame(GetNext());
5183 (aRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
5184
5185 // ...and disable bottom border paint/creation
5186 pBottomBorder = nullptr;
5187 }
5188 }
5189
5190 // necessary to replace TopBorder?
5191 if((!IsContentFrame() || rAttrs.GetTopLine(*this)) && IsCellFrame() && pCellFrameForTopBorderAttrs != this)
5192 {
5193 SwBorderAttrAccess aAccess(SwFrame::GetCache(), pCellFrameForTopBorderAttrs);
5194 pTopBorder = aAccess.Get()->GetBox().GetTop();
5195 }
5196
5197 // necessary to replace BottomBorder?
5198 if((!IsContentFrame() || rAttrs.GetBottomLine(*this)) && IsCellFrame() && pCellFrameForBottomBorderAttrs != this)
5199 {
5200 SwBorderAttrAccess aAccess(SwFrame::GetCache(), pCellFrameForBottomBorderAttrs);
5201 pBottomBorder = aAccess.Get()->GetBox().GetBottom();
5202 }
5203
5204 if(nullptr != pLeftBorder || nullptr != pRightBorder || nullptr != pTopBorder || nullptr != pBottomBorder)
5205 {
5206 // now we have all SvxBorderLine(s) sorted out, create geometry
5207 const basegfx::B2DHomMatrix aBorderTransform(
5208 basegfx::utils::createScaleTranslateB2DHomMatrix(
5209 aRect.Width(), aRect.Height(),
5210 aRect.Left(), aRect.Top()));
5211 const svx::frame::Style aStyleTop(pTopBorder, 1.0);
5212 const svx::frame::Style aStyleRight(pRightBorder, 1.0);
5213 const svx::frame::Style aStyleBottom(pBottomBorder, 1.0);
5214 const svx::frame::Style aStyleLeft(pLeftBorder, 1.0);
5215 drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
5216
5217 aBorderLineTarget.append(
5218 drawinglayer::primitive2d::Primitive2DReference(
5219 new drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
5220 aBorderTransform,
5221 aStyleTop,
5222 aStyleRight,
5223 aStyleBottom,
5224 aStyleLeft)));
5225 gProp.pBLines->AddBorderLines(aBorderLineTarget);
5226 }
5227 }
5228
5229 rAttrs.SetGetCacheLine( false );
5230}
5231
5232/**
5233 * Special implementation because of the footnote line
5234 *
5235 * Currently only the top frame needs to be taken into account
5236 * Other lines and shadows are set aside
5237 */
5238void SwFootnoteContFrame::PaintSwFrameShadowAndBorder(
5239 const SwRect& rRect,
5240 const SwPageFrame* pPage,
5241 const SwBorderAttrs&) const
5242{
5243 //If the rectangle is completely inside the PrtArea, no border needs to
5244 //be painted.
5245 SwRect aRect( getFramePrintArea() );
5246 aRect.Pos() += getFrameArea().Pos();
5247 if ( !aRect.IsInside( rRect ) )
5248 PaintLine( rRect, pPage );
5249}
5250
5251/// Paint footnote lines.
5252void SwFootnoteContFrame::PaintLine( const SwRect& rRect,
5253 const SwPageFrame *pPage ) const
5254{
5255 //The length of the line is derived from the percentual indication on the
5256 //PageDesc. The position is also stated on the PageDesc.
5257 //The pen can directly be taken from the PageDesc.
5258
5259 if ( !pPage )
5260 pPage = FindPageFrame();
5261 const SwPageFootnoteInfo &rInf = pPage->GetPageDesc()->GetFootnoteInfo();
5262
5263 SwRectFnSet aRectFnSet(this);
5264 SwTwips nPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
5265 Fraction aFract( nPrtWidth, 1 );
5266 aFract *= rInf.GetWidth();
5267 const SwTwips nWidth = static_cast<long>(aFract);
5268
5269 SwTwips nX = aRectFnSet.GetPrtLeft(*this);
5270 switch ( rInf.GetAdj() )
5271 {
5272 case css::text::HorizontalAdjust_CENTER:
5273 nX += nPrtWidth/2 - nWidth/2; break;
5274 case css::text::HorizontalAdjust_RIGHT:
5275 nX += nPrtWidth - nWidth; break;
5276 case css::text::HorizontalAdjust_LEFT:
5277 /* do nothing */; break;
5278 default:
5279 SAL_WARN("sw.core", "New adjustment for footnote lines?")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sw.core")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "New adjustment for footnote lines?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"
), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5279" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "New adjustment for footnote lines?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "New adjustment for footnote lines?"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5279" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "New adjustment for footnote lines?") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5279" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "New adjustment for footnote lines?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "New adjustment for footnote lines?"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sw.core"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5279" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
5280 assert(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", "/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
, 5280, __extension__ __PRETTY_FUNCTION__))
;
5281 }
5282 SwTwips nLineWidth = rInf.GetLineWidth();
5283 const SwRect aLineRect = aRectFnSet.IsVert() ?
5284 SwRect( Point(getFrameArea().Left()+getFrameArea().Width()-rInf.GetTopDist()-nLineWidth,
5285 nX), Size( nLineWidth, nWidth ) )
5286 : SwRect( Point( nX, getFrameArea().Pos().Y() + rInf.GetTopDist() ),
5287 Size( nWidth, rInf.GetLineWidth()));
5288 if ( aLineRect.HasArea() && rInf.GetLineStyle() != SvxBorderLineStyle::NONE)
5289 PaintBorderLine( rRect, aLineRect , pPage, &rInf.GetLineColor(),
5290 rInf.GetLineStyle() );
5291}
5292
5293/// Paints the separator line for inside columns
5294void SwLayoutFrame::PaintColLines( const SwRect &rRect, const SwFormatCol &rFormatCol,
5295 const SwPageFrame *pPage ) const
5296{
5297 const SwFrame *pCol = Lower();
5298 if ( !pCol || !pCol->IsColumnFrame() )
5299 return;
5300
5301 SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? (pCol->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
5302
5303 SwRect aLineRect = getFramePrintArea();
5304 aLineRect += getFrameArea().Pos();
5305
5306 SwTwips nTop = ((aLineRect.*fnRect->fnGetHeight)()*rFormatCol.GetLineHeight())
5307 / 100 - (aLineRect.*fnRect->fnGetHeight)();
5308 SwTwips nBottom = 0;
5309
5310 switch ( rFormatCol.GetLineAdj() )
5311 {
5312 case COLADJ_CENTER:
5313 nBottom = nTop / 2; nTop -= nBottom; break;
5314 case COLADJ_TOP:
5315 nBottom = nTop; nTop = 0; break;
5316 case COLADJ_BOTTOM:
5317 break;
5318 default:
5319 OSL_ENSURE( false, "New adjustment for column lines?" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "5319" ": "), "%s", "New adjustment for column lines?");
} } while (false)
;
5320 }
5321
5322 if( nTop )
5323 (aLineRect.*fnRect->fnSubTop)( nTop );
5324 if( nBottom )
5325 (aLineRect.*fnRect->fnAddBottom)( nBottom );
5326
5327 SwTwips nPenHalf = rFormatCol.GetLineWidth();
5328 (aLineRect.*fnRect->fnSetWidth)( nPenHalf );
5329 nPenHalf /= 2;
5330
5331 //We need to be a bit generous here, to not lose something.
5332 SwRect aRect( rRect );
5333 (aRect.*fnRect->fnSubLeft)( nPenHalf + gProp.nSPixelSzW );
5334 (aRect.*fnRect->fnAddRight)( nPenHalf + gProp.nSPixelSzW );
5335 SwRectGet fnGetX = IsRightToLeft() ? fnRect->fnGetLeft : fnRect->fnGetRight;
5336 while ( pCol->GetNext() )
5337 {
5338 (aLineRect.*fnRect->fnSetPosX)
5339 ( (pCol->getFrameArea().*fnGetX)() - nPenHalf );
5340 if ( aRect.IsOver( aLineRect ) )
5341 PaintBorderLine( aRect, aLineRect , pPage, &rFormatCol.GetLineColor(),
5342 rFormatCol.GetLineStyle() );
5343 pCol = pCol->GetNext();
5344 }
5345}
5346
5347void SwPageFrame::PaintGrid( OutputDevice const * pOut, SwRect const &rRect ) const
5348{
5349 if( !m_bHasGrid || gProp.pSRetoucheFly || gProp.pSRetoucheFly2 )
5350 return;
5351 SwTextGridItem const*const pGrid(GetGridItem(this));
5352 if( !(pGrid && ( OUTDEV_PRINTER != pOut->GetOutDevType() ?
5353 pGrid->GetDisplayGrid() : pGrid->GetPrintGrid() )) )
5354 return;
5355
5356 const SwLayoutFrame* pBody = FindBodyCont();
5357 if( !pBody )
5358 return;
5359
5360 SwRect aGrid( pBody->getFramePrintArea() );
5361 aGrid += pBody->getFrameArea().Pos();
5362
5363 SwRect aInter( aGrid );
5364 aInter.Intersection( rRect );
5365 if( !aInter.HasArea() )
5366 return;
5367
5368 bool bGrid = pGrid->GetRubyTextBelow();
5369 bool bCell = GRID_LINES_CHARS == pGrid->GetGridType();
5370 long nGrid = pGrid->GetBaseHeight();
5371 const SwDoc* pDoc = GetFormat()->GetDoc();
5372 long nGridWidth = GetGridWidth(*pGrid, *pDoc);
5373 long nRuby = pGrid->GetRubyHeight();
5374 long nSum = nGrid + nRuby;
5375 const Color *pCol = &pGrid->GetColor();
5376
5377 SwTwips nRight = aInter.Left() + aInter.Width();
5378 SwTwips nBottom = aInter.Top() + aInter.Height();
5379 if( IsVertical() )
5380 {
5381 SwTwips nOrig = aGrid.Left() + aGrid.Width();
5382 SwTwips nY = nOrig + nSum *
5383 ( ( nOrig - aInter.Left() ) / nSum );
5384 SwRect aTmp( Point( nY, aInter.Top() ),
5385 Size( 1, aInter.Height() ) );
5386 SwTwips nX = aGrid.Top() + nGrid *
5387 ( ( aInter.Top() - aGrid.Top() )/ nGrid );
5388 if( nX < aInter.Top() )
5389 nX += nGrid;
5390 SwTwips nGridBottom = aGrid.Top() + aGrid.Height();
5391 bool bLeft = aGrid.Top() >= aInter.Top();
5392 bool bRight = nGridBottom <= nBottom;
5393 bool bBorder = bLeft || bRight;
5394 while( nY > nRight )
5395 {
5396 aTmp.Pos().setX( nY );
5397 if( bGrid )
5398 {
5399 nY -= nGrid;
5400 SwTwips nPosY = std::max( aInter.Left(), nY );
5401 SwTwips nHeight = std::min(nRight, aTmp.Pos().X())-nPosY;
5402 if( nHeight > 0 )
5403 {
5404 if( bCell )
5405 {
5406 SwRect aVert( Point( nPosY, nX ),
5407 Size( nHeight, 1 ) );
5408 while( aVert.Top() <= nBottom )
5409 {
5410 PaintBorderLine(rRect,aVert,this,pCol);
5411 aVert.Pos().AdjustY(nGrid );
5412 }
5413 }
5414 else if( bBorder )
5415 {
5416 SwRect aVert( Point( nPosY, aGrid.Top() ),
5417 Size( nHeight, 1 ) );
5418 if( bLeft )
5419 PaintBorderLine(rRect,aVert,this,pCol);
5420 if( bRight )
5421 {
5422 aVert.Pos().setY( nGridBottom );
5423 PaintBorderLine(rRect,aVert,this,pCol);
5424 }
5425 }
5426 }
5427 }
5428 else
5429 {
5430 nY -= nRuby;
5431 if( bBorder )
5432 {
5433 SwTwips nPos = std::max( aInter.Left(), nY );
5434 SwTwips nW = std::min(nRight, aTmp.Pos().X()) - nPos;
5435 SwRect aVert( Point( nPos, aGrid.Top() ),
5436 Size( nW, 1 ) );
5437 if( nW > 0 )
5438 {
5439 if( bLeft )
5440 PaintBorderLine(rRect,aVert,this,pCol);
5441 if( bRight )
5442 {
5443 aVert.Pos().setY( nGridBottom );
5444 PaintBorderLine(rRect,aVert,this,pCol);
5445 }
5446 }
5447 }
5448 }
5449 bGrid = !bGrid;
5450 }
5451 while( nY >= aInter.Left() )
5452 {
5453 aTmp.Pos().setX( nY );
5454 PaintBorderLine( rRect, aTmp, this, pCol);
5455 if( bGrid )
5456 {
5457 nY -= nGrid;
5458 SwTwips nHeight = aTmp.Pos().X()
5459 - std::max(aInter.Left(), nY );
5460 if( nHeight > 0 )
5461 {
5462 if( bCell )
5463 {
5464 SwRect aVert( Point(aTmp.Pos().X()-nHeight,
5465 nX ), Size( nHeight, 1 ) );
5466 while( aVert.Top() <= nBottom )
5467 {
5468 PaintBorderLine(rRect,aVert,this,pCol);
5469 aVert.Pos().AdjustY(nGrid );
5470 }
5471 }
5472 else if( bBorder )
5473 {
5474 SwRect aVert( Point(aTmp.Pos().X()-nHeight,
5475 aGrid.Top() ), Size( nHeight, 1 ) );
5476 if( bLeft )
5477 PaintBorderLine(rRect,aVert,this,pCol);
5478 if( bRight )
5479 {
5480 aVert.Pos().setY( nGridBottom );
5481 PaintBorderLine(rRect,aVert,this,pCol);
5482 }
5483 }
5484 }
5485 }
5486 else
5487 {
5488 nY -= nRuby;
5489 if( bBorder )
5490 {
5491 SwTwips nPos = std::max( aInter.Left(), nY );
5492 SwTwips nW = std::min(nRight, aTmp.Pos().X()) - nPos;
5493 SwRect aVert( Point( nPos, aGrid.Top() ),
5494 Size( nW, 1 ) );
5495 if( nW > 0 )
5496 {
5497 if( bLeft )
5498 PaintBorderLine(rRect,aVert,this,pCol);
5499 if( bRight )
5500 {
5501 aVert.Pos().setY( nGridBottom );
5502 PaintBorderLine(rRect,aVert,this,pCol);
5503 }
5504 }
5505 }
5506 }
5507 bGrid = !bGrid;
5508 }
5509 }
5510 else
5511 {
5512 SwTwips nOrig = aGrid.Top();
5513 SwTwips nY = nOrig + nSum *( (aInter.Top()-nOrig)/nSum );
5514 SwRect aTmp( Point( aInter.Left(), nY ),
5515 Size( aInter.Width(), 1 ) );
5516 //for textgrid refactor
5517 SwTwips nX = aGrid.Left() + nGridWidth *
5518 ( ( aInter.Left() - aGrid.Left() )/ nGridWidth );
5519 if( nX < aInter.Left() )
5520 nX += nGridWidth;
5521 SwTwips nGridRight = aGrid.Left() + aGrid.Width();
5522 bool bLeft = aGrid.Left() >= aInter.Left();
5523 bool bRight = nGridRight <= nRight;
5524 bool bBorder = bLeft || bRight;
5525 while( nY < aInter.Top() )
5526 {
5527 aTmp.Pos().setY(nY);
5528 if( bGrid )
5529 {
5530 nY += nGrid;
5531 SwTwips nPosY = std::max( aInter.Top(), aTmp.Pos().getY() );
5532 SwTwips nHeight = std::min(nBottom, nY ) - nPosY;
5533 if( nHeight )
5534 {
5535 if( bCell )
5536 {
5537 SwRect aVert( Point( nX, nPosY ),
5538 Size( 1, nHeight ) );
5539 while( aVert.Left() <= nRight )
5540 {
5541 PaintBorderLine(rRect,aVert,this,pCol);
5542 aVert.Pos().AdjustX(nGridWidth ); //for textgrid refactor
5543 }
5544 }
5545 else if ( bBorder )
5546 {
5547 SwRect aVert( Point( aGrid.Left(), nPosY ),
5548 Size( 1, nHeight ) );
5549 if( bLeft )
5550 PaintBorderLine(rRect,aVert,this,pCol);
5551 if( bRight )
5552 {
5553 aVert.Pos().setX( nGridRight );
5554 PaintBorderLine(rRect,aVert,this,pCol);
5555 }
5556 }
5557 }
5558 }
5559 else
5560 {
5561 nY += nRuby;
5562 if( bBorder )
5563 {
5564 SwTwips nPos = std::max(aInter.Top(),aTmp.Pos().getY());
5565 SwTwips nH = std::min( nBottom, nY ) - nPos;
5566 SwRect aVert( Point( aGrid.Left(), nPos ),
5567 Size( 1, nH ) );
5568 if( nH > 0 )
5569 {
5570 if( bLeft )
5571 PaintBorderLine(rRect,aVert,this,pCol);
5572 if( bRight )
5573 {
5574 aVert.Pos().setX(nGridRight);
5575 PaintBorderLine(rRect,aVert,this,pCol);
5576 }
5577 }
5578 }
5579 }
5580 bGrid = !bGrid;
5581 }
5582 while( nY <= nBottom )
5583 {
5584 aTmp.Pos().setY(nY);
5585 PaintBorderLine( rRect, aTmp, this, pCol);
5586 if( bGrid )
5587 {
5588 nY += nGrid;
5589 SwTwips nHeight = std::min(nBottom, nY) - aTmp.Pos().getY();
5590 if( nHeight )
5591 {
5592 if( bCell )
5593 {
5594 SwRect aVert( Point( nX, aTmp.Pos().getY() ),
5595 Size( 1, nHeight ) );
5596 while( aVert.Left() <= nRight )
5597 {
5598 PaintBorderLine( rRect, aVert, this, pCol);
5599 aVert.Pos().setX(aVert.Pos().getX() + nGridWidth); //for textgrid refactor
5600 }
5601 }
5602 else if( bBorder )
5603 {
5604 SwRect aVert( Point( aGrid.Left(),
5605 aTmp.Pos().getY() ), Size( 1, nHeight ) );
5606 if( bLeft )
5607 PaintBorderLine(rRect,aVert,this,pCol);
5608 if( bRight )
5609 {
5610 aVert.Pos().setX(nGridRight);
5611 PaintBorderLine(rRect,aVert,this,pCol);
5612 }
5613 }
5614 }
5615 }
5616 else
5617 {
5618 nY += nRuby;
5619 if( bBorder )
5620 {
5621 SwTwips nPos = std::max(aInter.Top(),aTmp.Pos().Y());
5622 SwTwips nH = std::min( nBottom, nY ) - nPos;
5623 SwRect aVert( Point( aGrid.Left(), nPos ),
5624 Size( 1, nH ) );
5625 if( nH > 0 )
5626 {
5627 if( bLeft )
5628 PaintBorderLine(rRect,aVert,this,pCol);
5629 if( bRight )
5630 {
5631 aVert.Pos().setX(nGridRight);
5632 PaintBorderLine(rRect,aVert,this,pCol);
5633 }
5634 }
5635 }
5636 }
5637 bGrid = !bGrid;
5638 }
5639 }
5640}
5641
5642/**
5643 * Paint margin area of a page
5644 *
5645 * OD 20.11.2002 for #104598#:
5646 * implement paint of margin area; margin area will be painted for a
5647 * view shell with a window and if the document is not in online layout.
5648 *
5649 * @param _rOutputRect
5650 * input parameter - constant instance reference of the rectangle, for
5651 * which an output has to be generated.
5652 *
5653 * @param _pViewShell
5654 * input parameter - instance of the view shell, on which the output
5655 * has to be generated.
5656 */
5657void SwPageFrame::PaintMarginArea( const SwRect& _rOutputRect,
5658 SwViewShell const * _pViewShell ) const
5659{
5660 if ( !_pViewShell->GetWin() || _pViewShell->GetViewOptions()->getBrowseMode() )
5661 return;
5662
5663 // Simplified paint with DrawingLayer FillStyle
5664 SwRect aPgRect = getFrameArea();
5665 aPgRect.Intersection_( _rOutputRect );
5666
5667 if(!aPgRect.IsEmpty())
5668 {
5669 OutputDevice *pOut = _pViewShell->GetOut();
5670
5671 if(pOut->GetFillColor() != aGlobalRetoucheColor)
5672 {
5673 pOut->SetFillColor(aGlobalRetoucheColor);
5674 }
5675
5676 pOut->DrawRect(aPgRect.SVRect());
5677 }
5678}
5679
5680const sal_Int8 SwPageFrame::mnShadowPxWidth = 9;
5681
5682bool SwPageFrame::IsRightShadowNeeded() const
5683{
5684 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
5685 const bool bIsLTR = getRootFrame()->IsLeftToRightViewLayout();
5686
5687 // We paint the right shadow if we're not in book mode
5688 // or if we've no sibling or are the last page of the "row"
5689 return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetNext()
5690 || (this == Lower()) || (bIsLTR && OnRightPage())
5691 || (!bIsLTR && !OnRightPage());
5692
5693}
5694
5695bool SwPageFrame::IsLeftShadowNeeded() const
5696{
5697 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
5698 const bool bIsLTR = getRootFrame()->IsLeftToRightViewLayout();
5699
5700 // We paint the left shadow if we're not in book mode
5701 // or if we've no sibling or are the last page of the "row"
5702 return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetPrev()
5703 || (bIsLTR && !OnRightPage())
5704 || (!bIsLTR && OnRightPage());
5705}
5706
5707/**
5708 * Determine rectangle for bottom page shadow
5709 * for #i9719#
5710 */
5711/*static*/ void SwPageFrame::GetHorizontalShadowRect( const SwRect& _rPageRect,
5712 const SwViewShell* _pViewShell,
5713 OutputDevice const * pRenderContext,
5714 SwRect& _orHorizontalShadowRect,
5715 bool bPaintLeftShadow,
5716 bool bPaintRightShadow,
5717 bool bRightSidebar )
5718{
5719 const SwPostItMgr *pMgr = _pViewShell->GetPostItMgr();
5720 SwRect aAlignedPageRect( _rPageRect );
5721 ::SwAlignRect( aAlignedPageRect, _pViewShell, pRenderContext );
5722 SwRect aPagePxRect = pRenderContext->LogicToPixel( aAlignedPageRect.SVRect() );
5723
5724 long lShadowAdjustment = mnShadowPxWidth - 1; // TODO: extract this
5725
5726 _orHorizontalShadowRect.Chg(
5727 Point( aPagePxRect.Left() + (bPaintLeftShadow ? lShadowAdjustment : 0), 0 ),
5728 Size( aPagePxRect.Width() - ( (bPaintLeftShadow ? lShadowAdjustment : 0) + (bPaintRightShadow ? lShadowAdjustment : 0) ),
5729 mnShadowPxWidth ) );
5730
5731 if(pMgr && pMgr->ShowNotes() && pMgr->HasNotes())
5732 {
5733 // Notes are displayed, we've to extend borders
5734 SwTwips aSidebarTotalWidth = pMgr->GetSidebarWidth(true) + pMgr->GetSidebarBorderWidth(true);
5735 if(bRightSidebar)
5736 _orHorizontalShadowRect.AddRight( aSidebarTotalWidth );
5737 else
5738 _orHorizontalShadowRect.AddLeft( - aSidebarTotalWidth );
5739 }
5740}
5741
5742namespace {
5743
5744enum PaintArea {LEFT, RIGHT, TOP, BOTTOM};
5745
5746}
5747
5748#define BORDER_TILE_SIZE512 512
5749
5750/// Wrapper around pOut->DrawBitmapEx.
5751static void lcl_paintBitmapExToRect(vcl::RenderContext *pOut, const Point& aPoint, const Size& aSize, const BitmapEx& rBitmapEx, PaintArea eArea)
5752{
5753 // The problem is that if we get called multiple times and the color is
5754 // partly transparent, then the result will get darker and darker. To avoid
5755 // this, always paint the background color before doing the real paint.
5756 tools::Rectangle aRect(aPoint, aSize);
5757
5758 if (!aRect.IsEmpty())
5759 {
5760 switch (eArea)
5761 {
5762 case LEFT: aRect.SetLeft( aRect.Right() - 1 ); break;
5763 case RIGHT: aRect.SetRight( aRect.Left() + 1 ); break;
5764 case TOP: aRect.SetTop( aRect.Bottom() - 1 ); break;
5765 case BOTTOM: aRect.SetBottom( aRect.Top() + 1 ); break;
5766 }
5767 }
5768
5769 pOut->SetFillColor(SwViewOption::GetAppBackgroundColor());
5770 pOut->SetLineColor();
5771 pOut->DrawRect(pOut->PixelToLogic(aRect));
5772
5773 // Tiled render if necessary
5774 tools::Rectangle aComplete(aPoint, aSize);
5775 Size aTileSize(BORDER_TILE_SIZE512, BORDER_TILE_SIZE512);
5776
5777 long iterX = eArea != RIGHT && eArea != LEFT ? BORDER_TILE_SIZE512 : 0;
5778 long iterY = eArea == RIGHT || eArea == LEFT ? BORDER_TILE_SIZE512 : 0;
5779
5780 for (tools::Rectangle aTile(aPoint, aTileSize); true; aTile.Move(iterX, iterY))
5781 {
5782 tools::Rectangle aRender = aComplete.GetIntersection(aTile);
5783 if (aRender.IsEmpty())
5784 break;
5785 pOut->DrawBitmapEx(pOut->PixelToLogic(aRender.TopLeft()),
5786 pOut->PixelToLogic(aRender.GetSize()),
5787 Point(0, 0), aRender.GetSize(),
5788 rBitmapEx);
5789 }
5790
5791}
5792
5793/**
5794 * Paint page border and shadow
5795 *
5796 * for #i9719#
5797 * implement paint of page border and shadow
5798*/
5799/*static*/ void SwPageFrame::PaintBorderAndShadow( const SwRect& _rPageRect,
5800 const SwViewShell* _pViewShell,
5801 bool bPaintLeftShadow,
5802 bool bPaintRightShadow,
5803 bool bRightSidebar )
5804{
5805 // No shadow in prefs
5806 if (!SwViewOption::IsShadow())
5807 return;
5808
5809 // #i16816# tagged pdf support
5810 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *_pViewShell->GetOut() );
5811
5812 static vcl::DeleteOnDeinit<drawinglayer::primitive2d::DiscreteShadow> shadowMaskObj(
5813 new drawinglayer::primitive2d::DiscreteShadow(
5814 vcl::bitmap::loadFromName(BMP_PAGE_SHADOW_MASK"sw/res/page-shadow-mask.png",
5815 ImageLoadFlags::IgnoreDarkTheme | ImageLoadFlags::IgnoreScalingFactor)));
5816
5817 drawinglayer::primitive2d::DiscreteShadow& shadowMask = *shadowMaskObj.get();
5818 static vcl::DeleteOnDeinit< BitmapEx > aPageTopRightShadowObj( new BitmapEx );
5819 static vcl::DeleteOnDeinit< BitmapEx > aPageBottomRightShadowObj( new BitmapEx );
5820 static vcl::DeleteOnDeinit< BitmapEx > aPageBottomLeftShadowObj( new BitmapEx );
5821 static vcl::DeleteOnDeinit< BitmapEx > aPageBottomShadowBaseObj( new BitmapEx );
5822 static vcl::DeleteOnDeinit< BitmapEx > aPageRightShadowBaseObj( new BitmapEx );
5823 static vcl::DeleteOnDeinit< BitmapEx > aPageTopShadowBaseObj( new BitmapEx );
5824 static vcl::DeleteOnDeinit< BitmapEx > aPageTopLeftShadowObj( new BitmapEx );
5825 static vcl::DeleteOnDeinit< BitmapEx > aPageLeftShadowBaseObj( new BitmapEx );
5826 BitmapEx& aPageTopRightShadow = *aPageTopRightShadowObj.get();
5827 BitmapEx& aPageBottomRightShadow = *aPageBottomRightShadowObj.get();
5828 BitmapEx& aPageBottomLeftShadow = *aPageBottomLeftShadowObj.get();
5829 BitmapEx& aPageBottomShadow = *aPageBottomShadowBaseObj.get();
5830 BitmapEx& aPageRightShadow = *aPageRightShadowBaseObj.get();
5831 BitmapEx& aPageTopShadow = *aPageTopShadowBaseObj.get();
5832 BitmapEx& aPageTopLeftShadow = *aPageTopLeftShadowObj.get();
5833 BitmapEx& aPageLeftShadow = *aPageLeftShadowBaseObj.get();
5834 static Color aShadowColor( COL_AUTO );
5835
5836 SwRect aAlignedPageRect( _rPageRect );
5837 ::SwAlignRect( aAlignedPageRect, _pViewShell, _pViewShell->GetOut() );
5838 SwRect aPagePxRect = _pViewShell->GetOut()->LogicToPixel( aAlignedPageRect.SVRect() );
5839
5840 if (aShadowColor != SwViewOption::GetShadowColor())
5841 {
5842 aShadowColor = SwViewOption::GetShadowColor();
5843
5844 AlphaMask aMask( shadowMask.getBottomRight().GetBitmap() );
5845 Bitmap aFilledSquare( aMask.GetSizePixel(), 24 );
5846 aFilledSquare.Erase( aShadowColor );
5847 aPageBottomRightShadow = BitmapEx( aFilledSquare, aMask );
5848
5849 aMask = AlphaMask( shadowMask.getBottomLeft().GetBitmap() );
5850 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5851 aFilledSquare.Erase( aShadowColor );
5852 aPageBottomLeftShadow = BitmapEx( aFilledSquare, aMask );
5853
5854 aMask = AlphaMask( shadowMask.getBottom().GetBitmap() );
5855 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5856 aFilledSquare.Erase( aShadowColor );
5857 aPageBottomShadow = BitmapEx( aFilledSquare, aMask );
5858
5859 aMask = AlphaMask( shadowMask.getTop().GetBitmap() );
5860 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5861 aFilledSquare.Erase( aShadowColor );
5862 aPageTopShadow = BitmapEx( aFilledSquare, aMask );
5863
5864 aMask = AlphaMask( shadowMask.getTopRight().GetBitmap() );
5865 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5866 aFilledSquare.Erase( aShadowColor );
5867 aPageTopRightShadow = BitmapEx( aFilledSquare, aMask );
5868
5869 aMask = AlphaMask( shadowMask.getRight().GetBitmap() );
5870 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5871 aFilledSquare.Erase( aShadowColor );
5872 aPageRightShadow = BitmapEx( aFilledSquare, aMask );
5873
5874 aMask = AlphaMask( shadowMask.getTopLeft().GetBitmap() );
5875 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5876 aFilledSquare.Erase( aShadowColor );
5877 aPageTopLeftShadow = BitmapEx( aFilledSquare, aMask );
5878
5879 aMask = AlphaMask( shadowMask.getLeft().GetBitmap() );
5880 aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 );
5881 aFilledSquare.Erase( aShadowColor );
5882 aPageLeftShadow = BitmapEx( aFilledSquare, aMask );
5883 }
5884
5885 SwRect aPaintRect;
5886 OutputDevice *pOut = _pViewShell->GetOut();
5887
5888 SwPageFrame::GetHorizontalShadowRect( _rPageRect, _pViewShell, pOut, aPaintRect, bPaintLeftShadow, bPaintRightShadow, bRightSidebar );
5889
5890 // Right shadow & corners
5891 if ( bPaintRightShadow )
5892 {
5893 pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Right(), aPagePxRect.Bottom() + 1 - (aPageBottomRightShadow.GetSizePixel().Height() - mnShadowPxWidth) ) ),
5894 aPageBottomRightShadow );
5895 pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Right(), aPagePxRect.Top() - mnShadowPxWidth ) ),
5896 aPageTopRightShadow );
5897
5898 if (aPagePxRect.Height() > 2 * mnShadowPxWidth)
5899 {
5900 const long nWidth = aPageRightShadow.GetSizePixel().Width();
5901 const long nHeight = aPagePxRect.Height() - 2 * (mnShadowPxWidth - 1);
5902 if (aPageRightShadow.GetSizePixel().Height() < BORDER_TILE_SIZE512)
5903 aPageRightShadow.Scale(Size(nWidth, BORDER_TILE_SIZE512), BmpScaleFlag::Fast);
5904
5905 lcl_paintBitmapExToRect(pOut,
5906 Point(aPaintRect.Right() + mnShadowPxWidth, aPagePxRect.Top() + mnShadowPxWidth - 1),
5907 Size(nWidth, nHeight),
5908 aPageRightShadow, RIGHT);
5909 }
5910 }
5911
5912 // Left shadows and corners
5913 if(bPaintLeftShadow)
5914 {
5915 const long lLeft = aPaintRect.Left() - aPageBottomLeftShadow.GetSizePixel().Width();
5916 pOut->DrawBitmapEx( pOut->PixelToLogic( Point( lLeft,
5917 aPagePxRect.Bottom() + 1 + mnShadowPxWidth - aPageBottomLeftShadow.GetSizePixel().Height() ) ), aPageBottomLeftShadow );
5918 pOut->DrawBitmapEx( pOut->PixelToLogic( Point( lLeft, aPagePxRect.Top() - mnShadowPxWidth ) ), aPageTopLeftShadow );
5919 if (aPagePxRect.Height() > 2 * mnShadowPxWidth)
5920 {
5921 const long nWidth = aPageLeftShadow.GetSizePixel().Width();
5922 const long nHeight = aPagePxRect.Height() - 2 * (mnShadowPxWidth - 1);
5923 if (aPageLeftShadow.GetSizePixel().Height() < BORDER_TILE_SIZE512)
5924 aPageLeftShadow.Scale(Size(nWidth, BORDER_TILE_SIZE512), BmpScaleFlag::Fast);
5925
5926 lcl_paintBitmapExToRect(pOut,
5927 Point(lLeft, aPagePxRect.Top() + mnShadowPxWidth - 1),
5928 Size(nWidth, nHeight),
5929 aPageLeftShadow, LEFT);
5930 }
5931 }
5932
5933 // Bottom shadow
5934 const long nBottomHeight = aPageBottomShadow.GetSizePixel().Height();
5935 if (aPageBottomShadow.GetSizePixel().Width() < BORDER_TILE_SIZE512)
5936 aPageBottomShadow.Scale(Size(BORDER_TILE_SIZE512, nBottomHeight), BmpScaleFlag::Fast);
5937
5938 lcl_paintBitmapExToRect(pOut,
5939 Point(aPaintRect.Left(), aPagePxRect.Bottom() + 2),
5940 Size(aPaintRect.Width(), nBottomHeight),
5941 aPageBottomShadow, BOTTOM);
5942
5943 // Top shadow
5944 const long nTopHeight = aPageTopShadow.GetSizePixel().Height();
5945 if (aPageTopShadow.GetSizePixel().Width() < BORDER_TILE_SIZE512)
5946 aPageTopShadow.Scale(Size(BORDER_TILE_SIZE512, nTopHeight), BmpScaleFlag::Fast);
5947
5948 lcl_paintBitmapExToRect(pOut,
5949 Point(aPaintRect.Left(), aPagePxRect.Top() - mnShadowPxWidth),
5950 Size(aPaintRect.Width(), nTopHeight),
5951 aPageTopShadow, TOP);
5952}
5953
5954/**
5955 * mod #i6193# paint sidebar for notes
5956 * IMPORTANT: if you change the rects here, also change SwPostItMgr::ScrollbarHit
5957 */
5958/*static*/void SwPageFrame::PaintNotesSidebar(const SwRect& _rPageRect, SwViewShell* _pViewShell, sal_uInt16 nPageNum, bool bRight)
5959{
5960 //TODO: cut out scrollbar area and arrows out of sidepane rect, otherwise it could flicker when pressing arrow buttons
5961 if (!_pViewShell )
5962 return;
5963
5964 SwRect aPageRect( _rPageRect );
5965 SwAlignRect( aPageRect, _pViewShell, _pViewShell->GetOut() );
5966
5967 const SwPostItMgr *pMgr = _pViewShell->GetPostItMgr();
5968 if (!(pMgr && pMgr->ShowNotes() && pMgr->HasNotes())) // do not show anything in print preview
5969 return;
5970
5971 sal_Int32 nScrollerHeight = pMgr->GetSidebarScrollerHeight();
5972 const tools::Rectangle &aVisRect = _pViewShell->VisArea().SVRect();
5973 //draw border and sidepane
5974 _pViewShell->GetOut()->SetLineColor();
5975 if (!bRight)
5976 {
5977 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_BORDERColor(200,200,200));
5978 _pViewShell->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height()))) ;
5979 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
5980 _pViewShell->GetOut()->SetFillColor(COL_BLACK);
5981 else
5982 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANEColor(230,230,230));
5983 _pViewShell->GetOut()->DrawRect(tools::Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarWidth()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height()))) ;
5984 }
5985 else
5986 {
5987 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_BORDERColor(200,200,200));
5988 SwRect aSidebarBorder(aPageRect.TopRight(),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height()));
5989 _pViewShell->GetOut()->DrawRect(aSidebarBorder.SVRect());
5990 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
5991 _pViewShell->GetOut()->SetFillColor(COL_BLACK);
5992 else
5993 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANEColor(230,230,230));
5994 SwRect aSidebar(Point(aPageRect.Right()+pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height()));
5995 _pViewShell->GetOut()->DrawRect(aSidebar.SVRect());
5996 }
5997 if (!pMgr->ShowScrollbar(nPageNum))
5998 return;
5999
6000 // draw scrollbar area and arrows
6001 Point aPointBottom;
6002 Point aPointTop;
6003 aPointBottom = !bRight ? Point(aPageRect.Left() - pMgr->GetSidebarWidth() - pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- _pViewShell->GetOut()->PixelToLogic(Size(0,2+pMgr->GetSidebarScrollerHeight())).Height()) :
6004 Point(aPageRect.Right() + pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- _pViewShell->GetOut()->PixelToLogic(Size(0,2+pMgr->GetSidebarScrollerHeight())).Height());
6005 aPointTop = !bRight ? Point(aPageRect.Left() - pMgr->GetSidebarWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + _pViewShell->GetOut()->PixelToLogic(Size(0,2)).Height()) :
6006 Point(aPageRect.Right() + pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + _pViewShell->GetOut()->PixelToLogic(Size(0,2)).Height());
6007 Size aSize(pMgr->GetSidebarWidth() - _pViewShell->GetOut()->PixelToLogic(Size(4,0)).Width(), _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()) ;
6008 tools::Rectangle aRectBottom(aPointBottom,aSize);
6009 tools::Rectangle aRectTop(aPointTop,aSize);
6010
6011 if (aRectBottom.IsOver(aVisRect))
6012 {
6013
6014 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6015 {
6016 _pViewShell->GetOut()->SetLineColor(COL_WHITE);
6017 _pViewShell->GetOut()->SetFillColor(COL_BLACK);
6018 }
6019 else
6020 {
6021 _pViewShell->GetOut()->SetLineColor(COL_BLACK);
6022 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_SCROLLAREAColor(230,230,220));
6023 }
6024 _pViewShell->GetOut()->DrawRect(aRectBottom);
6025 _pViewShell->GetOut()->DrawLine(aPointBottom + Point(pMgr->GetSidebarWidth()/3,0), aPointBottom + Point(pMgr->GetSidebarWidth()/3 , _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()));
6026
6027 _pViewShell->GetOut()->SetLineColor();
6028 Point aMiddleFirst(aPointBottom + Point(pMgr->GetSidebarWidth()/6,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
6029 Point aMiddleSecond(aPointBottom + Point(pMgr->GetSidebarWidth()/3*2,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
6030 PaintNotesSidebarArrows(aMiddleFirst,aMiddleSecond,_pViewShell,pMgr->GetArrowColor(KEY_PAGEUP,nPageNum), pMgr->GetArrowColor(KEY_PAGEDOWN,nPageNum));
6031 }
6032 if (!aRectTop.IsOver(aVisRect))
6033 return;
6034
6035 if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
6036 {
6037 _pViewShell->GetOut()->SetLineColor(COL_WHITE);
6038 _pViewShell->GetOut()->SetFillColor(COL_BLACK);
6039 }
6040 else
6041 {
6042 _pViewShell->GetOut()->SetLineColor(COL_BLACK);
6043 _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_SCROLLAREAColor(230,230,220));
6044 }
6045 _pViewShell->GetOut()->DrawRect(aRectTop);
6046 _pViewShell->GetOut()->DrawLine(aPointTop + Point(pMgr->GetSidebarWidth()/3*2,0), aPointTop + Point(pMgr->GetSidebarWidth()/3*2 , _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()));
6047
6048 _pViewShell->GetOut()->SetLineColor();
6049 Point aMiddleFirst(aPointTop + Point(pMgr->GetSidebarWidth()/3,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
6050 Point aMiddleSecond(aPointTop + Point(pMgr->GetSidebarWidth()/6*5,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2));
6051 PaintNotesSidebarArrows(aMiddleFirst,aMiddleSecond,_pViewShell, pMgr->GetArrowColor(KEY_PAGEUP,nPageNum), pMgr->GetArrowColor(KEY_PAGEDOWN,nPageNum));
6052}
6053
6054/*static*/ void SwPageFrame::PaintNotesSidebarArrows(const Point &aMiddleFirst, const Point &aMiddleSecond, SwViewShell const * _pViewShell, const Color& rColorUp, const Color& rColorDown)
6055{
6056 tools::Polygon aTriangleUp(3);
6057 tools::Polygon aTriangleDown(3);
6058
6059 aTriangleUp.SetPoint(aMiddleFirst + Point(0,_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6060 aTriangleUp.SetPoint(aMiddleFirst + Point(_pViewShell->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),1);
6061 aTriangleUp.SetPoint(aMiddleFirst + Point(_pViewShell->GetOut()->PixelToLogic(Size(3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6062
6063 aTriangleDown.SetPoint(aMiddleSecond + Point(_pViewShell->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),0);
6064 aTriangleDown.SetPoint(aMiddleSecond + Point(_pViewShell->GetOut()->PixelToLogic(Size(+3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),1);
6065 aTriangleDown.SetPoint(aMiddleSecond + Point(0,_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),2);
6066
6067 _pViewShell->GetOut()->SetFillColor(rColorUp);
6068 _pViewShell->GetOut()->DrawPolygon(aTriangleUp);
6069 _pViewShell->GetOut()->SetFillColor(rColorDown);
6070 _pViewShell->GetOut()->DrawPolygon(aTriangleDown);
6071}
6072
6073/**
6074 * Get bound rectangle of border and shadow for repaints
6075 *
6076 * for #i9719#
6077 */
6078/*static*/ void SwPageFrame::GetBorderAndShadowBoundRect( const SwRect& _rPageRect,
6079 const SwViewShell* _pViewShell,
6080 OutputDevice const * pRenderContext,
6081 SwRect& _orBorderAndShadowBoundRect,
6082 bool bLeftShadow,
6083 bool bRightShadow,
6084 bool bRightSidebar
6085 )
6086{
6087 SwRect aAlignedPageRect( _rPageRect );
6088 ::SwAlignRect( aAlignedPageRect, _pViewShell, pRenderContext );
6089 SwRect aPagePxRect = pRenderContext->LogicToPixel( aAlignedPageRect.SVRect() );
6090 aPagePxRect.AddBottom( mnShadowPxWidth + 1 );
6091 aPagePxRect.AddTop( - mnShadowPxWidth - 1 );
6092
6093 SwRect aTmpRect;
6094
6095 // Always ask for full shadow since we want a bounding rect
6096 // including at least the page frame
6097 SwPageFrame::GetHorizontalShadowRect( _rPageRect, _pViewShell, pRenderContext, aTmpRect, false, false, bRightSidebar );
6098
6099 if(bLeftShadow) aPagePxRect.Left( aTmpRect.Left() - mnShadowPxWidth - 1);
6100 if(bRightShadow) aPagePxRect.Right( aTmpRect.Right() + mnShadowPxWidth + 1);
6101
6102 _orBorderAndShadowBoundRect = pRenderContext->PixelToLogic( aPagePxRect.SVRect() );
6103}
6104
6105SwRect SwPageFrame::GetBoundRect(OutputDevice const * pOutputDevice) const
6106{
6107 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
6108 SwRect aPageRect( getFrameArea() );
6109 SwRect aResult;
6110
6111 if(!pSh) {
6112 return SwRect( Point(0, 0), Size(0, 0) );
6113 }
6114
6115 SwPageFrame::GetBorderAndShadowBoundRect( aPageRect, pSh, pOutputDevice, aResult,
6116 IsLeftShadowNeeded(), IsRightShadowNeeded(), SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT );
6117 return aResult;
6118}
6119
6120/*static*/ SwTwips SwPageFrame::GetSidebarBorderWidth( const SwViewShell* _pViewShell )
6121{
6122 const SwPostItMgr* pPostItMgr = _pViewShell ? _pViewShell->GetPostItMgr() : nullptr;
6123 const SwTwips nRet = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ? pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() : 0;
6124 return nRet;
6125}
6126
6127void SwFrame::PaintBaBo( const SwRect& rRect, const SwPageFrame *pPage,
6128 const bool bOnlyTextBackground ) const
6129{
6130 if ( !pPage )
6131 pPage = FindPageFrame();
6132
6133 OutputDevice *pOut = gProp.pSGlobalShell->GetOut();
6134
6135 // #i16816# tagged pdf support
6136 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
6137
6138 pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
6139 pOut->SetLineColor();
6140
6141 SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
6142 const SwBorderAttrs &rAttrs = *aAccess.Get();
6143
6144 // take care of page margin area
6145 // Note: code move from <SwFrame::PaintSwFrameBackground(..)> to new method
6146 // <SwPageFrame::Paintmargin(..)>.
6147 if ( IsPageFrame() && !bOnlyTextBackground)
6148 {
6149 static_cast<const SwPageFrame*>(this)->PaintMarginArea( rRect, gProp.pSGlobalShell );
6150 }
6151
6152 // paint background
6153 {
6154 PaintSwFrameBackground( rRect, pPage, rAttrs, false, true/*bLowerBorder*/, bOnlyTextBackground );
6155 }
6156
6157 // paint border before painting background
6158 // paint grid for page frame and paint border
6159 if (!bOnlyTextBackground)
6160 {
6161 SwRect aRect( rRect );
6162
6163 if( IsPageFrame() )
6164 {
6165 static_cast<const SwPageFrame*>(this)->PaintGrid( pOut, aRect );
6166 }
6167
6168 PaintSwFrameShadowAndBorder(aRect, pPage, rAttrs);
6169 }
6170
6171 pOut->Pop();
6172}
6173
6174static bool lcl_compareFillAttributes(const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& pA, const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& pB)
6175{
6176 if (pA == pB)
6177 return true;
6178 if (!pA || !pB)
6179 return false;
6180 return pA->getFillAttribute() == pB->getFillAttribute();
6181}
6182
6183/// Do not paint background for fly frames without a background brush by
6184/// calling <PaintBaBo> at the page or at the fly frame its anchored
6185void SwFrame::PaintSwFrameBackground( const SwRect &rRect, const SwPageFrame *pPage,
6186 const SwBorderAttrs & rAttrs,
6187 const bool bLowerMode,
6188 const bool bLowerBorder,
6189 const bool bOnlyTextBackground ) const
6190{
6191 // #i1837# - no paint of table background, if corresponding option is *not* set.
6192 if( IsTabFrame() &&
6193 !gProp.pSGlobalShell->GetViewOptions()->IsTable() )
6194 {
6195 return;
6196 }
6197
6198 SwViewShell *pSh = gProp.pSGlobalShell;
6199
6200 // #i16816# tagged pdf support
6201 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh->GetOut() );
6202
6203 const SvxBrushItem* pItem;
6204 // temporary background brush for a fly frame without a background brush
6205 std::unique_ptr<SvxBrushItem> pTmpBackBrush;
6206 const Color* pCol;
6207 SwRect aOrigBackRect;
6208 const bool bPageFrame = IsPageFrame();
6209 bool bLowMode = true;
6210 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
6211
6212 bool bBack = GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, bLowerMode, /*bConsiderTextBox=*/false );
6213 //- Output if a separate background is used.
6214 bool bNoFlyBackground = !gProp.bSFlyMetafile && !bBack && IsFlyFrame();
6215 if ( bNoFlyBackground )
6216 {
6217 // Fly frame has no background.
6218 // Try to find background brush at parents, if previous call of
6219 // <GetBackgroundBrush> disabled this option with the parameter <bLowerMode>
6220 if ( bLowerMode )
6221 {
6222 bBack = GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/false );
6223 }
6224 // If still no background found for the fly frame, initialize the
6225 // background brush <pItem> with global retouche color and set <bBack>
6226 // to true, that fly frame will paint its background using this color.
6227 if ( !bBack )
6228 {
6229 // #i6467# - on print output, pdf output and in embedded mode not editing color COL_WHITE is used
6230 // instead of the global retouche color.
6231 if ( pSh->GetOut()->GetOutDevType() == OUTDEV_PRINTER ||
6232 pSh->GetViewOptions()->IsPDFExport() ||
6233 ( pSh->GetDoc()->GetDocShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED &&
6234 !pSh->GetDoc()->GetDocShell()->IsInPlaceActive()
6235 )
6236 )
6237 {
6238 pTmpBackBrush.reset(new SvxBrushItem( COL_WHITE, RES_BACKGROUND ));
6239
6240 //UUU
6241 aFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(COL_WHITE);
6242 }
6243 else
6244 {
6245 pTmpBackBrush.reset(new SvxBrushItem( aGlobalRetoucheColor, RES_BACKGROUND));
6246
6247 //UUU
6248 aFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(aGlobalRetoucheColor);
6249 }
6250
6251 pItem = pTmpBackBrush.get();
6252 bBack = true;
6253 }
6254 }
6255
6256 SwRect aPaintRect( getFrameArea() );
6257 if( IsTextFrame() || IsSctFrame() )
6258 aPaintRect = UnionFrame( true );
6259
6260 // bOnlyTextBackground means background that's on top of background shapes,
6261 // this includes both text and cell frames.
6262 if ( (!bOnlyTextBackground || IsTextFrame() || IsCellFrame()) && aPaintRect.IsOver( rRect ) )
6263 {
6264 if ( bBack || bPageFrame || !bLowerMode )
6265 {
6266 const bool bBrowse = pSh->GetViewOptions()->getBrowseMode();
6267 SwRect aRect;
6268 if ( (bPageFrame && bBrowse) ||
6269 (IsTextFrame() && getFramePrintArea().SSize() == getFrameArea().SSize()) )
6270 {
6271 aRect = getFrameArea();
6272 ::SwAlignRect( aRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
6273 }
6274 else
6275 {
6276 if ( bPageFrame )
6277 {
6278 aRect = getFrameArea();
6279 }
6280 else
6281 {
6282 ::lcl_CalcBorderRect( aRect, this, rAttrs, false, gProp);
6283 }
6284
6285 if ( (IsTextFrame() || IsTabFrame()) && GetPrev() )
6286 {
6287 if ( GetPrev()->GetAttrSet()->GetBackground() == GetAttrSet()->GetBackground() &&
6288 lcl_compareFillAttributes(GetPrev()->getSdrAllFillAttributesHelper(), getSdrAllFillAttributesHelper()))
6289 {
6290 aRect.Top( getFrameArea().Top() );
6291 }
6292 }
6293 }
6294 aRect.Intersection( rRect );
6295
6296 OutputDevice *pOut = pSh->GetOut();
6297
6298 if ( aRect.HasArea() )
6299 {
6300 std::unique_ptr<SvxBrushItem> pNewItem;
6301
6302 if( pCol )
6303 {
6304 pNewItem.reset(new SvxBrushItem( *pCol, RES_BACKGROUND ));
6305 pItem = pNewItem.get();
6306 aFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(*pCol);
6307 }
6308
6309 SwRegionRects aRegion( aRect );
6310 basegfx::B2DPolygon aB2DPolygon{tools::Polygon(aRect.SVRect()).getB2DPolygon()};
6311 basegfx::utils::B2DClipState aClipState{basegfx::B2DPolyPolygon(aB2DPolygon)};
6312 if (pPage->GetSortedObjs() &&
6313 pSh->GetDoc()->getIDocumentSettingAccess().get(DocumentSettingId::SUBTRACT_FLYS))
6314 {
6315 ::lcl_SubtractFlys( this, pPage, aRect, aRegion, aClipState, gProp );
6316 }
6317
6318 // Determine, if background transparency
6319 // have to be considered for drawing.
6320 // Status Quo: background transparency have to be
6321 // considered for fly frames
6322 const bool bConsiderBackgroundTransparency = IsFlyFrame();
6323 bool bDone(false);
6324
6325 // #i125189# We are also done when the new DrawingLayer FillAttributes are used
6326 // or the FillStyle is set (different from drawing::FillStyle_NONE)
6327 if(pOut && aFillAttributes)
6328 {
6329 if(aFillAttributes->isUsed())
6330 {
6331 // check if really something is painted
6332 bDone = DrawFillAttributes(aFillAttributes, aOrigBackRect, aRegion, aClipState, *pOut);
6333 }
6334
6335 if(!bDone)
6336 {
6337 // if not, still a FillStyle could be set but the transparency is at 100%,
6338 // thus need to check the model data itself for FillStyle (do not rely on
6339 // SdrAllFillAttributesHelper since it already contains optimized information,
6340 // e.g. transparency leads to no fill)
6341 const drawing::FillStyle eFillStyle(GetAttrSet()->Get(XATTR_FILLSTYLE).GetValue());
6342
6343 if(drawing::FillStyle_NONE != eFillStyle)
6344 {
6345 bDone = true;
6346 }
6347 }
6348 }
6349
6350 if(!bDone)
6351 {
6352 for (size_t i = 0; i < aRegion.size(); ++i)
6353 {
6354 if (1 < aRegion.size())
6355 {
6356 ::SwAlignRect( aRegion[i], gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
6357 if( !aRegion[i].HasArea() )
6358 continue;
6359 }
6360 // add 6th parameter to indicate, if background transparency have to be considered
6361 // Set missing 5th parameter to the default value GRFNUM_NO
6362 // - see declaration in /core/inc/frmtool.hxx.
6363 ::DrawGraphic(
6364 pItem,
6365 pOut,
6366 aOrigBackRect,
6367 aRegion[i],
6368 GRFNUM_NO0,
6369 bConsiderBackgroundTransparency );
6370 }
6371 }
6372 }
6373 }
6374 else
6375 bLowMode = bLowerMode;
6376 }
6377
6378 // delete temporary background brush.
6379 pTmpBackBrush.reset();
6380
6381 //Now process lower and his neighbour.
6382 //We end this as soon as a Frame leaves the chain and therefore is not a lower
6383 //of me anymore
6384 const SwFrame *pFrame = GetLower();
6385 if ( !pFrame )
6386 return;
6387
6388 SwRect aFrameRect;
6389 SwRect aRect( GetPaintArea() );
6390 aRect.Intersection_( rRect );
6391 SwRect aBorderRect( aRect );
6392 SwShortCut aShortCut( *pFrame, aBorderRect );
6393 do
6394 { if ( gProp.pSProgress )
6395 SfxProgress::Reschedule();
6396
6397 aFrameRect = pFrame->GetPaintArea();
6398 if ( aFrameRect.IsOver( aBorderRect ) )
6399 {
6400 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pFrame );
6401 const SwBorderAttrs &rTmpAttrs = *aAccess.Get();
6402 if ( ( pFrame->IsLayoutFrame() && bLowerBorder ) || aFrameRect.IsOver( aRect ) )
6403 {
6404 pFrame->PaintSwFrameBackground( aRect, pPage, rTmpAttrs, bLowMode,
6405 bLowerBorder, bOnlyTextBackground );
6406 }
6407
6408 if ( bLowerBorder )
6409 {
6410 pFrame->PaintSwFrameShadowAndBorder( aBorderRect, pPage, rTmpAttrs );
6411 }
6412 }
6413 pFrame = pFrame->GetNext();
6414 } while ( pFrame && pFrame->GetUpper() == this &&
6415 !aShortCut.Stop( aFrameRect ) );
6416}
6417
6418/// Refreshes all subsidiary lines of a page.
6419void SwPageFrame::RefreshSubsidiary( const SwRect &rRect ) const
6420{
6421 if ( !(isSubsidiaryLinesEnabled() || isTableBoundariesEnabled()
6422 || isSubsidiaryLinesForSectionsEnabled() || isSubsidiaryLinesFlysEnabled()) )
6423 return;
6424
6425 if ( !rRect.HasArea() )
6426 return;
6427
6428 //During paint using the root, the array is controlled from there.
6429 //Otherwise we'll handle it for our self.
6430 bool bDelSubs = false;
6431 if ( !gProp.pSSubsLines )
6432 {
6433 gProp.pSSubsLines.reset(new SwSubsRects);
6434 // create container for special subsidiary lines
6435 gProp.pSSpecSubsLines.reset(new SwSubsRects);
6436 bDelSubs = true;
6437 }
6438
6439 RefreshLaySubsidiary( this, rRect );
6440
6441 if ( bDelSubs )
6442 {
6443 // paint special subsidiary lines and delete its container
6444 gProp.pSSpecSubsLines->PaintSubsidiary( gProp.pSGlobalShell->GetOut(), nullptr, gProp );
6445 gProp.pSSpecSubsLines.reset();
6446
6447 gProp.pSSubsLines->PaintSubsidiary(gProp.pSGlobalShell->GetOut(), gProp.pSLines.get(), gProp);
6448 gProp.pSSubsLines.reset();
6449 }
6450}
6451
6452void SwLayoutFrame::RefreshLaySubsidiary( const SwPageFrame *pPage,
6453 const SwRect &rRect ) const
6454{
6455 const bool bSubsOpt = isSubsidiaryLinesEnabled();
6456 if ( bSubsOpt )
6457 PaintSubsidiaryLines( pPage, rRect );
6458
6459 const SwFrame *pLow = Lower();
6460 if( !pLow )
6461 return;
6462 SwShortCut aShortCut( *pLow, rRect );
6463 while( pLow && !aShortCut.Stop( pLow->getFrameArea() ) )
6464 {
6465 if ( pLow->getFrameArea().IsOver( rRect ) && pLow->getFrameArea().HasArea() )
6466 {
6467 if ( pLow->IsLayoutFrame() )
6468 static_cast<const SwLayoutFrame*>(pLow)->RefreshLaySubsidiary( pPage, rRect);
6469 else if ( pLow->GetDrawObjs() )
6470 {
6471 const SwSortedObjs& rObjs = *(pLow->GetDrawObjs());
6472 for (SwAnchoredObject* pAnchoredObj : rObjs)
6473 {
6474 if ( pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
6475 pAnchoredObj->GetDrawObj()->GetLayer() ) &&
6476 dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
6477 {
6478 const SwFlyFrame *pFly =
6479 static_cast<const SwFlyFrame*>(pAnchoredObj);
6480 if ( pFly->IsFlyInContentFrame() && pFly->getFrameArea().IsOver( rRect ) )
6481 {
6482 if ( !pFly->Lower() || !pFly->Lower()->IsNoTextFrame() ||
6483 !static_cast<const SwNoTextFrame*>(pFly->Lower())->HasAnimation())
6484 pFly->RefreshLaySubsidiary( pPage, rRect );
6485 }
6486 }
6487 }
6488 }
6489 }
6490 pLow = pLow->GetNext();
6491 }
6492}
6493
6494/**
6495 * Subsidiary lines to paint the PrtAreas
6496 * Only the LayoutFrames which directly contain Content
6497 * Paints the desired line and pays attention to not overpaint any flys
6498 */
6499static void lcl_RefreshLine( const SwLayoutFrame *pLay,
6500 const SwPageFrame *pPage,
6501 const Point &rP1,
6502 const Point &rP2,
6503 const SubColFlags nSubColor,
6504 SwLineRects* pSubsLines )
6505{
6506 //In which direction do we loop? Can only be horizontal or vertical.
6507 OSL_ENSURE( ((rP1.X() == rP2.X()) || (rP1.Y() == rP2.Y())),do { if (true && (!(((rP1.X() == rP2.X()) || (rP1.Y()
== rP2.Y()))))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "6508" ": "), "%s", "Sloped subsidiary lines are not allowed."
); } } while (false)
6508 "Sloped subsidiary lines are not allowed." )do { if (true && (!(((rP1.X() == rP2.X()) || (rP1.Y()
== rP2.Y()))))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "6508" ": "), "%s", "Sloped subsidiary lines are not allowed."
); } } while (false)
;
6509
6510 const bool bHori = rP1.Y() == rP2.Y();
6511
6512 // use pointers to member function in order to unify flow
6513 typedef long (Point::*pmfPtGet)() const;
6514 typedef void (Point::*pmfPtSet)(long);
6515 const pmfPtGet pDirPtX = &Point::X;
6516 const pmfPtGet pDirPtY = &Point::Y;
6517 const pmfPtGet pDirPt = bHori ? pDirPtX : pDirPtY;
6518 const pmfPtSet pDirPtSetX = &Point::setX;
6519 const pmfPtSet pDirPtSetY = &Point::setY;
6520 const pmfPtSet pDirPtSet = bHori ? pDirPtSetX : pDirPtSetY;
6521
6522 Point aP1( rP1 );
6523 Point aP2( rP2 );
6524
6525 while ( (aP1.*pDirPt)() < (aP2.*pDirPt)() )
6526 {
6527 //If the starting point lies in a fly, it is directly set behind the
6528 //fly.
6529 //The end point moves to the start if the end point lies in a fly or we
6530 //have a fly between starting point and end point.
6531 // In this way, every position is output one by one.
6532
6533 //If I'm a fly I'll only avoid those flys which are places 'above' me;
6534 //this means those who are behind me in the array.
6535 //Even if I'm inside a fly or inside a fly inside a fly a.s.o I won't
6536 //avoid any of those flys.
6537 SwOrderIter aIter( pPage );
6538 const SwFlyFrame *pMyFly = pLay->FindFlyFrame();
6539 if ( pMyFly )
6540 {
6541 aIter.Current( pMyFly->GetVirtDrawObj() );
6542 while ( nullptr != (pMyFly = pMyFly->GetAnchorFrame()->FindFlyFrame()) )
6543 {
6544 if ( aIter()->GetOrdNum() > pMyFly->GetVirtDrawObj()->GetOrdNum() )
6545 aIter.Current( pMyFly->GetVirtDrawObj() );
6546 }
6547 }
6548 else
6549 aIter.Bottom();
6550
6551 while ( aIter() )
6552 {
6553 const SwVirtFlyDrawObj *pObj = static_cast<const SwVirtFlyDrawObj*>(aIter());
6554 const SwFlyFrame *pFly = pObj ? pObj->GetFlyFrame() : nullptr;
6555
6556 //I certainly won't avoid myself, even if I'm placed _inside_ the
6557 //fly I won't avoid it.
6558 if ( !pFly || (pFly == pLay || pFly->IsAnLower( pLay )) )
6559 {
6560 aIter.Next();
6561 continue;
6562 }
6563
6564 // do *not* consider fly frames with a transparent background.
6565 // do *not* consider fly frame, which belongs to an invisible layer
6566 if ( pFly->IsBackgroundTransparent() ||
6567 !pFly->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( pObj->GetLayer() ) )
6568 {
6569 aIter.Next();
6570 continue;
6571 }
6572
6573 //Is the Obj placed on the line
6574 const long nP1OthPt = !bHori ? rP1.X() : rP1.Y();
6575 const tools::Rectangle &rBound = pObj->GetCurrentBoundRect();
6576 const Point aDrPt( rBound.TopLeft() );
6577 const long nDrOthPt = !bHori ? aDrPt.X() : aDrPt.Y();
6578 const Size aDrSz( rBound.GetSize() );
6579 const long nDrOthSz = !bHori ? aDrSz.Width() : aDrSz.Height();
6580
6581 if ( nP1OthPt >= nDrOthPt && nP1OthPt <= nDrOthPt + nDrOthSz )
6582 {
6583 const long nDrDirPt = bHori ? aDrPt.X() : aDrPt.Y();
6584 const long nDrDirSz = bHori ? aDrSz.Width() : aDrSz.Height();
6585
6586 if ( (aP1.*pDirPt)() >= nDrDirPt && (aP1.*pDirPt)() <= nDrDirPt + nDrDirSz )
6587 (aP1.*pDirPtSet)( nDrDirPt + nDrDirSz );
6588
6589 if ( (aP2.*pDirPt)() >= nDrDirPt && (aP1.*pDirPt)() < (nDrDirPt - 1) )
6590 (aP2.*pDirPtSet)( nDrDirPt - 1 );
6591 }
6592 aIter.Next();
6593 }
6594
6595 if ( (aP1.*pDirPt)() < (aP2.*pDirPt)() )
6596 {
6597 SwRect aRect( aP1, aP2 );
6598 // use parameter <pSubsLines> instead of global variable <gProp.pSSubsLines>.
6599 pSubsLines->AddLineRect( aRect, nullptr, SvxBorderLineStyle::SOLID,
6600 nullptr, nSubColor, gProp );
6601 }
6602 aP1 = aP2;
6603 (aP1.*pDirPtSet)( (aP1.*pDirPt)() + 1 );
6604 aP2 = rP2;
6605 }
6606}
6607
6608static drawinglayer::primitive2d::Primitive2DContainer lcl_CreatePageAreaDelimiterPrimitives(
6609 const SwRect& rRect )
6610{
6611 drawinglayer::primitive2d::Primitive2DContainer aSeq( 4 );
6612
6613 basegfx::BColor aLineColor = SwViewOption::GetDocBoundariesColor().getBColor();
6614 double nLineLength = 200.0; // in Twips
6615
6616 Point aPoints[] = { rRect.TopLeft(), rRect.TopRight(), rRect.BottomRight(), rRect.BottomLeft() };
6617 double const aXOffDirs[] = { -1.0, 1.0, 1.0, -1.0 };
6618 double const aYOffDirs[] = { -1.0, -1.0, 1.0, 1.0 };
6619
6620 // Actually loop over the corners to create the two lines
6621 for ( int i = 0; i < 4; i++ )
6622 {
6623 basegfx::B2DVector aHorizVector( aXOffDirs[i], 0.0 );
6624 basegfx::B2DVector aVertVector( 0.0, aYOffDirs[i] );
6625
6626 basegfx::B2DPoint aBPoint( aPoints[i].getX(), aPoints[i].getY() );
6627
6628 basegfx::B2DPolygon aPolygon;
6629 aPolygon.append( aBPoint + aHorizVector * nLineLength );
6630 aPolygon.append( aBPoint );
6631 aPolygon.append( aBPoint + aVertVector * nLineLength );
6632
6633 drawinglayer::primitive2d::PolygonHairlinePrimitive2D* pLine =
6634 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
6635 aPolygon, aLineColor );
6636 aSeq[i] = drawinglayer::primitive2d::Primitive2DReference( pLine );
6637 }
6638
6639 return aSeq;
6640}
6641
6642static drawinglayer::primitive2d::Primitive2DContainer lcl_CreateRectangleDelimiterPrimitives (
6643 const SwRect& rRect )
6644{
6645 drawinglayer::primitive2d::Primitive2DContainer aSeq( 1 );
6646 basegfx::BColor aLineColor = SwViewOption::GetDocBoundariesColor().getBColor();
6647
6648 basegfx::B2DPolygon aPolygon;
6649 aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Top() ) );
6650 aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Top() ) );
6651 aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Bottom() ) );
6652 aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Bottom() ) );
6653 aPolygon.setClosed( true );
6654
6655 drawinglayer::primitive2d::PolygonHairlinePrimitive2D* pLine =
6656 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
6657 aPolygon, aLineColor );
6658 aSeq[0] = drawinglayer::primitive2d::Primitive2DReference( pLine );
6659
6660 return aSeq;
6661}
6662
6663static drawinglayer::primitive2d::Primitive2DContainer lcl_CreateColumnAreaDelimiterPrimitives(
6664 const SwRect& rRect )
6665{
6666 drawinglayer::primitive2d::Primitive2DContainer aSeq( 4 );
6667
6668 basegfx::BColor aLineColor = SwViewOption::GetDocBoundariesColor().getBColor();
6669 double nLineLength = 100.0; // in Twips
6670
6671 Point aPoints[] = { rRect.TopLeft(), rRect.TopRight(), rRect.BottomRight(), rRect.BottomLeft() };
6672 double const aXOffDirs[] = { 1.0, -1.0, -1.0, 1.0 };
6673 double const aYOffDirs[] = { 1.0, 1.0, -1.0, -1.0 };
6674
6675 // Actually loop over the corners to create the two lines
6676 for ( int i = 0; i < 4; i++ )
6677 {
6678 basegfx::B2DVector aHorizVector( aXOffDirs[i], 0.0 );
6679 basegfx::B2DVector aVertVector( 0.0, aYOffDirs[i] );
6680
6681 basegfx::B2DPoint aBPoint( aPoints[i].getX(), aPoints[i].getY() );
6682
6683 basegfx::B2DPolygon aPolygon;
6684 aPolygon.append( aBPoint + aHorizVector * nLineLength );
6685 aPolygon.append( aBPoint );
6686 aPolygon.append( aBPoint + aVertVector * nLineLength );
6687
6688 drawinglayer::primitive2d::PolygonHairlinePrimitive2D* pLine =
6689 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
6690 aPolygon, aLineColor );
6691 aSeq[i] = drawinglayer::primitive2d::Primitive2DReference( pLine );
6692 }
6693
6694 return aSeq;
6695}
6696
6697void SwPageFrame::PaintSubsidiaryLines( const SwPageFrame *,
6698 const SwRect & ) const
6699{
6700 if ( gProp.pSGlobalShell->IsHeaderFooterEdit() )
6701 return;
6702
6703 const SwFrame* pLay = Lower();
6704 const SwFrame* pFootnoteCont = nullptr;
6705 const SwFrame* pPageBody = nullptr;
6706 while ( pLay && !( pFootnoteCont && pPageBody ) )
6707 {
6708 if ( pLay->IsFootnoteContFrame( ) )
6709 pFootnoteCont = pLay;
6710 if ( pLay->IsBodyFrame() )
6711 pPageBody = pLay;
6712 pLay = pLay->GetNext();
6713 }
6714
6715 SwRect aArea( pPageBody->getFrameArea() );
6716 if ( pFootnoteCont )
6717 aArea.AddBottom( pFootnoteCont->getFrameArea().Bottom() - aArea.Bottom() );
6718
6719 if ( !gProp.pSGlobalShell->GetViewOptions()->IsViewMetaChars( ) )
6720 ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea ) );
6721 else
6722 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea ) );
6723}
6724
6725void SwColumnFrame::PaintSubsidiaryLines( const SwPageFrame *,
6726 const SwRect & ) const
6727{
6728 const SwFrame* pLay = Lower();
6729 const SwFrame* pFootnoteCont = nullptr;
6730 const SwFrame* pColBody = nullptr;
6731 while ( pLay && !( pFootnoteCont && pColBody ) )
6732 {
6733 if ( pLay->IsFootnoteContFrame( ) )
6734 pFootnoteCont = pLay;
6735 if ( pLay->IsBodyFrame() )
6736 pColBody = pLay;
6737 pLay = pLay->GetNext();
6738 }
6739
6740 SwRect aArea( pColBody->getFrameArea() );
6741
6742 // #i3662# - enlarge top of column body frame's printing area
6743 // in sections to top of section frame.
6744 const bool bColInSection = GetUpper()->IsSctFrame();
6745 if ( bColInSection )
6746 {
6747 if ( IsVertical() )
6748 aArea.Right( GetUpper()->getFrameArea().Right() );
6749 else
6750 aArea.Top( GetUpper()->getFrameArea().Top() );
6751 }
6752
6753 if ( pFootnoteCont )
6754 aArea.AddBottom( pFootnoteCont->getFrameArea().Bottom() - aArea.Bottom() );
6755
6756 ::SwAlignRect( aArea, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
6757
6758 if ( !gProp.pSGlobalShell->GetViewOptions()->IsViewMetaChars( ) )
6759 ProcessPrimitives( lcl_CreateColumnAreaDelimiterPrimitives( aArea ) );
6760 else
6761 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea ) );
6762}
6763
6764void SwSectionFrame::PaintSubsidiaryLines( const SwPageFrame * pPage,
6765 const SwRect & rRect ) const
6766{
6767 const bool bNoLowerColumn = !Lower() || !Lower()->IsColumnFrame();
6768 if ( bNoLowerColumn )
6769 {
6770 SwLayoutFrame::PaintSubsidiaryLines( pPage, rRect );
6771 }
6772}
6773
6774/**
6775 * The SwBodyFrame doesn't print any subsidiary line: it's bounds are painted
6776 * either by the parent page or the parent column frame.
6777 */
6778void SwBodyFrame::PaintSubsidiaryLines( const SwPageFrame *,
6779 const SwRect & ) const
6780{
6781}
6782
6783void SwHeadFootFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect & ) const
6784{
6785 if ( gProp.pSGlobalShell->IsHeaderFooterEdit() )
6786 {
6787 SwRect aArea( getFramePrintArea() );
6788 aArea.Pos() += getFrameArea().Pos();
6789 if ( !gProp.pSGlobalShell->GetViewOptions()->IsViewMetaChars( ) )
6790 ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea ) );
6791 else
6792 ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea ) );
6793 }
6794}
6795
6796/**
6797 * This method is overridden in order to have no subsidiary lines
6798 * around the footnotes.
6799 */
6800void SwFootnoteFrame::PaintSubsidiaryLines( const SwPageFrame *,
6801 const SwRect & ) const
6802{
6803}
6804
6805/**
6806 * This method is overridden in order to have no subsidiary lines
6807 * around the footnotes containers.
6808 */
6809void SwFootnoteContFrame::PaintSubsidiaryLines( const SwPageFrame *,
6810 const SwRect & ) const
6811{
6812}
6813
6814void SwLayoutFrame::PaintSubsidiaryLines( const SwPageFrame *pPage,
6815 const SwRect &rRect ) const
6816{
6817 bool bNewTableModel = false;
6818
6819 // #i29550#
6820 if ( IsTabFrame() || IsCellFrame() || IsRowFrame() )
6821 {
6822 const SwTabFrame* pTabFrame = FindTabFrame();
6823 if ( pTabFrame->IsCollapsingBorders() )
6824 return;
6825
6826 bNewTableModel = pTabFrame->GetTable()->IsNewModel();
6827 // in the new table model, we have an early return for all cell-related
6828 // frames, except from non-covered table cells
6829 if ( bNewTableModel )
6830 if ( IsTabFrame() ||
6831 IsRowFrame() ||
6832 ( IsCellFrame() && IsCoveredCell() ) )
6833 return;
6834 }
6835
6836 const bool bFlys = pPage->GetSortedObjs() != nullptr;
6837
6838 const bool bCell = IsCellFrame();
6839 // #i3662# - use frame area for cells for section use also frame area
6840 const bool bUseFrameArea = bCell || IsSctFrame();
6841 SwRect aOriginal( bUseFrameArea ? getFrameArea() : getFramePrintArea() );
6842 if ( !bUseFrameArea )
6843 aOriginal.Pos() += getFrameArea().Pos();
6844
6845 ::SwAlignRect( aOriginal, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
6846
6847 if ( !aOriginal.IsOver( rRect ) )
6848 return;
6849
6850 SwRect aOut( aOriginal );
6851 aOut.Intersection_( rRect );
6852
6853 const SwTwips nRight = aOut.Right();
6854 const SwTwips nBottom= aOut.Bottom();
6855
6856 const Point aRT( nRight, aOut.Top() );
6857 const Point aRB( nRight, nBottom );
6858 const Point aLB( aOut.Left(), nBottom );
6859
6860 SubColFlags nSubColor = ( bCell || IsRowFrame() )
6861 ? SubColFlags::Tab
6862 : ( IsInSct()
6863 ? SubColFlags::Sect
6864 : ( IsInFly() ? SubColFlags::Fly : SubColFlags::Page ) );
6865
6866 // collect body, header, footer, footnote and section
6867 // sub-lines in <pSpecSubsLine> array.
6868 const bool bSpecialSublines = IsBodyFrame() || IsHeaderFrame() || IsFooterFrame() ||
6869 IsFootnoteFrame() || IsSctFrame();
6870 SwLineRects *const pUsedSubsLines = bSpecialSublines
6871 ? gProp.pSSpecSubsLines.get() : gProp.pSSubsLines.get();
6872
6873 // NOTE: for cell frames only left and right (horizontal layout) respectively
6874 // top and bottom (vertical layout) lines painted.
6875 // NOTE2: this does not hold for the new table model!!! We paint the top border
6876 // of each non-covered table cell.
6877 const bool bVert = IsVertical();
6878 if ( bFlys )
6879 {
6880 // add control for drawing left and right lines
6881 if ( !bCell || bNewTableModel || !bVert )
6882 {
6883 if ( aOriginal.Left() == aOut.Left() )
6884 ::lcl_RefreshLine( this, pPage, aOut.Pos(), aLB, nSubColor, pUsedSubsLines );
6885 // in vertical layout set page/column break at right
6886 if ( aOriginal.Right() == nRight )
6887 ::lcl_RefreshLine( this, pPage, aRT, aRB, nSubColor, pUsedSubsLines );
6888 }
6889 // adjust control for drawing top and bottom lines
6890 if ( !bCell || bNewTableModel || bVert )
6891 {
6892 if ( aOriginal.Top() == aOut.Top() )
6893 // in horizontal layout set page/column break at top
6894 ::lcl_RefreshLine( this, pPage, aOut.Pos(), aRT, nSubColor, pUsedSubsLines );
6895 if ( aOriginal.Bottom() == nBottom )
6896 ::lcl_RefreshLine( this, pPage, aLB, aRB, nSubColor,
6897 pUsedSubsLines );
6898 }
6899 }
6900 else
6901 {
6902 // add control for drawing left and right lines
6903 if ( !bCell || bNewTableModel || !bVert )
6904 {
6905 if ( aOriginal.Left() == aOut.Left() )
6906 {
6907 const SwRect aRect( aOut.Pos(), aLB );
6908 pUsedSubsLines->AddLineRect( aRect, nullptr,
6909 SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
6910 }
6911 // in vertical layout set page/column break at right
6912 if ( aOriginal.Right() == nRight )
6913 {
6914 const SwRect aRect( aRT, aRB );
6915 pUsedSubsLines->AddLineRect( aRect, nullptr,
6916 SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
6917 }
6918 }
6919 // adjust control for drawing top and bottom lines
6920 if ( !bCell || bNewTableModel || bVert )
6921 {
6922 if ( aOriginal.Top() == aOut.Top() )
6923 {
6924 // in horizontal layout set page/column break at top
6925 const SwRect aRect( aOut.Pos(), aRT );
6926 pUsedSubsLines->AddLineRect( aRect, nullptr,
6927 SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
6928 }
6929 if ( aOriginal.Bottom() == nBottom )
6930 {
6931 const SwRect aRect( aLB, aRB );
6932 pUsedSubsLines->AddLineRect( aRect, nullptr,
6933 SvxBorderLineStyle::SOLID, nullptr, nSubColor, gProp );
6934 }
6935 }
6936 }
6937}
6938
6939/**
6940 * Refreshes all extra data (line breaks a.s.o) of the page. Basically only those objects
6941 * are considered which horizontally overlap the Rect.
6942 */
6943void SwPageFrame::RefreshExtraData( const SwRect &rRect ) const
6944{
6945 const SwLineNumberInfo &rInfo = GetFormat()->GetDoc()->GetLineNumberInfo();
6946 bool bLineInFly = (rInfo.IsPaintLineNumbers() && rInfo.IsCountInFlys())
6947 || static_cast<sal_Int16>(SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetRedlineMarkPos()) != text::HoriOrientation::NONE;
6948
6949 SwRect aRect( rRect );
6950 ::SwAlignRect( aRect, gProp.pSGlobalShell, gProp.pSGlobalShell->GetOut() );
6951 if ( !aRect.HasArea() )
6952 return;
6953
6954 SwLayoutFrame::RefreshExtraData( aRect );
6955
6956 if ( bLineInFly && GetSortedObjs() )
6957 for (SwAnchoredObject* pAnchoredObj : *GetSortedObjs())
6958 {
6959 if ( auto pFly = dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) )
6960 {
6961 if ( pFly->getFrameArea().Top() <= aRect.Bottom() &&
6962 pFly->getFrameArea().Bottom() >= aRect.Top() )
6963 pFly->RefreshExtraData( aRect );
6964 }
6965 }
6966}
6967
6968void SwLayoutFrame::RefreshExtraData( const SwRect &rRect ) const
6969{
6970
6971 const SwLineNumberInfo &rInfo = GetFormat()->GetDoc()->GetLineNumberInfo();
6972 bool bLineInBody = rInfo.IsPaintLineNumbers(),
6973 bLineInFly = bLineInBody && rInfo.IsCountInFlys(),
6974 bRedLine = static_cast<sal_Int16>(SW_MOD()( static_cast<SwModule*>(SfxApplication::GetModule(SfxToolsModule
::Writer)))
->GetRedlineMarkPos())!=text::HoriOrientation::NONE;
6975
6976 const SwContentFrame *pCnt = ContainsContent();
6977 while ( pCnt && IsAnLower( pCnt ) )
6978 {
6979 if ( pCnt->IsTextFrame() && ( bRedLine ||
6980 ( !pCnt->IsInTab() &&
6981 ((bLineInBody && pCnt->IsInDocBody()) ||
6982 (bLineInFly && pCnt->IsInFly())) ) ) &&
6983 pCnt->getFrameArea().Top() <= rRect.Bottom() &&
6984 pCnt->getFrameArea().Bottom() >= rRect.Top() )
6985 {
6986 static_cast<const SwTextFrame*>(pCnt)->PaintExtraData( rRect );
6987 }
6988 if ( bLineInFly && pCnt->GetDrawObjs() )
6989 for (SwAnchoredObject* pAnchoredObj : *pCnt->GetDrawObjs())
6990 {
6991 if ( auto pFly = dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) )
6992 {
6993 if ( pFly->IsFlyInContentFrame() &&
6994 pFly->getFrameArea().Top() <= rRect.Bottom() &&
6995 pFly->getFrameArea().Bottom() >= rRect.Top() )
6996 pFly->RefreshExtraData( rRect );
6997 }
6998 }
6999 pCnt = pCnt->GetNextContentFrame();
7000 }
7001}
7002
7003/**
7004 * For #102450#
7005 * Determine the color, that is respectively will be drawn as background
7006 * for the page frame.
7007 * Using existing method SwFrame::GetBackgroundBrush to determine the color
7008 * that is set at the page frame respectively is parent. If none is found
7009 * return the global retouche color
7010 *
7011 * @return Color
7012 */
7013Color SwPageFrame::GetDrawBackgrdColor() const
7014{
7015 const SvxBrushItem* pBrushItem;
7016 const Color* pDummyColor;
7017 SwRect aDummyRect;
7018 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes;
7019
7020 if ( GetBackgroundBrush( aFillAttributes, pBrushItem, pDummyColor, aDummyRect, true, /*bConsiderTextBox=*/false) )
7021 {
7022 if(aFillAttributes && aFillAttributes->isUsed())
7023 {
7024 // let SdrAllFillAttributesHelper do the average color calculation
7025 return Color(aFillAttributes->getAverageColor(aGlobalRetoucheColor.getBColor()));
7026 }
7027 else if(pBrushItem)
7028 {
7029 OUString referer;
7030 SwViewShell * sh1 = getRootFrame()->GetCurrShell();
7031 if (sh1 != nullptr) {
7032 SfxObjectShell * sh2 = sh1->GetDoc()->GetPersist();
7033 if (sh2 != nullptr && sh2->HasName()) {
7034 referer = sh2->GetMedium()->GetName();
7035 }
7036 }
7037 const Graphic* pGraphic = pBrushItem->GetGraphic(referer);
7038
7039 if(pGraphic)
7040 {
7041 // #29105# when a graphic is set, it may be possible to calculate a single
7042 // color which looks good in all places of the graphic. Since it is
7043 // planned to have text edit on the overlay one day and the fallback
7044 // to aGlobalRetoucheColor returns something useful, just use that
7045 // for now.
7046 }
7047 else
7048 {
7049 // not a graphic, use (hopefully) initialized color
7050 return pBrushItem->GetColor();
7051 }
7052 }
7053 }
7054
7055 return aGlobalRetoucheColor;
7056}
7057
7058/// create/return font used to paint the "empty page" string
7059const vcl::Font& SwPageFrame::GetEmptyPageFont()
7060{
7061 static vcl::Font aEmptyPgFont = [&]()
7062 {
7063 vcl::Font tmp;
7064 tmp.SetFontSize( Size( 0, 80 * 20 )); // == 80 pt
7065 tmp.SetWeight( WEIGHT_BOLD );
7066 tmp.SetStyleName(OUString());
7067 tmp.SetFamilyName("Helvetica");
7068 tmp.SetFamily( FAMILY_SWISS );
7069 tmp.SetTransparent( true );
7070 tmp.SetColor( COL_GRAY );
7071 return tmp;
7072 }();
7073
7074 return aEmptyPgFont;
7075}
7076
7077/**
7078 * Retouch for a section
7079 *
7080 * Retouch will only be done, if the Frame is the last one in his chain.
7081 * The whole area of the upper which is located below the Frame will be
7082 * cleared using PaintSwFrameBackground.
7083 */
7084void SwFrame::Retouch( const SwPageFrame * pPage, const SwRect &rRect ) const
7085{
7086 if ( gProp.bSFlyMetafile )
7087 return;
7088
7089 OSL_ENSURE( GetUpper(), "Retouche try without Upper." )do { if (true && (!(GetUpper()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "7089" ": "), "%s", "Retouche try without Upper."); } } while
(false)
;
7090 OSL_ENSURE( getRootFrame()->GetCurrShell() && gProp.pSGlobalShell->GetWin(), "Retouche on a printer?" )do { if (true && (!(getRootFrame()->GetCurrShell()
&& gProp.pSGlobalShell->GetWin()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "7090" ": "), "%s", "Retouche on a printer?"); } } while
(false)
;
7091
7092 SwRect aRetouche( GetUpper()->GetPaintArea() );
7093 aRetouche.Top( getFrameArea().Top() + getFrameArea().Height() );
7094 aRetouche.Intersection( gProp.pSGlobalShell->VisArea() );
7095
7096 if ( aRetouche.HasArea() )
7097 {
7098 //Omit the passed Rect. To do this, we unfortunately need a region to
7099 //cut out.
7100 SwRegionRects aRegion( aRetouche );
7101 aRegion -= rRect;
7102 SwViewShell *pSh = getRootFrame()->GetCurrShell();
7103
7104 // #i16816# tagged pdf support
7105 SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pSh->GetOut() );
7106
7107 for ( size_t i = 0; i < aRegion.size(); ++i )
7108 {
7109 const SwRect &rRetouche = aRegion[i];
7110
7111 GetUpper()->PaintBaBo( rRetouche, pPage );
7112
7113 //Hell and Heaven need to be refreshed too.
7114 //To avoid recursion my retouch flag needs to be reset first!
7115 ResetRetouche();
7116 if ( rRetouche.HasArea() )
7117 {
7118 const Color aPageBackgrdColor(pPage->GetDrawBackgrdColor());
7119 const IDocumentDrawModelAccess& rIDDMA = pSh->getIDocumentDrawModelAccess();
7120 // --> OD #i76669#
7121 SwViewObjectContactRedirector aSwRedirector( *pSh );
7122 // <--
7123
7124 pSh->Imp()->PaintLayer( rIDDMA.GetHellId(), nullptr,
7125 *pPage, rRetouche, &aPageBackgrdColor,
7126 pPage->IsRightToLeft(),
7127 &aSwRedirector );
7128 pSh->Imp()->PaintLayer( rIDDMA.GetHeavenId(), nullptr,
7129 *pPage, rRetouche, &aPageBackgrdColor,
7130 pPage->IsRightToLeft(),
7131 &aSwRedirector );
7132 }
7133
7134 SetRetouche();
7135
7136 //Because we leave all paint areas, we need to refresh the
7137 //subsidiary lines.
7138 pPage->RefreshSubsidiary( rRetouche );
7139 }
7140 }
7141 if ( SwViewShell::IsLstEndAction() )
7142 ResetRetouche();
7143}
7144
7145/**
7146 * Determine the background brush for the frame:
7147 * the background brush is taken from it-self or from its parent (anchor/upper).
7148 * Normally, the background brush is taken, which has no transparent color or
7149 * which has a background graphic. But there are some special cases:
7150 * (1) No background brush is taken from a page frame, if view option "IsPageBack"
7151 * isn't set.
7152 * (2) Background brush from an index section is taken under special conditions.
7153 * In this case parameter <rpCol> is set to the index shading color.
7154 * (3) New (OD 20.08.2002) - Background brush is taken, if on background drawing
7155 * of the frame transparency is considered and its color is not "no fill"/"auto fill"
7156 *
7157 * Old description in German:
7158 * Returns the Backgroundbrush for the area of the Frame.
7159 * The Brush is defined by the Frame or by an upper, the first Brush is
7160 * used. If no Brush is defined for a Frame, false is returned.
7161 *
7162 * @param rpBrush
7163 * output parameter - constant reference pointer the found background brush
7164 *
7165 * @param rpFillStyle
7166 * output parameter - constant reference pointer the found background fill style
7167 *
7168 * @param rpFillGradient
7169 * output parameter - constant reference pointer the found background fill gradient
7170 *
7171 * @param rpCol
7172 * output parameter - constant reference pointer to the color of the index shading
7173 * set under special conditions, if background brush is taken from an index section.
7174 *
7175 * @param rOrigRect
7176 * in-/output parameter - reference to the rectangle the background brush is
7177 * considered for - adjusted to the frame, from which the background brush is
7178 * taken.
7179 *
7180 * @parem bLowerMode
7181 * input parameter - boolean indicating, if background brush should *not* be
7182 * taken from parent.
7183 *
7184 * @param bConsiderTextBox
7185 * consider the TextBox of this fly frame (if there is any) when determining
7186 * the background color, useful for automatic font color.
7187 *
7188 * @return true, if a background brush for the frame is found
7189 */
7190bool SwFrame::GetBackgroundBrush(
7191 drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
7192 const SvxBrushItem* & rpBrush,
7193 const Color*& rpCol,
7194 SwRect &rOrigRect,
7195 bool bLowerMode,
7196 bool bConsiderTextBox ) const
7197{
7198 const SwFrame *pFrame = this;
7199 SwViewShell *pSh = getRootFrame()->GetCurrShell();
7200 const SwViewOption *pOpt = pSh->GetViewOptions();
7201 rpBrush = nullptr;
7202 rpCol = nullptr;
7203 do
7204 {
7205 if ( pFrame->IsPageFrame() && !pOpt->IsPageBack() )
7206 return false;
7207
7208 if (pFrame->supportsFullDrawingLayerFillAttributeSet())
7209 {
7210 bool bHandledTextBox = false;
7211 if (pFrame->IsFlyFrame() && bConsiderTextBox)
7212 {
7213 const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(pFrame);
7214 SwFrameFormat* pShape
7215 = SwTextBoxHelper::getOtherTextBoxFormat(pFlyFrame->GetFormat(), RES_FLYFRMFMT);
7216 if (pShape)
7217 {
7218 SdrObject* pObject = pShape->FindRealSdrObject();
7219 if (pObject)
7220 {
7221 // Work with the fill attributes of the shape of the fly frame.
7222 rFillAttributes =
7223 std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(
7224 pObject->GetMergedItemSet());
7225 bHandledTextBox = true;
7226 }
7227 }
7228 }
7229
7230 if (!bHandledTextBox)
7231 rFillAttributes = pFrame->getSdrAllFillAttributesHelper();
7232 }
7233 const SvxBrushItem &rBack = pFrame->GetAttrSet()->GetBackground();
7234
7235 if( pFrame->IsSctFrame() )
7236 {
7237 const SwSection* pSection = static_cast<const SwSectionFrame*>(pFrame)->GetSection();
7238 // Note: If frame <pFrame> is a section of the index and
7239 // it its background color is "no fill"/"auto fill" and
7240 // it has no background graphic and
7241 // we are not in the page preview and
7242 // we are not in read-only mode and
7243 // option "index shadings" is set and
7244 // the output is not the printer
7245 // then set <rpCol> to the color of the index shading
7246 if( pSection && ( SectionType::ToxHeader == pSection->GetType() ||
7247 SectionType::ToxContent == pSection->GetType() ) &&
7248 (rBack.GetColor() == COL_TRANSPARENT) &&
7249 rBack.GetGraphicPos() == GPOS_NONE &&
7250 !pOpt->IsPagePreview() &&
7251 !pOpt->IsReadonly() &&
7252 // #114856# Form view
7253 !pOpt->IsFormView() &&
7254 SwViewOption::IsIndexShadings() &&
7255 !pOpt->IsPDFExport() &&
7256 pSh->GetOut()->GetOutDevType() != OUTDEV_PRINTER )
7257 {
7258 rpCol = &SwViewOption::GetIndexShadingsColor();
7259 }
7260 }
7261
7262 // determine, if background draw of frame <pFrame> considers transparency
7263 // Status Quo: background transparency have to be
7264 // considered for fly frames
7265 const bool bConsiderBackgroundTransparency = pFrame->IsFlyFrame();
7266
7267 // #i125189# Do not base the decision for using the parent's fill style for this
7268 // frame when the new DrawingLayer FillAttributes are used on the SdrAllFillAttributesHelper
7269 // information. There the data is already optimized to no fill in the case that the
7270 // transparence is at 100% while no fill is the criteria for derivation
7271 bool bNewDrawingLayerFillStyleIsUsedAndNotNoFill(false);
7272
7273 if(rFillAttributes)
7274 {
7275 // the new DrawingLayer FillStyle is used
7276 if(rFillAttributes->isUsed())
7277 {
7278 // it's not drawing::FillStyle_NONE
7279 bNewDrawingLayerFillStyleIsUsedAndNotNoFill = true;
7280 }
7281 else
7282 {
7283 // maybe optimized already when 100% transparency is used somewhere, need to test
7284 // XFillStyleItem directly from the model data
7285 const drawing::FillStyle eFillStyle(pFrame->GetAttrSet()->Get(XATTR_FILLSTYLE).GetValue());
7286
7287 if(drawing::FillStyle_NONE != eFillStyle)
7288 {
7289 bNewDrawingLayerFillStyleIsUsedAndNotNoFill = true;
7290 }
7291 }
7292 }
7293
7294 // add condition:
7295 // If <bConsiderBackgroundTransparency> is set - see above -,
7296 // return brush of frame <pFrame>, if its color is *not* "no fill"/"auto fill"
7297 if (
7298 // #i125189# Done when the new DrawingLayer FillAttributes are used and
7299 // not drawing::FillStyle_NONE (see above)
7300 bNewDrawingLayerFillStyleIsUsedAndNotNoFill ||
7301
7302 // done when SvxBrushItem is used
7303 !rBack.GetColor().GetTransparency() || rBack.GetGraphicPos() != GPOS_NONE ||
7304
7305 // done when direct color is forced
7306 rpCol ||
7307
7308 // done when consider BG transparency and color is not completely transparent
7309 (bConsiderBackgroundTransparency && (rBack.GetColor() != COL_TRANSPARENT))
7310 )
7311 {
7312 rpBrush = &rBack;
7313 if ( pFrame->IsPageFrame() && pSh->GetViewOptions()->getBrowseMode() )
7314 {
7315 rOrigRect = pFrame->getFrameArea();
7316 }
7317 else
7318 {
7319 if ( pFrame->getFrameArea().SSize() != pFrame->getFramePrintArea().SSize() )
7320 {
7321 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pFrame );
7322 const SwBorderAttrs &rAttrs = *aAccess.Get();
7323 ::lcl_CalcBorderRect( rOrigRect, pFrame, rAttrs, false, gProp );
7324 }
7325 else
7326 {
7327 rOrigRect = pFrame->getFramePrintArea();
7328 rOrigRect += pFrame->getFrameArea().Pos();
7329 }
7330 }
7331
7332 return true;
7333 }
7334
7335 if ( bLowerMode )
7336 {
7337 // Do not try to get background brush from parent (anchor/upper)
7338 return false;
7339 }
7340
7341 // get parent frame - anchor or upper - for next loop
7342 if ( pFrame->IsFlyFrame() )
7343 {
7344 pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
7345 }
7346 else
7347 {
7348 pFrame = pFrame->GetUpper();
7349 }
7350 } while ( pFrame );
7351
7352 return false;
7353}
7354
7355void SetOutDevAndWin( SwViewShell *pSh, OutputDevice *pO,
7356 vcl::Window *pW, sal_uInt16 nZoom )
7357{
7358 pSh->mpOut = pO;
7359 pSh->mpWin = pW;
7360 pSh->mpOpt->SetZoom( nZoom );
7361}
7362
7363Graphic SwFrameFormat::MakeGraphic( ImageMap* )
7364{
7365 return Graphic();
7366}
7367
7368Graphic SwFlyFrameFormat::MakeGraphic( ImageMap* pMap )
7369{
7370 Graphic aRet;
7371 //search any Fly!
7372 SwIterator<SwFrame,SwFormat> aIter( *this );
7373 SwFrame *pFirst = aIter.First();
7374 SwViewShell *const pSh =
7375 pFirst ? pFirst->getRootFrame()->GetCurrShell() : nullptr;
7376 if (nullptr != pSh)
7377 {
7378 SwViewShell *pOldGlobal = gProp.pSGlobalShell;
7379 gProp.pSGlobalShell = pSh;
7380
7381 bool bNoteURL = pMap &&
7382 SfxItemState::SET != GetAttrSet().GetItemState( RES_URL );
7383 if( bNoteURL )
7384 {
7385 OSL_ENSURE( !pNoteURL, "MakeGraphic: pNoteURL already used? " )do { if (true && (!(!pNoteURL))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "7385" ": "), "%s", "MakeGraphic: pNoteURL already used? "
); } } while (false)
;
7386 pNoteURL = new SwNoteURL;
7387 }
7388 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pFirst);
7389
7390 OutputDevice *pOld = pSh->GetOut();
7391 ScopedVclPtrInstance< VirtualDevice > pDev( *pOld );
7392 pDev->EnableOutput( false );
7393
7394 GDIMetaFile aMet;
7395 MapMode aMap( pOld->GetMapMode().GetMapUnit() );
7396 pDev->SetMapMode( aMap );
7397 aMet.SetPrefMapMode( aMap );
7398
7399 ::SwCalcPixStatics( pSh->GetOut() );
7400 aMet.SetPrefSize( pFly->getFrameArea().SSize() );
7401
7402 aMet.Record( pDev.get() );
7403 pDev->SetLineColor();
7404 pDev->SetFillColor();
7405 pDev->SetFont( pOld->GetFont() );
7406
7407 //Enlarge the rectangle if needed, so the border is painted too.
7408 SwRect aOut( pFly->getFrameArea() );
7409 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pFly );
7410 const SwBorderAttrs &rAttrs = *aAccess.Get();
7411 if ( rAttrs.CalcRightLine() )
7412 aOut.AddWidth(2*gProp.nSPixelSzW );
7413 if ( rAttrs.CalcBottomLine() )
7414 aOut.AddHeight(2*gProp.nSPixelSzH );
7415
7416 // #i92711# start Pre/PostPaint encapsulation before pOut is changed to the buffering VDev
7417 const vcl::Region aRepaintRegion(aOut.SVRect());
7418 pSh->DLPrePaint2(aRepaintRegion);
7419
7420 vcl::Window *pWin = pSh->GetWin();
7421 sal_uInt16 nZoom = pSh->GetViewOptions()->GetZoom();
7422 ::SetOutDevAndWin( pSh, pDev, nullptr, 100 );
7423 gProp.bSFlyMetafile = true;
7424 gProp.pSFlyMetafileOut = pWin;
7425
7426 SwViewShellImp *pImp = pSh->Imp();
7427 gProp.pSFlyOnlyDraw = pFly;
7428 gProp.pSLines.reset(new SwLineRects);
7429
7430 // determine page, fly frame is on
7431 const SwPageFrame* pFlyPage = pFly->FindPageFrame();
7432 const Color aPageBackgrdColor(pFlyPage->GetDrawBackgrdColor());
7433 const IDocumentDrawModelAccess& rIDDMA = pSh->getIDocumentDrawModelAccess();
7434 // --> OD #i76669#
7435 SwViewObjectContactRedirector aSwRedirector( *pSh );
7436 // <--
7437 pImp->PaintLayer( rIDDMA.GetHellId(), nullptr,
7438 *pFlyPage, aOut, &aPageBackgrdColor,
7439 pFlyPage->IsRightToLeft(),
7440 &aSwRedirector );
7441 gProp.pSLines->PaintLines( pDev, gProp );
7442 if ( pFly->IsFlyInContentFrame() )
7443 pFly->PaintSwFrame( *pDev, aOut );
7444 gProp.pSLines->PaintLines( pDev, gProp );
7445 pImp->PaintLayer( rIDDMA.GetHeavenId(), nullptr,
7446 *pFlyPage, aOut, &aPageBackgrdColor,
7447 pFlyPage->IsRightToLeft(),
7448 &aSwRedirector );
7449 gProp.pSLines->PaintLines( pDev, gProp );
7450 gProp.pSLines.reset();
7451 gProp.pSFlyOnlyDraw = nullptr;
7452
7453 gProp.pSFlyMetafileOut = nullptr;
7454 gProp.bSFlyMetafile = false;
7455 ::SetOutDevAndWin( pSh, pOld, pWin, nZoom );
7456
7457 // #i92711# end Pre/PostPaint encapsulation when pOut is back and content is painted
7458 pSh->DLPostPaint2(true);
7459
7460 aMet.Stop();
7461 aMet.Move( -pFly->getFrameArea().Left(), -pFly->getFrameArea().Top() );
7462 aRet = Graphic( aMet );
7463
7464 if( bNoteURL )
7465 {
7466 OSL_ENSURE( pNoteURL, "MakeGraphic: Good Bye, NoteURL." )do { if (true && (!(pNoteURL))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx"
":" "7466" ": "), "%s", "MakeGraphic: Good Bye, NoteURL."); }
} while (false)
;
7467 delete pNoteURL;
7468 pNoteURL = nullptr;
7469 }
7470 gProp.pSGlobalShell = pOldGlobal;
7471 }
7472 return aRet;
7473}
7474
7475Graphic SwDrawFrameFormat::MakeGraphic( ImageMap* )
7476{
7477 Graphic aRet;
7478 SwDrawModel* pMod = getIDocumentDrawModelAccess().GetDrawModel();
7479 if ( pMod )
7480 {
7481 SdrObject *pObj = FindSdrObject();
7482 std::unique_ptr<SdrView> pView( new SdrView( *pMod ) );
7483 SdrPageView *pPgView = pView->ShowSdrPage(pView->GetModel()->GetPage(0));
7484 pView->MarkObj( pObj, pPgView );
7485 aRet = pView->GetMarkedObjBitmapEx();
7486 pView->HideSdrPage();
7487 }
7488 return aRet;
7489}
7490
7491/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/source/core/inc/frame.hxx

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#ifndef INCLUDED_SW_SOURCE_CORE_INC_FRAME_HXX
21#define INCLUDED_SW_SOURCE_CORE_INC_FRAME_HXX
22
23#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
24#include <editeng/borderline.hxx>
25#include <svl/poolitem.hxx>
26#include <swtypes.hxx>
27#include <swrect.hxx>
28#include <calbck.hxx>
29#include <svl/SfxBroadcaster.hxx>
30#include <o3tl/typed_flags_set.hxx>
31#include <com/sun/star/style/TabStop.hpp>
32#include <basegfx/matrix/b2dhommatrix.hxx>
33#include <vcl/outdev.hxx>
34
35#include <memory>
36
37namespace drawinglayer::processor2d { class BaseProcessor2D; }
38
39class SwLayoutFrame;
40class SwRootFrame;
41class SwPageFrame;
42class SwBodyFrame;
43class SwFlyFrame;
44class SwSectionFrame;
45class SwFootnoteFrame;
46class SwFootnoteBossFrame;
47class SwTabFrame;
48class SwRowFrame;
49class SwContentFrame;
50class SwAttrSet;
51class Color;
52class SwBorderAttrs;
53class SwCache;
54class SvxBrushItem;
55class SvxFormatBreakItem;
56class SwFormatPageDesc;
57class SwSelectionList;
58struct SwPosition;
59struct SwCursorMoveState;
60class SwFormat;
61class SwPrintData;
62class SwSortedObjs;
63class SwAnchoredObject;
64enum class SvxFrameDirection;
65class IDocumentDrawModelAccess;
66
67// Each FrameType is represented here as a bit.
68// The bits must be set in a way that it can be determined with masking of
69// which kind of FrameType an instance is _and_ from what classes it was derived.
70// Each frame has in its base class a member that must be set by the
71// constructors accordingly.
72enum class SwFrameType
73{
74 None = 0x0000,
75 Root = 0x0001,
76 Page = 0x0002,
77 Column = 0x0004,
78 Header = 0x0008,
79 Footer = 0x0010,
80 FtnCont = 0x0020,
81 Ftn = 0x0040,
82 Body = 0x0080,
83 Fly = 0x0100,
84 Section = 0x0200,
85// UNUSED 0x0400
86 Tab = 0x0800,
87 Row = 0x1000,
88 Cell = 0x2000,
89 Txt = 0x4000,
90 NoTxt = 0x8000,
91};
92
93namespace o3tl
94{
95 template<> struct typed_flags<SwFrameType> : is_typed_flags<SwFrameType, 0xfbff> {};
96};
97
98// for internal use some common combinations
99#define FRM_LAYOUTSwFrameType(0x3bFF) SwFrameType(0x3bFF)
100#define FRM_ALLSwFrameType(0xfbff) SwFrameType(0xfbff)
101#define FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt) (SwFrameType::Txt | SwFrameType::NoTxt)
102#define FRM_FTNBOSS(SwFrameType::Page | SwFrameType::Column) (SwFrameType::Page | SwFrameType::Column)
103#define FRM_ACCESSIBLE(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType
::Tab | SwFrameType::Cell | SwFrameType::Txt)
(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header | SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType::Tab | SwFrameType::Cell | SwFrameType::Txt)
104#define FRM_NEIGHBOUR(SwFrameType::Column | SwFrameType::Cell) (SwFrameType::Column | SwFrameType::Cell)
105#define FRM_NOTE_VERT(SwFrameType::FtnCont | SwFrameType::Ftn | SwFrameType::Section
| SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell | SwFrameType
::Txt)
(SwFrameType::FtnCont | SwFrameType::Ftn | SwFrameType::Section | SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell | SwFrameType::Txt)
106#define FRM_HEADFOOT(SwFrameType::Header | SwFrameType::Footer) (SwFrameType::Header | SwFrameType::Footer)
107#define FRM_BODYFTNC(SwFrameType::FtnCont | SwFrameType::Body) (SwFrameType::FtnCont | SwFrameType::Body)
108
109// for GetNextLeaf/GetPrevLeaf.
110enum MakePageType
111{
112 MAKEPAGE_NONE, // do not create page/footnote
113 MAKEPAGE_APPEND, // only append page if needed
114 MAKEPAGE_INSERT, // add or append page if needed
115 MAKEPAGE_FTN, // add footnote if needed
116 MAKEPAGE_NOSECTION // Don't create section frames
117};
118
119namespace drawinglayer::attribute {
120 class SdrAllFillAttributesHelper;
121 typedef std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr;
122}
123
124/// Helper class to isolate geometry-defining members of SwFrame
125/// and to control their accesses. Moved to own class to have no
126/// hidden accesses to 'private' members anymore.
127///
128/// Added most important flags about the state of this geometric
129/// information and if it is valid or not
130class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SwFrameAreaDefinition
131{
132private:
133 friend void FriendHackInvalidateRowFrame(SwFrameAreaDefinition &);
134
135 // The absolute position and size of the SwFrame in the document.
136 // This values are set by the layouter implementations
137 SwRect maFrameArea;
138
139 // The 'inner' Frame Area defined by a SwRect relative to FrameArea:
140 // When identical to FrameArea, Pos() will be (0, 0) and Size identical.
141 SwRect maFramePrintArea;
142
143 // bitfield
144 bool mbFrameAreaPositionValid : 1;
145 bool mbFrameAreaSizeValid : 1;
146 bool mbFramePrintAreaValid : 1;
147
148 // #i65250#
149 // frame ID is now in general available - used for layout loop control
150 static sal_uInt32 mnLastFrameId;
151 const sal_uInt32 mnFrameId;
152
153protected:
154 // write access to mb*Valid flags
155 void setFrameAreaPositionValid(bool bNew);
156 void setFrameAreaSizeValid(bool bNew);
157 void setFramePrintAreaValid(bool bNew);
158
159public:
160 SwFrameAreaDefinition();
161 virtual ~SwFrameAreaDefinition();
162
163 // read access to mb*Valid flags
164 bool isFrameAreaPositionValid() const { return mbFrameAreaPositionValid; }
165 bool isFrameAreaSizeValid() const { return mbFrameAreaSizeValid; }
166 bool isFramePrintAreaValid() const { return mbFramePrintAreaValid; }
167
168 // syntactic sugar: test whole FrameAreaDefinition
169 bool isFrameAreaDefinitionValid() const { return isFrameAreaPositionValid() && isFrameAreaSizeValid() && isFramePrintAreaValid(); }
170
171 // #i65250#
172 sal_uInt32 GetFrameId() const { return mnFrameId; }
173
174 // read accesses to FrameArea definitions - only const access allowed.
175 // Do *not* const_cast results, it is necessary to track changes. use
176 // the below offered WriteAccess helper classes instead
177 const SwRect& getFrameArea() const { return maFrameArea; }
178 const SwRect& getFramePrintArea() const { return maFramePrintArea; }
179
180 // helper class(es) for FrameArea manipulation. These
181 // have to be used to apply changes to FrameAreas. They hold a copy of the
182 // SwRect for manipulation. It gets written back at destruction. Thus, this
183 // mechanism depends on scope usage, take care. It prevents errors using
184 // different instances of SwFrame in get/set methods which is more safe
185 class FrameAreaWriteAccess : public SwRect
186 {
187 private:
188 SwFrameAreaDefinition& mrTarget;
189
190 FrameAreaWriteAccess(const FrameAreaWriteAccess&) = delete;
191 FrameAreaWriteAccess& operator=(const FrameAreaWriteAccess&) = delete;
192
193 public:
194 FrameAreaWriteAccess(SwFrameAreaDefinition& rTarget) : SwRect(rTarget.getFrameArea()), mrTarget(rTarget) {}
195 ~FrameAreaWriteAccess();
196 void setSwRect(const SwRect& rNew) { *reinterpret_cast< SwRect* >(this) = rNew; }
197 };
198
199 // same helper for FramePrintArea
200 class FramePrintAreaWriteAccess : public SwRect
201 {
202 private:
203 SwFrameAreaDefinition& mrTarget;
204
205 FramePrintAreaWriteAccess(const FramePrintAreaWriteAccess&) = delete;
206 FramePrintAreaWriteAccess& operator=(const FramePrintAreaWriteAccess&) = delete;
207
208 public:
209 FramePrintAreaWriteAccess(SwFrameAreaDefinition& rTarget) : SwRect(rTarget.getFramePrintArea()), mrTarget(rTarget) {}
210 ~FramePrintAreaWriteAccess();
211 void setSwRect(const SwRect& rNew) { *reinterpret_cast< SwRect* >(this) = rNew; }
212 };
213
214 // RotateFlyFrame3 - Support for Transformations
215 // Hand out the Transformations for the current FrameAreaDefinition
216 // for the FrameArea and FramePrintArea.
217 // FramePrintArea is not relative to FrameArea in this
218 // transformation representation (to make it easier to use and understand).
219 // There is no 'set' method since SwFrame is a layout object. For
220 // some cases rotation will be included (used for SwGrfNode in inner
221 // SwFrame of a SwFlyFrame)
222 virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const;
223 virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
224
225 // RotateFlyFrame3 - Support for Transformations
226 // Modify current transformations by applying given translation
227 virtual void transform_translate(const Point& rOffset);
228};
229
230/// RotateFlyFrame3: Helper class when you want to make your SwFrame derivate
231/// transformable. It provides some tooling to do so. To use, add as member
232/// (see e.g. SwFlyFreeFrame which uses 'std::unique_ptr< TransformableSwFrame >')
233class TransformableSwFrame
234{
235private:
236 // The SwFrameAreaDefinition to work on
237 SwFrameAreaDefinition& mrSwFrameAreaDefinition;
238
239 // FrameAreaTransformation and FramePrintAreaTransformation
240 // !identity when needed (translate/scale is used (e.g. rotation))
241 basegfx::B2DHomMatrix maFrameAreaTransformation;
242 basegfx::B2DHomMatrix maFramePrintAreaTransformation;
243
244public:
245 TransformableSwFrame(SwFrameAreaDefinition& rSwFrameAreaDefinition)
246 : mrSwFrameAreaDefinition(rSwFrameAreaDefinition),
247 maFrameAreaTransformation(),
248 maFramePrintAreaTransformation()
249 {
250 }
251
252 // get SwFrameArea in transformation form
253 const basegfx::B2DHomMatrix& getLocalFrameAreaTransformation() const
254 {
255 return maFrameAreaTransformation;
256 }
257
258 // get SwFramePrintArea in transformation form
259 const basegfx::B2DHomMatrix& getLocalFramePrintAreaTransformation() const
260 {
261 return maFramePrintAreaTransformation;
262 }
263
264 // Helpers to re-create the untransformed SwRect(s) originally
265 // in the SwFrameAreaDefinition, based on the current Transformations.
266 SwRect getUntransformedFrameArea() const;
267 SwRect getUntransformedFramePrintArea() const;
268
269 // Helper method to re-create FrameAreaTransformations based on the
270 // current FrameAreaDefinition transformed by given rotation and Center
271 void createFrameAreaTransformations(
272 double fRotation,
273 const basegfx::B2DPoint& rCenter);
274
275 // Tooling method to reset the SwRect(s) in the current
276 // SwFrameAreaDefinition which are already adapted to
277 // Transformation back to the untransformed state, using
278 // the getUntransformedFrame*Area calls above when needed.
279 // Only the SwRect(s) are changed back, not the transformations.
280 void restoreFrameAreas();
281
282 // Re-Creates the SwRect(s) as BoundAreas based on the current
283 // set Transformations.
284 void adaptFrameAreasToTransformations();
285
286 // Modify current definitions by applying the given transformation
287 void transform(const basegfx::B2DHomMatrix& aTransform);
288};
289
290/**
291 * Base class of the Writer layout elements.
292 *
293 * This includes not only fly frames, but everything down to the paragraph
294 * level: pages, headers, footers, etc. (Inside a paragraph SwLinePortion
295 * instances are used.)
296 */
297class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwFrame : public SwFrameAreaDefinition, public SwClient, public SfxBroadcaster
298{
299 // the hidden Frame
300 friend class SwFlowFrame;
301 friend class SwLayoutFrame;
302 friend class SwLooping;
303 friend class SwDeletionChecker; // for GetDep()
304
305 // voids lower during creation of a column
306 friend SwFrame *SaveContent( SwLayoutFrame *, SwFrame* pStart );
307 friend void RestoreContent( SwFrame *, SwLayoutFrame *, SwFrame *pSibling );
308
309 // for validating a mistakenly invalidated one in SwContentFrame::MakeAll
310 friend void ValidateSz( SwFrame *pFrame );
311 // implemented in text/txtftn.cxx, prevents Footnote oscillation
312 friend void ValidateText( SwFrame *pFrame );
313
314 friend void MakeNxt( SwFrame *pFrame, SwFrame *pNxt );
315
316 // cache for (border) attributes
317 static SwCache *mpCache;
318
319 SwRootFrame *mpRoot;
320 SwLayoutFrame *mpUpper;
321 SwFrame *mpNext;
322 SwFrame *mpPrev;
323
324 // sw_redlinehide: hide these dangerous SwClient functions
325 using SwClient::GetRegisteredInNonConst;
326 using SwClient::GetRegisteredIn;
327
328 SwFrame *FindNext_();
329 SwFrame *FindPrev_();
330
331 /** method to determine next content frame in the same environment
332 for a flow frame (content frame, table frame, section frame)
333
334 #i27138# - adding documentation:
335 Travelling downwards through the layout to determine the next content
336 frame in the same environment. There are several environments in a
337 document, which form a closed context regarding this function. These
338 environments are:
339 - Each page header
340 - Each page footer
341 - Each unlinked fly frame
342 - Each group of linked fly frames
343 - All footnotes
344 - All document body frames
345 #i27138# - adding parameter <_bInSameFootnote>
346 Its default value is <false>. If its value is <true>, the environment
347 'All footnotes' is no longer treated. Instead each footnote is treated
348 as an own environment.
349
350 @param _bInSameFootnote
351 input parameter - boolean indicating, that the found next content
352 frame has to be in the same footnote frame. This parameter is only
353 relevant for flow frames in footnotes.
354
355 @return SwContentFrame*
356 pointer to the found next content frame. It's NULL, if none exists.
357 */
358 SwContentFrame* FindNextCnt_( const bool _bInSameFootnote );
359
360 /** method to determine previous content frame in the same environment
361 for a flow frame (content frame, table frame, section frame)
362
363 #i27138#
364 Travelling upwards through the layout to determine the previous content
365 frame in the same environment. There are several environments in a
366 document, which form a closed context regarding this function. These
367 environments are:
368 - Each page header
369 - Each page footer
370 - Each unlinked fly frame
371 - Each group of linked fly frames
372 - All footnotes
373 - All document body frames
374 #i27138# - adding parameter <_bInSameFootnote>
375 Its default value is <false>. If its value is <true>, the environment
376 'All footnotes' is no longer treated. Instead each footnote is treated
377 as an own environment.
378
379 The found previous content frame has to be in the same footnote frame. This is only
380 relevant for flow frames in footnotes.
381
382 @return SwContentFrame*
383 pointer to the found previous content frame. It's NULL, if none exists.
384 */
385 SwContentFrame* FindPrevCnt_();
386
387 void UpdateAttrFrame( const SfxPoolItem*, const SfxPoolItem*, sal_uInt8 & );
388 SwFrame* GetIndNext_();
389 void SetDirFlags( bool bVert );
390
391 const SwLayoutFrame* ImplGetNextLayoutLeaf( bool bFwd ) const;
392
393 SwPageFrame* ImplFindPageFrame();
394
395protected:
396 std::unique_ptr<SwSortedObjs> m_pDrawObjs; // draw objects, can be null
397 SwFrameType mnFrameType; //Who am I?
398
399 bool mbInDtor : 1;
400 bool mbInvalidR2L : 1;
401 bool mbDerivedR2L : 1;
402 bool mbRightToLeft : 1;
403 bool mbInvalidVert : 1;
404 bool mbDerivedVert : 1;
405 bool mbVertical : 1;
406
407 bool mbVertLR : 1;
408 bool mbVertLRBT : 1;
409
410 bool mbValidLineNum : 1;
411 bool mbFixSize : 1;
412
413 // if true, frame will be painted completely even content was changed
414 // only partially. For ContentFrames a border (from Action) will exclusively
415 // painted if <mbCompletePaint> is true.
416 bool mbCompletePaint : 1;
417
418 bool mbRetouche : 1; // frame is responsible for retouching
419
420 bool mbInfInvalid : 1; // InfoFlags are invalid
421 bool mbInfBody : 1; // Frame is in document body
422 bool mbInfTab : 1; // Frame is in a table
423 bool mbInfFly : 1; // Frame is in a Fly
424 bool mbInfFootnote : 1; // Frame is in a footnote
425 bool mbInfSct : 1; // Frame is in a section
426 bool mbColLocked : 1; // lock Grow/Shrink for column-wise section
427 // or fly frames, will be set in Format
428 bool m_isInDestroy : 1;
429 bool mbForbidDelete : 1;
430
431 void ColLock() { mbColLocked = true; }
432 void ColUnlock() { mbColLocked = false; }
433
434 virtual void DestroyImpl();
435 virtual ~SwFrame() override;
436
437 // Only used by SwRootFrame Ctor to get 'this' into mpRoot...
438 void setRootFrame( SwRootFrame* pRoot ) { mpRoot = pRoot; }
439
440 SwPageFrame *InsertPage( SwPageFrame *pSibling, bool bFootnote );
441 void PrepareMake(vcl::RenderContext* pRenderContext);
442 void OptPrepareMake();
443 virtual void MakePos();
444 // Format next frame of table frame to assure keeping attributes.
445 // In case of nested tables method <SwFrame::MakeAll()> is called to
446 // avoid formatting of superior table frame.
447 friend SwFrame* sw_FormatNextContentForKeep( SwTabFrame* pTabFrame );
448
449 virtual void MakeAll(vcl::RenderContext* pRenderContext) = 0;
450 // adjust frames of a page
451 SwTwips AdjustNeighbourhood( SwTwips nDiff, bool bTst = false );
452
453 // change only frame size not the size of PrtArea
454 virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) = 0;
455 virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) = 0;
456
457 /// use these so we can grep for SwFrame's GetRegisteredIn accesses
458 /// beware that SwTextFrame may return sw::WriterMultiListener
459 SwModify *GetDep() { return GetRegisteredInNonConst(); }
460 const SwModify *GetDep() const { return GetRegisteredIn(); }
461
462 SwFrame( SwModify*, SwFrame* );
463
464 void CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool bBrowse );
465
466 /** enumeration for the different invalidations
467 #i28701#
468 */
469 enum InvalidationType
470 {
471 INVALID_SIZE, INVALID_PRTAREA, INVALID_POS, INVALID_LINENUM, INVALID_ALL
472 };
473
474 /** method to determine, if an invalidation is allowed.
475 #i28701
476 */
477 virtual bool InvalidationAllowed( const InvalidationType _nInvalid ) const;
478
479 /** method to perform additional actions on an invalidation
480
481 #i28701#
482 Method has *only* to contain actions, which has to be performed on
483 *every* assignment of the corresponding flag to <false>.
484 */
485 virtual void ActionOnInvalidation( const InvalidationType _nInvalid );
486
487 // draw shadow and borders
488 void PaintShadow( const SwRect&, SwRect&, const SwBorderAttrs& ) const;
489 virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
490
491 virtual const IDocumentDrawModelAccess& getIDocumentDrawModelAccess( );
492
493public:
494 virtual css::uno::Sequence< css::style::TabStop > GetTabStopInfo( SwTwips )
495 {
496 return css::uno::Sequence< css::style::TabStop >();
497 }
498
499
500 SwFrameType GetType() const { return mnFrameType; }
501
502 static SwCache &GetCache() { return *mpCache; }
503 static SwCache *GetCachePtr() { return mpCache; }
504 static void SetCache( SwCache *pNew ) { mpCache = pNew; }
505
506 // change PrtArea size and FrameSize
507 SwTwips Shrink( SwTwips, bool bTst = false, bool bInfo = false );
508 SwTwips Grow ( SwTwips, bool bTst = false, bool bInfo = false );
509
510 // different methods for inserting in layout tree (for performance reasons)
511
512 // insert before pBehind or at the end of the chain below mpUpper
513 void InsertBefore( SwLayoutFrame* pParent, SwFrame* pBehind );
514 // insert after pBefore or at the beginning of the chain below mpUpper
515 void InsertBehind( SwLayoutFrame *pParent, SwFrame *pBefore );
516 // insert before pBehind or at the end of the chain while considering
517 // the siblings of pSct
518 bool InsertGroupBefore( SwFrame* pParent, SwFrame* pWhere, SwFrame* pSct );
519 void RemoveFromLayout();
520
521 // For internal use only - who ignores this will be put in a sack and has
522 // to stay there for two days
523 // Does special treatment for Get_[Next|Prev]Leaf() (for tables).
524 SwLayoutFrame *GetLeaf( MakePageType eMakePage, bool bFwd );
525 SwLayoutFrame *GetNextLeaf ( MakePageType eMakePage );
526 SwLayoutFrame *GetNextFootnoteLeaf( MakePageType eMakePage );
527 SwLayoutFrame *GetNextSctLeaf( MakePageType eMakePage );
528 SwLayoutFrame *GetNextCellLeaf();
529 SwLayoutFrame *GetPrevLeaf ();
530 SwLayoutFrame *GetPrevFootnoteLeaf( MakePageType eMakeFootnote );
531 SwLayoutFrame *GetPrevSctLeaf();
532 SwLayoutFrame *GetPrevCellLeaf();
533 const SwLayoutFrame *GetLeaf ( MakePageType eMakePage, bool bFwd,
534 const SwFrame *pAnch ) const;
535
536 bool WrongPageDesc( SwPageFrame* pNew );
537
538 //#i28701# - new methods to append/remove drawing objects
539 void AppendDrawObj( SwAnchoredObject& _rNewObj );
540 void RemoveDrawObj( SwAnchoredObject& _rToRemoveObj );
541
542 // work with chain of FlyFrames
543 void AppendFly( SwFlyFrame *pNew );
544 void RemoveFly( SwFlyFrame *pToRemove );
545 const SwSortedObjs *GetDrawObjs() const { return m_pDrawObjs.get(); }
546 SwSortedObjs *GetDrawObjs() { return m_pDrawObjs.get(); }
547 // #i28701# - change purpose of method and adjust its name
548 void InvalidateObjs( const bool _bNoInvaOfAsCharAnchoredObjs = true );
549
550 virtual void PaintSwFrameShadowAndBorder(
551 const SwRect&,
552 const SwPageFrame* pPage,
553 const SwBorderAttrs&) const;
554 void PaintBaBo( const SwRect&, const SwPageFrame *pPage,
555 const bool bOnlyTextBackground = false) const;
556 void PaintSwFrameBackground( const SwRect&, const SwPageFrame *pPage,
557 const SwBorderAttrs &,
558 const bool bLowerMode = false,
559 const bool bLowerBorder = false,
560 const bool bOnlyTextBackground = false ) const;
561 void PaintBorderLine( const SwRect&, const SwRect&, const SwPageFrame*,
562 const Color *pColor,
563 const SvxBorderLineStyle = SvxBorderLineStyle::SOLID ) const;
564
565 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> CreateProcessor2D( ) const;
566 void ProcessPrimitives( const drawinglayer::primitive2d::Primitive2DContainer& rSequence ) const;
567
568 // retouch, not in the area of the given Rect!
569 void Retouch( const SwPageFrame *pPage, const SwRect &rRect ) const;
570
571 bool GetBackgroundBrush(
572 drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
573 const SvxBrushItem*& rpBrush,
574 const Color*& rpColor,
575 SwRect &rOrigRect,
576 bool bLowerMode,
577 bool bConsiderTextBox ) const;
578
579 inline void SetCompletePaint() const;
580 inline void ResetCompletePaint() const;
581 bool IsCompletePaint() const { return mbCompletePaint; }
582
583 inline void SetRetouche() const;
584 inline void ResetRetouche() const;
585 bool IsRetouche() const { return mbRetouche; }
586
587 void SetInfFlags();
588 void InvalidateInfFlags() { mbInfInvalid = true; }
589 inline bool IsInDocBody() const; // use InfoFlags, determine flags
590 inline bool IsInFootnote() const; // if necessary
591 inline bool IsInTab() const;
592 inline bool IsInFly() const;
593 inline bool IsInSct() const;
594
595 // If frame is inside a split table row, this function returns
596 // the corresponding row frame in the follow table.
597 const SwRowFrame* IsInSplitTableRow() const;
598
599 // If frame is inside a follow flow row, this function returns
600 // the corresponding row frame master table
601 const SwRowFrame* IsInFollowFlowRow() const;
602
603 bool IsInBalancedSection() const;
604
605 inline bool IsVertical() const;
606 inline bool IsVertLR() const;
607 inline bool IsVertLRBT() const;
608
609 void SetDerivedVert( bool bNew ){ mbDerivedVert = bNew; }
610 void SetInvalidVert( bool bNew) { mbInvalidVert = bNew; }
611 inline bool IsRightToLeft() const;
612 void SetDerivedR2L( bool bNew ) { mbDerivedR2L = bNew; }
613
614 void CheckDirChange();
615 // returns upper left frame position for LTR and
616 // upper right frame position for Asian / RTL frames
617 Point GetFrameAnchorPos( bool bIgnoreFlysAnchoredAtThisFrame ) const;
618
619 /** determine, if frame is moveable in given environment
620
621 method replaced 'old' method <bool IsMoveable() const>.
622 Determines, if frame is moveable in given environment. if no environment
623 is given (parameter _pLayoutFrame == 0), the movability in the actual
624 environment (<GetUpper()) is checked.
625
626 @param _pLayoutFrame
627 input parameter - given environment (layout frame), in which the movability
628 will be checked. If not set ( == 0 ), actual environment is taken.
629
630 @return boolean, indicating, if frame is moveable in given environment
631 */
632 bool IsMoveable( const SwLayoutFrame* _pLayoutFrame = nullptr ) const;
633
634 // Is it permitted for the (Text)Frame to add a footnote in the current
635 // environment (not e.g. for repeating table headlines)
636 bool IsFootnoteAllowed() const;
637
638 virtual void Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr );
639
640 virtual void CheckDirection( bool bVert );
641
642 void ReinitializeFrameSizeAttrFlags();
643
644 /// WARNING: this may not return correct RES_PAGEDESC/RES_BREAK items for
645 /// SwTextFrame, use GetBreakItem()/GetPageDescItem() instead
646 const SwAttrSet *GetAttrSet() const;
647 virtual const SvxFormatBreakItem& GetBreakItem() const;
648 virtual const SwFormatPageDesc& GetPageDescItem() const;
649
650 bool HasFixSize() const { return mbFixSize; }
651
652 // check all pages (starting from the given) and correct them if needed
653 static void CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields = true, SwPageFrame** ppPrev = nullptr);
654
655 // might return 0, with and without const
656 SwFrame *GetNext() { return mpNext; }
657 SwFrame *GetPrev() { return mpPrev; }
658 SwLayoutFrame *GetUpper() { return mpUpper; }
659 SwRootFrame *getRootFrame(){ return mpRoot; }
660 SwPageFrame *FindPageFrame() { return IsPageFrame() ? reinterpret_cast<SwPageFrame*>(this) : ImplFindPageFrame(); }
14
'?' condition is true
15
Returning pointer, which participates in a condition later
661 SwFrame *FindColFrame();
662 SwRowFrame *FindRowFrame();
663 SwFootnoteBossFrame *FindFootnoteBossFrame( bool bFootnotes = false );
664 SwTabFrame *ImplFindTabFrame();
665 SwFootnoteFrame *ImplFindFootnoteFrame();
666 SwFlyFrame *ImplFindFlyFrame();
667 SwSectionFrame *ImplFindSctFrame();
668 const SwBodyFrame *ImplFindBodyFrame() const;
669 SwFrame *FindFooterOrHeader();
670 SwFrame *GetLower();
671 const SwFrame *GetNext() const { return mpNext; }
672 const SwFrame *GetPrev() const { return mpPrev; }
673 const SwLayoutFrame *GetUpper() const { return mpUpper; }
674 const SwRootFrame *getRootFrame() const { return mpRoot; }
675 inline SwTabFrame *FindTabFrame();
676 inline SwFootnoteFrame *FindFootnoteFrame();
677 inline SwFlyFrame *FindFlyFrame();
678 inline SwSectionFrame *FindSctFrame();
679 inline SwFrame *FindNext();
680 // #i27138# - add parameter <_bInSameFootnote>
681 SwContentFrame* FindNextCnt( const bool _bInSameFootnote = false );
682 inline SwFrame *FindPrev();
683 inline const SwPageFrame *FindPageFrame() const;
684 inline const SwFootnoteBossFrame *FindFootnoteBossFrame( bool bFootnote = false ) const;
685 inline const SwFrame *FindColFrame() const;
686 inline const SwFrame *FindFooterOrHeader() const;
687 inline const SwTabFrame *FindTabFrame() const;
688 inline const SwFootnoteFrame *FindFootnoteFrame() const;
689 inline const SwFlyFrame *FindFlyFrame() const;
690 inline const SwSectionFrame *FindSctFrame() const;
691 inline const SwBodyFrame *FindBodyFrame() const;
692 inline const SwFrame *FindNext() const;
693 // #i27138# - add parameter <_bInSameFootnote>
694 const SwContentFrame* FindNextCnt( const bool _bInSameFootnote = false ) const;
695 inline const SwFrame *FindPrev() const;
696 const SwFrame *GetLower() const;
697
698 SwContentFrame* FindPrevCnt();
699
700 const SwContentFrame* FindPrevCnt() const;
701
702 // #i79774#
703 SwFrame* GetIndPrev_() const;
704 SwFrame* GetIndPrev() const
705 { return ( mpPrev || !IsInSct() ) ? mpPrev : GetIndPrev_(); }
706
707 SwFrame* GetIndNext()
708 { return ( mpNext || !IsInSct() ) ? mpNext : GetIndNext_(); }
709 const SwFrame* GetIndNext() const { return const_cast<SwFrame*>(this)->GetIndNext(); }
710
711 sal_uInt16 GetPhyPageNum() const; // page number without offset
712 sal_uInt16 GetVirtPageNum() const; // page number with offset
713 bool OnRightPage() const { return 0 != GetPhyPageNum() % 2; };
714 bool WannaRightPage() const;
715 bool OnFirstPage() const;
716
717 inline const SwLayoutFrame *GetPrevLayoutLeaf() const;
718 inline const SwLayoutFrame *GetNextLayoutLeaf() const;
719 inline SwLayoutFrame *GetPrevLayoutLeaf();
720 inline SwLayoutFrame *GetNextLayoutLeaf();
721
722 virtual void Calc(vcl::RenderContext* pRenderContext) const; // here might be "formatted"
723 inline void OptCalc() const; // here we assume (for optimization) that
724 // the predecessors are already formatted
725 Point GetRelPos() const;
726
727 // PaintArea is the area where content might be displayed.
728 // The margin of a page or the space between columns belongs to it.
729 SwRect GetPaintArea() const;
730
731 // UnionFrame is the union of Frame- and PrtArea, normally identical
732 // to the FrameArea except in case of negative Prt margins.
733 SwRect UnionFrame( bool bBorder = false ) const;
734
735 virtual Size ChgSize( const Size& aNewSize );
736
737 virtual void Cut() = 0;
738 virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) = 0;
739
740 void ValidateLineNum() { mbValidLineNum = true; }
741
742 bool GetValidLineNumFlag()const { return mbValidLineNum; }
743
744 // Only invalidate Frame
745 // #i28701# - add call to method <ActionOnInvalidation(..)>
746 // for all invalidation methods.
747 // #i28701# - use method <InvalidationAllowed(..)> to
748 // decide, if invalidation will to be performed or not.
749 // #i26945# - no additional invalidation, if it's already
750 // invalidate.
751 void InvalidateSize_()
752 {
753 if ( isFrameAreaSizeValid() && InvalidationAllowed( INVALID_SIZE ) )
754 {
755 setFrameAreaSizeValid(false);
756 ActionOnInvalidation( INVALID_SIZE );
757 }
758 }
759 void InvalidatePrt_()
760 {
761 if ( isFramePrintAreaValid() && InvalidationAllowed( INVALID_PRTAREA ) )
762 {
763 setFramePrintAreaValid(false);
764 ActionOnInvalidation( INVALID_PRTAREA );
765 }
766 }
767 void InvalidatePos_()
768 {
769 if ( isFrameAreaPositionValid() && InvalidationAllowed( INVALID_POS ) )
770 {
771 setFrameAreaPositionValid(false);
772 ActionOnInvalidation( INVALID_POS );
773 }
774 }
775 void InvalidateLineNum_()
776 {
777 if ( mbValidLineNum && InvalidationAllowed( INVALID_LINENUM ) )
778 {
779 mbValidLineNum = false;
780 ActionOnInvalidation( INVALID_LINENUM );
781 }
782 }
783 void InvalidateAll_()
784 {
785 if ( ( isFrameAreaSizeValid() || isFramePrintAreaValid() || isFrameAreaPositionValid() ) && InvalidationAllowed( INVALID_ALL ) )
786 {
787 setFrameAreaSizeValid(false);
788 setFrameAreaPositionValid(false);
789 setFramePrintAreaValid(false);
790 ActionOnInvalidation( INVALID_ALL );
791 }
792 }
793 // also notify page at the same time
794 inline void InvalidateSize();
795 inline void InvalidatePrt();
796 inline void InvalidatePos();
797 inline void InvalidateLineNum();
798 inline void InvalidateAll();
799 void ImplInvalidateSize();
800 void ImplInvalidatePrt();
801 void ImplInvalidatePos();
802 void ImplInvalidateLineNum();
803
804 inline void InvalidateNextPos( bool bNoFootnote = false );
805 void ImplInvalidateNextPos( bool bNoFootnote );
806
807 /** method to invalidate printing area of next frame
808 #i11859#
809 */
810 void InvalidateNextPrtArea();
811
812 void InvalidatePage( const SwPageFrame *pPage = nullptr ) const;
813
814 virtual bool FillSelection( SwSelectionList& rList, const SwRect& rRect ) const;
815
816 virtual bool GetModelPositionForViewPoint( SwPosition *, Point&,
817 SwCursorMoveState* = nullptr, bool bTestBackground = false ) const;
818 virtual bool GetCharRect( SwRect &, const SwPosition&,
819 SwCursorMoveState* = nullptr, bool bAllowFarAway = true ) const;
820 virtual void PaintSwFrame( vcl::RenderContext& rRenderContext, SwRect const&,
821 SwPrintData const*const pPrintData = nullptr ) const;
822
823 // HACK: shortcut between frame and formatting
824 // It's your own fault if you cast void* incorrectly! In any case check
825 // the void* for 0.
826 virtual bool Prepare( const PrepareHint ePrep = PrepareHint::Clear,
827 const void *pVoid = nullptr, bool bNotify = true );
828
829 // true if it is the correct class, false otherwise
830 inline bool IsLayoutFrame() const;
831 inline bool IsRootFrame() const;
832 inline bool IsPageFrame() const;
833 inline bool IsColumnFrame() const;
834 inline bool IsFootnoteBossFrame() const; // footnote bosses might be PageFrames or ColumnFrames
835 inline bool IsHeaderFrame() const;
836 inline bool IsFooterFrame() const;
837 inline bool IsFootnoteContFrame() const;
838 inline bool IsFootnoteFrame() const;
839 inline bool IsBodyFrame() const;
840 inline bool IsColBodyFrame() const; // implemented in layfrm.hxx, BodyFrame above ColumnFrame
841 inline bool IsPageBodyFrame() const; // implemented in layfrm.hxx, BodyFrame above PageFrame
842 inline bool IsFlyFrame() const;
843 inline bool IsSctFrame() const;
844 inline bool IsTabFrame() const;
845 inline bool IsRowFrame() const;
846 inline bool IsCellFrame() const;
847 inline bool IsContentFrame() const;
848 inline bool IsTextFrame() const;
849 inline bool IsNoTextFrame() const;
850 // Frames where its PrtArea depends on their neighbors and that are
851 // positioned in the content flow
852 inline bool IsFlowFrame() const;
853 // Frames that are capable of retouching or that might need to retouch behind
854 // themselves
855 inline bool IsRetoucheFrame() const;
856 inline bool IsAccessibleFrame() const;
857
858 void PrepareCursor(); // CursorShell is allowed to call this
859
860 // Is the Frame (or the section containing it) protected? Same for Fly in
861 // Fly in ... and footnotes
862 bool IsProtected() const;
863
864 bool IsColLocked() const { return mbColLocked; }
865 virtual bool IsDeleteForbidden() const { return mbForbidDelete; }
866
867 /// this is the only way to delete a SwFrame instance
868 static void DestroyFrame(SwFrame *const pFrame);
869
870 bool IsInDtor() const { return mbInDtor; }
871
872 // No inline cause we need the function pointers
873 long GetTopMargin() const;
874 long GetBottomMargin() const;
875 long GetLeftMargin() const;
876 long GetRightMargin() const;
877 void SetTopBottomMargins( long, long );
878 void SetLeftRightMargins( long, long );
879 void SetRightLeftMargins( long, long );
880 long GetPrtLeft() const;
881 long GetPrtBottom() const;
882 long GetPrtRight() const;
883 long GetPrtTop() const;
884 bool SetMinLeft( long );
885 bool SetMaxBottom( long );
886 bool SetMaxRight( long );
887 void MakeBelowPos( const SwFrame*, const SwFrame*, bool );
888 void MakeLeftPos( const SwFrame*, const SwFrame*, bool );
889 void MakeRightPos( const SwFrame*, const SwFrame*, bool );
890 bool IsNeighbourFrame() const
891 { return bool(GetType() & FRM_NEIGHBOUR(SwFrameType::Column | SwFrameType::Cell)); }
892
893 // NEW TABLES
894 // Some functions for covered/covering table cells. This way unnecessary
895 // includes can be avoided
896 virtual bool IsLeaveUpperAllowed() const;
897 virtual bool IsCoveredCell() const;
898 bool IsInCoveredCell() const;
899
900 // #i81146# new loop control
901 bool KnowsFormat( const SwFormat& rFormat ) const;
902 void RegisterToFormat( SwFormat& rFormat );
903 void ValidateThisAndAllLowers( const sal_uInt16 nStage );
904
905 void ForbidDelete() { mbForbidDelete = true; }
906 void AllowDelete() { mbForbidDelete = false; }
907
908 drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const;
909 bool supportsFullDrawingLayerFillAttributeSet() const;
910
911public:
912 // if writer is NULL, dumps the layout structure as XML in layout.xml
913 virtual void dumpAsXml(xmlTextWriterPtr writer = nullptr) const;
914 void dumpTopMostAsXml(xmlTextWriterPtr writer = nullptr) const;
915 void dumpInfosAsXml(xmlTextWriterPtr writer) const;
916 virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const;
917 void dumpChildrenAsXml(xmlTextWriterPtr writer) const;
918 bool IsCollapse() const;
919};
920
921inline bool SwFrame::IsInDocBody() const
922{
923 if ( mbInfInvalid )
924 const_cast<SwFrame*>(this)->SetInfFlags();
925 return mbInfBody;
926}
927inline bool SwFrame::IsInFootnote() const
928{
929 if ( mbInfInvalid )
930 const_cast<SwFrame*>(this)->SetInfFlags();
931 return mbInfFootnote;
932}
933inline bool SwFrame::IsInTab() const
934{
935 if ( mbInfInvalid )
936 const_cast<SwFrame*>(this)->SetInfFlags();
937 return mbInfTab;
938}
939inline bool SwFrame::IsInFly() const
940{
941 if ( mbInfInvalid )
22
Assuming field 'mbInfInvalid' is false
23
Taking false branch
942 const_cast<SwFrame*>(this)->SetInfFlags();
943 return mbInfFly;
24
Returning value, which participates in a condition later
944}
945inline bool SwFrame::IsInSct() const
946{
947 if ( mbInfInvalid )
948 const_cast<SwFrame*>(this)->SetInfFlags();
949 return mbInfSct;
950}
951bool SwFrame::IsVertical() const
952{
953 if( mbInvalidVert )
954 const_cast<SwFrame*>(this)->SetDirFlags( true );
955 return mbVertical;
956}
957inline bool SwFrame::IsVertLR() const
958{
959 return mbVertLR;
960}
961inline bool SwFrame::IsVertLRBT() const
962{
963 return mbVertLRBT;
964}
965inline bool SwFrame::IsRightToLeft() const
966{
967 if( mbInvalidR2L )
968 const_cast<SwFrame*>(this)->SetDirFlags( false );
969 return mbRightToLeft;
970}
971
972inline void SwFrame::SetCompletePaint() const
973{
974 const_cast<SwFrame*>(this)->mbCompletePaint = true;
975}
976inline void SwFrame::ResetCompletePaint() const
977{
978 const_cast<SwFrame*>(this)->mbCompletePaint = false;
979}
980
981inline void SwFrame::SetRetouche() const
982{
983 const_cast<SwFrame*>(this)->mbRetouche = true;
984}
985inline void SwFrame::ResetRetouche() const
986{
987 const_cast<SwFrame*>(this)->mbRetouche = false;
988}
989
990inline SwLayoutFrame *SwFrame::GetNextLayoutLeaf()
991{
992 return const_cast<SwLayoutFrame*>(static_cast<const SwFrame*>(this)->GetNextLayoutLeaf());
993}
994inline SwLayoutFrame *SwFrame::GetPrevLayoutLeaf()
995{
996 return const_cast<SwLayoutFrame*>(static_cast<const SwFrame*>(this)->GetPrevLayoutLeaf());
997}
998inline const SwLayoutFrame *SwFrame::GetNextLayoutLeaf() const
999{
1000 return ImplGetNextLayoutLeaf( true );
1001}
1002inline const SwLayoutFrame *SwFrame::GetPrevLayoutLeaf() const
1003{
1004 return ImplGetNextLayoutLeaf( false );
1005}
1006
1007inline void SwFrame::InvalidateSize()
1008{
1009 if ( isFrameAreaSizeValid() )
1010 {
1011 ImplInvalidateSize();
1012 }
1013}
1014inline void SwFrame::InvalidatePrt()
1015{
1016 if ( isFramePrintAreaValid() )
1017 {
1018 ImplInvalidatePrt();
1019 }
1020}
1021inline void SwFrame::InvalidatePos()
1022{
1023 if ( isFrameAreaPositionValid() )
1024 {
1025 ImplInvalidatePos();
1026 }
1027}
1028inline void SwFrame::InvalidateLineNum()
1029{
1030 if ( mbValidLineNum )
1031 ImplInvalidateLineNum();
1032}
1033inline void SwFrame::InvalidateAll()
1034{
1035 if ( InvalidationAllowed( INVALID_ALL ) )
1036 {
1037 if ( isFrameAreaDefinitionValid() )
1038 {
1039 ImplInvalidatePos();
1040 }
1041
1042 setFrameAreaSizeValid(false);
1043 setFrameAreaPositionValid(false);
1044 setFramePrintAreaValid(false);
1045
1046 // #i28701#
1047 ActionOnInvalidation( INVALID_ALL );
1048 }
1049}
1050inline void SwFrame::InvalidateNextPos( bool bNoFootnote )
1051{
1052 if ( mpNext && !mpNext->IsSctFrame() )
1053 mpNext->InvalidatePos();
1054 else
1055 ImplInvalidateNextPos( bNoFootnote );
1056}
1057
1058inline void SwFrame::OptCalc() const
1059{
1060 if ( !isFrameAreaPositionValid() || !isFramePrintAreaValid() || !isFrameAreaSizeValid() )
1061 {
1062 const_cast<SwFrame*>(this)->OptPrepareMake();
1063 }
1064}
1065inline const SwPageFrame *SwFrame::FindPageFrame() const
1066{
1067 return const_cast<SwFrame*>(this)->FindPageFrame();
1068}
1069inline const SwFrame *SwFrame::FindColFrame() const
1070{
1071 return const_cast<SwFrame*>(this)->FindColFrame();
1072}
1073inline const SwFrame *SwFrame::FindFooterOrHeader() const
1074{
1075 return const_cast<SwFrame*>(this)->FindFooterOrHeader();
1076}
1077inline SwTabFrame *SwFrame::FindTabFrame()
1078{
1079 return IsInTab() ? ImplFindTabFrame() : nullptr;
1080}
1081inline const SwFootnoteBossFrame *SwFrame::FindFootnoteBossFrame( bool bFootnote ) const
1082{
1083 return const_cast<SwFrame*>(this)->FindFootnoteBossFrame( bFootnote );
1084}
1085inline SwFootnoteFrame *SwFrame::FindFootnoteFrame()
1086{
1087 return IsInFootnote() ? ImplFindFootnoteFrame() : nullptr;
1088}
1089inline SwFlyFrame *SwFrame::FindFlyFrame()
1090{
1091 return IsInFly() ? ImplFindFlyFrame() : nullptr;
1092}
1093inline SwSectionFrame *SwFrame::FindSctFrame()
1094{
1095 return IsInSct() ? ImplFindSctFrame() : nullptr;
1096}
1097
1098inline const SwBodyFrame *SwFrame::FindBodyFrame() const
1099{
1100 return IsInDocBody() ? ImplFindBodyFrame() : nullptr;
1101}
1102
1103inline const SwTabFrame *SwFrame::FindTabFrame() const
1104{
1105 return IsInTab() ? const_cast<SwFrame*>(this)->ImplFindTabFrame() : nullptr;
1106}
1107inline const SwFootnoteFrame *SwFrame::FindFootnoteFrame() const
1108{
1109 return IsInFootnote() ? const_cast<SwFrame*>(this)->ImplFindFootnoteFrame() : nullptr;
1110}
1111inline const SwFlyFrame *SwFrame::FindFlyFrame() const
1112{
1113 return IsInFly() ? const_cast<SwFrame*>(this)->ImplFindFlyFrame() : nullptr;
1114}
1115inline const SwSectionFrame *SwFrame::FindSctFrame() const
1116{
1117 return IsInSct() ? const_cast<SwFrame*>(this)->ImplFindSctFrame() : nullptr;
1118}
1119inline SwFrame *SwFrame::FindNext()
1120{
1121 if ( mpNext )
1122 return mpNext;
1123 else
1124 return FindNext_();
1125}
1126inline const SwFrame *SwFrame::FindNext() const
1127{
1128 if ( mpNext )
1129 return mpNext;
1130 else
1131 return const_cast<SwFrame*>(this)->FindNext_();
1132}
1133inline SwFrame *SwFrame::FindPrev()
1134{
1135 if ( mpPrev && !mpPrev->IsSctFrame() )
1136 return mpPrev;
1137 else
1138 return FindPrev_();
1139}
1140inline const SwFrame *SwFrame::FindPrev() const
1141{
1142 if ( mpPrev && !mpPrev->IsSctFrame() )
1143 return mpPrev;
1144 else
1145 return const_cast<SwFrame*>(this)->FindPrev_();
1146}
1147
1148inline bool SwFrame::IsLayoutFrame() const
1149{
1150 return bool(GetType() & FRM_LAYOUTSwFrameType(0x3bFF));
1151}
1152inline bool SwFrame::IsRootFrame() const
1153{
1154 return mnFrameType == SwFrameType::Root;
1155}
1156inline bool SwFrame::IsPageFrame() const
1157{
1158 return mnFrameType == SwFrameType::Page;
1159}
1160inline bool SwFrame::IsColumnFrame() const
1161{
1162 return mnFrameType == SwFrameType::Column;
1163}
1164inline bool SwFrame::IsFootnoteBossFrame() const
1165{
1166 return bool(GetType() & FRM_FTNBOSS(SwFrameType::Page | SwFrameType::Column));
1167}
1168inline bool SwFrame::IsHeaderFrame() const
1169{
1170 return mnFrameType == SwFrameType::Header;
1171}
1172inline bool SwFrame::IsFooterFrame() const
1173{
1174 return mnFrameType == SwFrameType::Footer;
1175}
1176inline bool SwFrame::IsFootnoteContFrame() const
1177{
1178 return mnFrameType == SwFrameType::FtnCont;
1179}
1180inline bool SwFrame::IsFootnoteFrame() const
1181{
1182 return mnFrameType == SwFrameType::Ftn;
1183}
1184inline bool SwFrame::IsBodyFrame() const
1185{
1186 return mnFrameType == SwFrameType::Body;
1187}
1188inline bool SwFrame::IsFlyFrame() const
1189{
1190 return mnFrameType == SwFrameType::Fly;
1191}
1192inline bool SwFrame::IsSctFrame() const
1193{
1194 return mnFrameType == SwFrameType::Section;
1195}
1196inline bool SwFrame::IsTabFrame() const
1197{
1198 return mnFrameType == SwFrameType::Tab;
1199}
1200inline bool SwFrame::IsRowFrame() const
1201{
1202 return mnFrameType == SwFrameType::Row;
1203}
1204inline bool SwFrame::IsCellFrame() const
1205{
1206 return mnFrameType == SwFrameType::Cell;
1207}
1208inline bool SwFrame::IsContentFrame() const
1209{
1210 return bool(GetType() & FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt));
1211}
1212inline bool SwFrame::IsTextFrame() const
1213{
1214 return mnFrameType == SwFrameType::Txt;
1215}
1216inline bool SwFrame::IsNoTextFrame() const
1217{
1218 return mnFrameType == SwFrameType::NoTxt;
1219}
1220inline bool SwFrame::IsFlowFrame() const
1221{
1222 return bool(GetType() & (FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt)|SwFrameType::Tab|SwFrameType::Section));
1223}
1224inline bool SwFrame::IsRetoucheFrame() const
1225{
1226 return bool(GetType() & (FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt)|SwFrameType::Tab|SwFrameType::Section|SwFrameType::Ftn));
1227}
1228inline bool SwFrame::IsAccessibleFrame() const
1229{
1230 return bool(GetType() & FRM_ACCESSIBLE(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType
::Tab | SwFrameType::Cell | SwFrameType::Txt)
);
1231}
1232
1233//use this to protect a SwFrame for a given scope from getting deleted
1234class SwFrameDeleteGuard
1235{
1236private:
1237 SwFrame *m_pForbidFrame;
1238public:
1239 //Flag pFrame for SwFrameDeleteGuard lifetime that we shouldn't delete
1240 //it in e.g. SwSectionFrame::MergeNext etc because we will need it
1241 //again after the SwFrameDeleteGuard dtor
1242 explicit SwFrameDeleteGuard(SwFrame* pFrame)
1243 : m_pForbidFrame((pFrame && !pFrame->IsDeleteForbidden()) ?
1244 pFrame : nullptr)
1245 {
1246 if (m_pForbidFrame)
1247 m_pForbidFrame->ForbidDelete();
1248 }
1249
1250 SwFrameDeleteGuard(const SwFrameDeleteGuard&) =delete;
1251
1252 ~SwFrameDeleteGuard()
1253 {
1254 if (m_pForbidFrame)
1255 m_pForbidFrame->AllowDelete();
1256 }
1257
1258 SwFrameDeleteGuard& operator=(const SwFrameDeleteGuard&) =delete;
1259};
1260
1261typedef long (SwFrame::*SwFrameGet)() const;
1262typedef bool (SwFrame::*SwFrameMax)( long );
1263typedef void (SwFrame::*SwFrameMakePos)( const SwFrame*, const SwFrame*, bool );
1264typedef long (*SwOperator)( long, long );
1265typedef void (SwFrame::*SwFrameSet)( long, long );
1266
1267struct SwRectFnCollection
1268{
1269 SwRectGet fnGetTop;
1270 SwRectGet fnGetBottom;
1271 SwRectGet fnGetLeft;
1272 SwRectGet fnGetRight;
1273 SwRectGet fnGetWidth;
1274 SwRectGet fnGetHeight;
1275 SwRectPoint fnGetPos;
1276 SwRectSize fnGetSize;
1277
1278 SwRectSet fnSetTop;
1279 SwRectSet fnSetBottom;
1280 SwRectSet fnSetLeft;
1281 SwRectSet fnSetRight;
1282 SwRectSet fnSetWidth;
1283 SwRectSet fnSetHeight;
1284
1285 SwRectSet fnSubTop;
1286 SwRectSet fnAddBottom;
1287 SwRectSet fnSubLeft;
1288 SwRectSet fnAddRight;
1289 SwRectSet fnAddWidth;
1290 SwRectSet fnAddHeight;
1291
1292 SwRectSet fnSetPosX;
1293 SwRectSet fnSetPosY;
1294
1295 SwFrameGet fnGetTopMargin;
1296 SwFrameGet fnGetBottomMargin;
1297 SwFrameGet fnGetLeftMargin;
1298 SwFrameGet fnGetRightMargin;
1299 SwFrameSet fnSetXMargins;
1300 SwFrameSet fnSetYMargins;
1301 SwFrameGet fnGetPrtTop;
1302 SwFrameGet fnGetPrtBottom;
1303 SwFrameGet fnGetPrtLeft;
1304 SwFrameGet fnGetPrtRight;
1305 SwRectDist fnTopDist;
1306 SwRectDist fnBottomDist;
1307 SwRectDist fnLeftDist;
1308 SwRectDist fnRightDist;
1309 SwFrameMax fnSetLimit;
1310 SwRectMax fnOverStep;
1311
1312 SwRectSetPos fnSetPos;
1313 SwFrameMakePos fnMakePos;
1314 SwOperator fnXDiff;
1315 SwOperator fnYDiff;
1316 SwOperator fnXInc;
1317 SwOperator fnYInc;
1318
1319 SwRectSetTwice fnSetLeftAndWidth;
1320 SwRectSetTwice fnSetTopAndHeight;
1321};
1322
1323typedef SwRectFnCollection* SwRectFn;
1324
1325// This class allows to use proper methods regardless of orientation (LTR/RTL, horizontal or vertical)
1326extern SwRectFn fnRectHori, fnRectVert, fnRectVertL2R, fnRectVertL2RB2T;
1327class SwRectFnSet {
1328public:
1329 explicit SwRectFnSet(const SwFrame *pFrame)
1330 : m_bVert(pFrame->IsVertical())
1331 , m_bVertL2R(pFrame->IsVertLR())
1332 , m_bVertL2RB2T(pFrame->IsVertLRBT())
1333 {
1334 m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
1335 }
1336
1337 void Refresh(const SwFrame *pFrame)
1338 {
1339 m_bVert = pFrame->IsVertical();
1340 m_bVertL2R = pFrame->IsVertLR();
1341 m_bVertL2RB2T = pFrame->IsVertLRBT();
1342 m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
1343 }
1344
1345 bool IsVert() const { return m_bVert; }
1346 bool IsVertL2R() const { return m_bVertL2R; }
1347 SwRectFn FnRect() const { return m_fnRect; }
1348
1349 bool PosDiff(const SwRect &rRect1, const SwRect &rRect2) const
1350 {
1351 return ((rRect1.*m_fnRect->fnGetTop)() != (rRect2.*m_fnRect->fnGetTop)()
1352 || (rRect1.*m_fnRect->fnGetLeft)() != (rRect2.*m_fnRect->fnGetLeft)());
1353 }
1354
1355 long GetTop (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetTop) (); }
1356 long GetBottom(const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetBottom)(); }
1357 long GetLeft (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetLeft) (); }
1358 long GetRight (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetRight) (); }
1359 long GetWidth (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetWidth) (); }
1360 long GetHeight(const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetHeight)(); }
1361 Point GetPos (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetPos) (); }
1362 Size GetSize (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetSize) (); }
1363
1364 void SetTop (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetTop) (nNew); }
1365 void SetBottom(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetBottom)(nNew); }
1366 void SetLeft (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetLeft) (nNew); }
1367 void SetRight (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetRight) (nNew); }
1368 void SetWidth (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetWidth) (nNew); }
1369 void SetHeight(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetHeight)(nNew); }
1370
1371 void SubTop (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSubTop) (nNew); }
1372 void AddBottom(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddBottom)(nNew); }
1373 void SubLeft (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSubLeft) (nNew); }
1374 void AddRight (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddRight) (nNew); }
1375 void AddWidth (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddWidth) (nNew); }
1376 void AddHeight(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddHeight)(nNew); }
1377
1378 void SetPosX(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetPosX)(nNew); }
1379 void SetPosY(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetPosY)(nNew); }
1380
1381 long GetTopMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetTopMargin) (); }
1382 long GetBottomMargin(const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetBottomMargin)(); }
1383 long GetLeftMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetLeftMargin) (); }
1384 long GetRightMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetRightMargin) (); }
1385 void SetXMargins(SwFrame& rFrame, long nLeft, long nRight) const { (rFrame.*m_fnRect->fnSetXMargins)(nLeft, nRight); }
1386 void SetYMargins(SwFrame& rFrame, long nTop, long nBottom) const { (rFrame.*m_fnRect->fnSetYMargins)(nTop, nBottom); }
1387 long GetPrtTop (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtTop) (); }
1388 long GetPrtBottom (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtBottom) (); }
1389 long GetPrtLeft (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtLeft) (); }
1390 long GetPrtRight (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtRight) (); }
1391 long TopDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnTopDist) (nPos); }
1392 long BottomDist(const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnBottomDist) (nPos); }
1393 long LeftDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnLeftDist) (nPos); }
1394 long RightDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnRightDist) (nPos); }
1395 void SetLimit (SwFrame& rFrame, long nNew) const { (rFrame.*m_fnRect->fnSetLimit) (nNew); }
1396 bool OverStep (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnOverStep) (nPos); }
1397
1398 void SetPos(SwRect& rRect, const Point& rNew) const { (rRect.*m_fnRect->fnSetPos)(rNew); }
1399 void MakePos(SwFrame& rFrame, const SwFrame* pUp, const SwFrame* pPrv, bool bNotify) const { (rFrame.*m_fnRect->fnMakePos)(pUp, pPrv, bNotify); }
1400 long XDiff(long n1, long n2) const { return (m_fnRect->fnXDiff) (n1, n2); }
1401 long YDiff(long n1, long n2) const { return (m_fnRect->fnYDiff) (n1, n2); }
1402 long XInc (long n1, long n2) const { return (m_fnRect->fnXInc) (n1, n2); }
1403 long YInc (long n1, long n2) const { return (m_fnRect->fnYInc) (n1, n2); }
1404
1405 void SetLeftAndWidth(SwRect& rRect, long nLeft, long nWidth) const { (rRect.*m_fnRect->fnSetLeftAndWidth)(nLeft, nWidth); }
1406 void SetTopAndHeight(SwRect& rRect, long nTop, long nHeight) const { (rRect.*m_fnRect->fnSetTopAndHeight)(nTop, nHeight); }
1407
1408private:
1409 bool m_bVert;
1410 bool m_bVertL2R;
1411 bool m_bVertL2RB2T;
1412 SwRectFn m_fnRect;
1413};
1414
1415#endif
1416
1417/* vim:set shiftwidth=4 softtabstop=4 expandtab: */