Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/layout/paintfrm.cxx
Warning:line 6715, column 19
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
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 )
2910 {
2911 bPaint = SwFlyFrame::IsPaint( pObj, &mrViewShell );
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 )
3802 return true;
3803
3804 //Attribute dependent, don't paint for printer or Preview
3805 bool bPaint = gProp.pSFlyOnlyDraw ||
3806 static_cast<SwContact*>(pUserCall)->GetFormat()->GetPrint().GetValue();
3807 if ( !bPaint )
3808 bPaint = pSh->GetWin() && !pSh->IsPreview();
3809
3810 if ( bPaint )
3811 {
3812 //The paint may be prevented by the superior Flys.
3813 SwFrame *pAnch = nullptr;
3814 if ( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr ) // i#117962#
3815 {
3816 bPaint = false;
3817 }
3818 if ( dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) != nullptr )
3819 {
3820 SwFlyFrame *pFly = static_cast<SwVirtFlyDrawObj*>(pObj)->GetFlyFrame();
3821 if ( gProp.pSFlyOnlyDraw && gProp.pSFlyOnlyDraw == pFly )
3822 return true;
3823
3824 //Try to avoid displaying the intermediate stage, Flys which don't
3825 //overlap with the page on which they are anchored won't be
3826 //painted.
3827 //HACK: exception: printing of frames in tables, those can overlap
3828 //a page once in a while when dealing with oversized tables (HTML).
3829 SwPageFrame *pPage = pFly->FindPageFrame();
3830 if ( pPage && pPage->getFrameArea().IsOver( pFly->getFrameArea() ) )
3831 {
3832 pAnch = pFly->AnchorFrame();
3833 }
3834
3835 }
3836 else
3837 {
3838 // Consider 'virtual' drawing objects
3839 SwDrawContact* pDrawContact = dynamic_cast<SwDrawContact*>(pUserCall);
3840 pAnch = pDrawContact ? pDrawContact->GetAnchorFrame(pObj) : nullptr;
3841 if ( pAnch )
3842 {
3843 if ( !pAnch->isFrameAreaPositionValid() )
3844 pAnch = nullptr;
3845 else if ( pSh->GetOut() == pSh->getIDocumentDeviceAccess().getPrinter( false ))
3846 {
3847 //HACK: we have to omit some of the objects for printing,
3848 //otherwise they would be printed twice.
3849 //The objects should get printed if the TableHack is active
3850 //right now. Afterwards they must not be printed if the
3851 //page over which they float position wise gets printed.
3852 const SwPageFrame *pPage = pAnch->FindPageFrame();
3853 if ( !pPage->getFrameArea().IsOver( pObj->GetCurrentBoundRect() ) )
3854 pAnch = nullptr;
3855 }
3856 }
3857 else
3858 {
3859 if ( dynamic_cast< const SdrObjGroup *>( pObj ) == nullptr )
3860 {
3861 OSL_FAIL( "<SwFlyFrame::IsPaint(..)> - paint of drawing object without anchor frame!?" )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 )
3866 {
3867 if ( pAnch->IsInFly() )
3868 bPaint = SwFlyFrame::IsPaint( pAnch->FindFlyFrame()->GetVirtDrawObj(),
3869 pSh );
3870 else if ( gProp.pSFlyOnlyDraw )
3871 bPaint = false;
3872 }
3873 else
3874 bPaint = false;
3875 }
3876 return bPaint;
3877}
3878
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() )
1
Assuming the condition is false
2
Taking false branch
6701 return;
6702
6703 const SwFrame* pLay = Lower();
6704 const SwFrame* pFootnoteCont = nullptr;
6705 const SwFrame* pPageBody = nullptr;
3
'pPageBody' initialized to a null pointer value
6706 while ( pLay && !( pFootnoteCont && pPageBody ) )
4
Assuming 'pLay' is null
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() );
5
Called C++ object pointer is null
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: */