[Libreoffice-commits] core.git: Branch 'feature/RotGrfFlyFrame' - sw/source sw/uiconfig
Armin Le Grand
Armin.Le.Grand at cib.de
Tue Oct 3 15:03:01 UTC 2017
sw/source/core/layout/paintfrm.cxx.orig | 7565 +++++++++++++++++++++++
sw/uiconfig/swriter/toolbar/graphicobjectbar.xml | 2
sw/uiconfig/swxform/toolbar/graphicobjectbar.xml | 4
3 files changed, 7568 insertions(+), 3 deletions(-)
New commits:
commit e1742c565420bfb82b486e46fe0f55515ac2001b
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date: Fri Sep 29 12:35:44 2017 +0200
RotGrfFlyFrame: Corrected position for CropHandles
Position was taken from OuterBound FlyFrame, even in current
master which is wrong. There can be a distance defined between
InnerBound and OuterBound that has to be taken into account
Change-Id: Id88f99c0b218bd26fa1daa5e8215eced00c0baa6
diff --git a/sw/source/core/layout/paintfrm.cxx.orig b/sw/source/core/layout/paintfrm.cxx.orig
new file mode 100644
index 000000000000..351ac1a8ba35
--- /dev/null
+++ b/sw/source/core/layout/paintfrm.cxx.orig
@@ -0,0 +1,7565 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/lazydelete.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/progress.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/prntitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <svx/framelink.hxx>
+#include <drawdoc.hxx>
+#include <tgrditem.hxx>
+#include <calbck.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtclds.hxx>
+#include <strings.hrc>
+#include <swmodule.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <section.hxx>
+#include <sectfrm.hxx>
+#include <viewimp.hxx>
+#include <dflyobj.hxx>
+#include <flyfrm.hxx>
+#include <viewopt.hxx>
+#include <dview.hxx>
+#include <dcontact.hxx>
+#include <txtfrm.hxx>
+#include <ftnfrm.hxx>
+#include <tabfrm.hxx>
+#include <rowfrm.hxx>
+#include <cellfrm.hxx>
+#include <notxtfrm.hxx>
+#include <layact.hxx>
+#include <pagedesc.hxx>
+#include <ptqueue.hxx>
+#include <noteurl.hxx>
+#include <virtoutp.hxx>
+#include <lineinfo.hxx>
+#include <dbg_lay.hxx>
+#include <docsh.hxx>
+#include <svx/svdogrp.hxx>
+#include <sortedobjs.hxx>
+#include <EnhancedPDFExportHelper.hxx>
+#include <bodyfrm.hxx>
+#include <hffrm.hxx>
+#include <colfrm.hxx>
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <DocumentSettingManager.hxx>
+#include <IDocumentDeviceAccess.hxx>
+
+#include <ndole.hxx>
+#include <PostItMgr.hxx>
+#include <FrameControlsManager.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+
+#include <svtools/borderhelper.hxx>
+
+#include "bitmaps.hlst"
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/framelinkarray.hxx>
+#include <comphelper/sequence.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/color/bcolortools.hxx>
+
+#include <memory>
+#include <vector>
+#include <algorithm>
+#include <wrtsh.hxx>
+#include <edtwin.hxx>
+#include <view.hxx>
+#include <paintfrm.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+#include <vcl/BitmapTools.hxx>
+
+#define COL_NOTES_SIDEPANE RGB_COLORDATA(230,230,230)
+#define COL_NOTES_SIDEPANE_BORDER RGB_COLORDATA(200,200,200)
+#define COL_NOTES_SIDEPANE_SCROLLAREA RGB_COLORDATA(230,230,220)
+
+using namespace ::editeng;
+using namespace ::com::sun::star;
+using ::drawinglayer::primitive2d::BorderLinePrimitive2D;
+using ::drawinglayer::primitive2d::BorderLine;
+using std::pair;
+using std::make_pair;
+
+struct SwPaintProperties;
+
+//other subsidiary lines enabled?
+#define IS_SUBS (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+ !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() && \
+ !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+ !gProp.pSGlobalShell->GetViewOptions()->IsWhitespaceHidden() &&\
+ SwViewOption::IsDocBoundaries())
+//subsidiary lines for sections
+#define IS_SUBS_SECTION (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+ !gProp.pSGlobalShell->GetViewOptions()->IsReadonly()&&\
+ !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+ SwViewOption::IsSectionBoundaries())
+#define IS_SUBS_FLYS (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+ !gProp.pSGlobalShell->GetViewOptions()->IsReadonly()&&\
+ !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+ SwViewOption::IsObjectBoundaries())
+
+//Class declaration; here because they are only used in this file
+enum class SubColFlags {
+ Page = 0x01, //Helplines of the page
+ Tab = 0x08, //Helplines inside tables
+ Fly = 0x10, //Helplines inside fly frames
+ Sect = 0x20, //Helplines inside sections
+};
+namespace o3tl {
+ template<> struct typed_flags<SubColFlags> : is_typed_flags<SubColFlags, 0x39> {};
+}
+
+// Classes collecting the border lines and help lines
+class SwLineRect : public SwRect
+{
+ Color aColor;
+ SvxBorderLineStyle nStyle;
+ const SwTabFrame *pTab;
+ SubColFlags nSubColor; //colorize subsidiary lines
+ bool bPainted; //already painted?
+ sal_uInt8 nLock; //To distinguish the line and the hell layer.
+public:
+ SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
+ const SwTabFrame *pT , const SubColFlags nSCol );
+
+ const Color& GetColor() const { return aColor;}
+ SvxBorderLineStyle GetStyle() const { return nStyle; }
+ const SwTabFrame *GetTab() const { return pTab; }
+ void SetPainted() { bPainted = true; }
+ void Lock( bool bLock ) { if ( bLock )
+ ++nLock;
+ else if ( nLock )
+ --nLock;
+ }
+ bool IsPainted() const { return bPainted; }
+ bool IsLocked() const { return nLock != 0; }
+ SubColFlags GetSubColor() const { return nSubColor;}
+
+ bool MakeUnion( const SwRect &rRect, SwPaintProperties const &properties );
+};
+
+#ifdef IOS
+static void dummy_function()
+{
+ pid_t pid = getpid();
+ (void) pid;
+}
+#endif
+
+class SwLineRects
+{
+public:
+ std::vector< SwLineRect > aLineRects;
+ typedef std::vector< SwLineRect >::const_iterator const_iterator;
+ typedef std::vector< SwLineRect >::iterator iterator;
+ typedef std::vector< SwLineRect >::reverse_iterator reverse_iterator;
+ typedef std::vector< SwLineRect >::size_type size_type;
+ size_t nLastCount; //avoid unnecessary cycles in PaintLines
+ SwLineRects() : nLastCount( 0 )
+ {
+#ifdef IOS
+ // Work around what is either a compiler bug in Xcode 5.1.1,
+ // or some unknown problem in this file. If I ifdef out this
+ // call, I get a crash in SwSubsRects::PaintSubsidiary: the
+ // address of the rLi reference variable is claimed to be
+ // 0x4000000!
+ dummy_function();
+#endif
+ }
+ void AddLineRect( const SwRect& rRect, const Color *pColor, const SvxBorderLineStyle nStyle,
+ const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const &properties );
+ void ConnectEdges( OutputDevice const *pOut, SwPaintProperties const &properties );
+ void PaintLines ( OutputDevice *pOut, SwPaintProperties const &properties );
+ void LockLines( bool bLock );
+
+ //Limit lines to 100
+ bool isFull() const { return aLineRects.size()>100; }
+};
+
+class SwSubsRects : public SwLineRects
+{
+ void RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const &properties );
+public:
+ void PaintSubsidiary( OutputDevice *pOut, const SwLineRects *pRects, SwPaintProperties const &properties );
+};
+
+class BorderLines
+{
+ drawinglayer::primitive2d::Primitive2DContainer m_Lines;
+public:
+ void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine);
+ drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
+ {
+ drawinglayer::primitive2d::Primitive2DContainer lines;
+ lines.swap(m_Lines);
+ return lines;
+ }
+};
+
+// Default zoom factor
+const static double aMinDistScale = 0.73;
+const static double aEdgeScale = 0.5;
+
+//To optimize the expensive RetouchColor determination
+Color aGlobalRetoucheColor;
+
+namespace sw
+{
+Color* GetActiveRetoucheColor()
+{
+ return &aGlobalRetoucheColor;
+}
+}
+
+/**
+ * Container for static properties
+ */
+struct SwPaintProperties {
+ // Only repaint the Fly content as well as the background of the Fly content if
+ // a metafile is taken of the Fly.
+ bool bSFlyMetafile;
+ VclPtr<OutputDevice> pSFlyMetafileOut;
+ SwViewShell *pSGlobalShell;
+
+ // Retouch for transparent Flys is done by the background of the Flys.
+ // The Fly itself should certainly not be spared out. See PaintBackground and
+ // lcl_SubtractFlys()
+ SwFlyFrame *pSRetoucheFly;
+ SwFlyFrame *pSRetoucheFly2;
+ SwFlyFrame *pSFlyOnlyDraw;
+
+ // The borders will be collected in pSLines during the Paint and later
+ // possibly merge them.
+ // The help lines will be collected and merged in gProp.pSSubsLines. These will
+ // be compared with pSLines before the work in order to avoid help lines
+ // to hide borders.
+ BorderLines *pBLines;
+ SwLineRects *pSLines;
+ SwSubsRects *pSSubsLines;
+
+ // global variable for sub-lines of body, header, footer, section and footnote frames.
+ SwSubsRects *pSSpecSubsLines;
+ SfxProgress *pSProgress;
+
+ // Sizes of a pixel and the corresponding halves. Will be reset when
+ // entering SwRootFrame::Paint
+ long nSPixelSzW;
+ long nSPixelSzH;
+ long nSHalfPixelSzW;
+ long nSHalfPixelSzH;
+ long nSMinDistPixelW;
+ long nSMinDistPixelH;
+
+ Color aSGlobalRetoucheColor;
+
+ // Current zoom factor
+ double aSScaleX;
+ double aSScaleY;
+
+ SwPaintProperties()
+ : bSFlyMetafile(false)
+ , pSFlyMetafileOut(nullptr)
+ , pSGlobalShell(nullptr)
+ , pSRetoucheFly(nullptr)
+ , pSRetoucheFly2(nullptr)
+ , pSFlyOnlyDraw(nullptr)
+ , pBLines(nullptr)
+ , pSLines(nullptr)
+ , pSSubsLines(nullptr)
+ , pSSpecSubsLines(nullptr)
+ , pSProgress(nullptr)
+ , nSPixelSzW(0)
+ , nSPixelSzH(0)
+ , nSHalfPixelSzW(0)
+ , nSHalfPixelSzH(0)
+ , nSMinDistPixelW(0)
+ , nSMinDistPixelH(0)
+ , aSScaleX(1)
+ , aSScaleY(1)
+ {
+ }
+
+};
+
+static SwPaintProperties gProp;
+
+namespace {
+
+bool isTableBoundariesEnabled()
+{
+ if (!gProp.pSGlobalShell->GetViewOptions()->IsTable())
+ return false;
+
+ if (gProp.pSGlobalShell->GetViewOptions()->IsPagePreview())
+ return false;
+
+ if (gProp.pSGlobalShell->GetViewOptions()->IsReadonly())
+ return false;
+
+ if (gProp.pSGlobalShell->GetViewOptions()->IsFormView())
+ return false;
+
+ return SwViewOption::IsTableBoundaries();
+}
+
+}
+
+/**
+ * Set borders alignment statics
+ * Adjustment for 'small' twip-to-pixel relations:
+ * For 'small' twip-to-pixel relations (less then 2:1)
+ * values of <gProp.nSHalfPixelSzW> and <gProp.nSHalfPixelSzH> are set to ZERO
+ */
+void SwCalcPixStatics( vcl::RenderContext const *pOut )
+{
+ // determine 'small' twip-to-pixel relation
+ bool bSmallTwipToPxRelW = false;
+ bool bSmallTwipToPxRelH = false;
+ {
+ Size aCheckTwipToPxRelSz( pOut->PixelToLogic( Size( 100, 100 )) );
+ if ( (aCheckTwipToPxRelSz.Width()/100.0) < 2.0 )
+ {
+ bSmallTwipToPxRelW = true;
+ }
+ if ( (aCheckTwipToPxRelSz.Height()/100.0) < 2.0 )
+ {
+ bSmallTwipToPxRelH = true;
+ }
+ }
+
+ Size aSz( pOut->PixelToLogic( Size( 1,1 )) );
+
+ gProp.nSPixelSzW = aSz.Width();
+ if( !gProp.nSPixelSzW )
+ gProp.nSPixelSzW = 1;
+ gProp.nSPixelSzH = aSz.Height();
+ if( !gProp.nSPixelSzH )
+ gProp.nSPixelSzH = 1;
+
+ // consider 'small' twip-to-pixel relations
+ if ( !bSmallTwipToPxRelW )
+ {
+ gProp.nSHalfPixelSzW = gProp.nSPixelSzW / 2 + 1;
+ }
+ else
+ {
+ gProp.nSHalfPixelSzW = 0;
+ }
+ // consider 'small' twip-to-pixel relations
+ if ( !bSmallTwipToPxRelH )
+ {
+ gProp.nSHalfPixelSzH = gProp.nSPixelSzH / 2 + 1;
+ }
+ else
+ {
+ gProp.nSHalfPixelSzH = 0;
+ }
+
+ gProp.nSMinDistPixelW = gProp.nSPixelSzW * 2 + 1;
+ gProp.nSMinDistPixelH = gProp.nSPixelSzH * 2 + 1;
+
+ const MapMode &rMap = pOut->GetMapMode();
+ gProp.aSScaleX = double(rMap.GetScaleX());
+ gProp.aSScaleY = double(rMap.GetScaleY());
+}
+
+/**
+ * To be able to save the statics so the paint is more or less reentrant
+ */
+class SwSavePaintStatics : public SwPaintProperties
+{
+public:
+ SwSavePaintStatics();
+ ~SwSavePaintStatics();
+};
+
+SwSavePaintStatics::SwSavePaintStatics()
+{
+ // Saving globales
+ bSFlyMetafile = gProp.bSFlyMetafile;
+ pSGlobalShell = gProp.pSGlobalShell;
+ pSFlyMetafileOut = gProp.pSFlyMetafileOut;
+ pSRetoucheFly = gProp.pSRetoucheFly;
+ pSRetoucheFly2 = gProp.pSRetoucheFly2;
+ pSFlyOnlyDraw = gProp.pSFlyOnlyDraw;
+ pBLines = gProp.pBLines;
+ pSLines = gProp.pSLines;
+ pSSubsLines = gProp.pSSubsLines;
+ pSSpecSubsLines = gProp.pSSpecSubsLines;
+ pSProgress = gProp.pSProgress;
+ nSPixelSzW = gProp.nSPixelSzW;
+ nSPixelSzH = gProp.nSPixelSzH;
+ nSHalfPixelSzW = gProp.nSHalfPixelSzW;
+ nSHalfPixelSzH = gProp.nSHalfPixelSzH;
+ nSMinDistPixelW = gProp.nSMinDistPixelW;
+ nSMinDistPixelH = gProp.nSMinDistPixelH ;
+ aSGlobalRetoucheColor = aGlobalRetoucheColor;
+ aSScaleX = gProp.aSScaleX;
+ aSScaleY = gProp.aSScaleY;
+
+ // Restoring globales to default
+ gProp.bSFlyMetafile = false;
+ gProp.pSFlyMetafileOut = nullptr;
+ gProp.pSRetoucheFly = nullptr;
+ gProp.pSRetoucheFly2 = nullptr;
+ gProp.nSPixelSzW = gProp.nSPixelSzH =
+ gProp.nSHalfPixelSzW = gProp.nSHalfPixelSzH =
+ gProp.nSMinDistPixelW = gProp.nSMinDistPixelH = 0;
+ gProp.aSScaleX = gProp.aSScaleY = 1.0;
+ gProp.pBLines = nullptr;
+ gProp.pSLines = nullptr;
+ gProp.pSSubsLines = nullptr;
+ gProp.pSSpecSubsLines = nullptr;
+ gProp.pSProgress = nullptr;
+}
+
+SwSavePaintStatics::~SwSavePaintStatics()
+{
+ // Restoring globales to saved one
+ gProp.pSGlobalShell = pSGlobalShell;
+ gProp.bSFlyMetafile = bSFlyMetafile;
+ gProp.pSFlyMetafileOut = pSFlyMetafileOut;
+ gProp.pSRetoucheFly = pSRetoucheFly;
+ gProp.pSRetoucheFly2 = pSRetoucheFly2;
+ gProp.pSFlyOnlyDraw = pSFlyOnlyDraw;
+ gProp.pBLines = pBLines;
+ gProp.pSLines = pSLines;
+ gProp.pSSubsLines = pSSubsLines;
+ gProp.pSSpecSubsLines = pSSpecSubsLines;
+ gProp.pSProgress = pSProgress;
+ gProp.nSPixelSzW = nSPixelSzW;
+ gProp.nSPixelSzH = nSPixelSzH;
+ gProp.nSHalfPixelSzW = nSHalfPixelSzW;
+ gProp.nSHalfPixelSzH = nSHalfPixelSzH;
+ gProp.nSMinDistPixelW = nSMinDistPixelW;
+ gProp.nSMinDistPixelH = nSMinDistPixelH;
+ aGlobalRetoucheColor = aSGlobalRetoucheColor;
+ gProp.aSScaleX = aSScaleX;
+ gProp.aSScaleY = aSScaleY;
+}
+
+void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine)
+{
+ for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it)
+ {
+ const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine));
+
+ if (aMerged.is())
+ {
+ *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine
+ return;
+ }
+ }
+
+ m_Lines.append(rLine);
+}
+
+SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
+ const SwTabFrame *pT, const SubColFlags nSCol ) :
+ SwRect( rRect ),
+ nStyle( nStyl ),
+ pTab( pT ),
+ nSubColor( nSCol ),
+ bPainted( false ),
+ nLock( 0 )
+{
+ if ( pCol != nullptr )
+ aColor = *pCol;
+}
+
+bool SwLineRect::MakeUnion( const SwRect &rRect, SwPaintProperties const & properties)
+{
+ // It has already been tested outside, whether the rectangles have
+ // the same orientation (horizontal or vertical), color, etc.
+ if ( Height() > Width() ) //Vertical line
+ {
+ if ( Left() == rRect.Left() && Width() == rRect.Width() )
+ {
+ // Merge when there is no gap between the lines
+ const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
+ if ( Bottom() + nAdd >= rRect.Top() &&
+ Top() - nAdd <= rRect.Bottom() )
+ {
+ Bottom( std::max( Bottom(), rRect.Bottom() ) );
+ Top ( std::min( Top(), rRect.Top() ) );
+ return true;
+ }
+ }
+ }
+ else
+ {
+ if ( Top() == rRect.Top() && Height() == rRect.Height() )
+ {
+ // Merge when there is no gap between the lines
+ const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
+ if ( Right() + nAdd >= rRect.Left() &&
+ Left() - nAdd <= rRect.Right() )
+ {
+ Right( std::max( Right(), rRect.Right() ) );
+ Left ( std::min( Left(), rRect.Left() ) );
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SwLineRects::AddLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
+ const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const & properties )
+{
+ // Loop backwards because lines which can be combined, can usually be painted
+ // in the same context
+ for (reverse_iterator it = aLineRects.rbegin(); it != aLineRects.rend();
+ ++it)
+ {
+ SwLineRect &rLRect = (*it);
+ // Test for the orientation, color, table
+ if ( rLRect.GetTab() == pTab &&
+ !rLRect.IsPainted() && rLRect.GetSubColor() == nSCol &&
+ (rLRect.Height() > rLRect.Width()) == (rRect.Height() > rRect.Width()) &&
+ (pCol && rLRect.GetColor() == *pCol) )
+ {
+ if ( rLRect.MakeUnion( rRect, properties ) )
+ return;
+ }
+ }
+ aLineRects.emplace_back( rRect, pCol, nStyle, pTab, nSCol );
+}
+
+void SwLineRects::ConnectEdges( OutputDevice const *pOut, SwPaintProperties const & properties )
+{
+ if ( pOut->GetOutDevType() != OUTDEV_PRINTER )
+ {
+ // I'm not doing anything for a too small zoom
+ if ( properties.aSScaleX < aEdgeScale || properties.aSScaleY < aEdgeScale )
+ return;
+ }
+
+ static const long nAdd = 20;
+
+ std::vector<SwLineRect*> aCheck;
+
+ for (size_t i = 0; i < aLineRects.size(); ++i)
+ {
+ SwLineRect &rL1 = aLineRects[i];
+ if ( !rL1.GetTab() || rL1.IsPainted() || rL1.IsLocked() )
+ continue;
+
+ aCheck.clear();
+
+ const bool bVert = rL1.Height() > rL1.Width();
+ long nL1a, nL1b, nL1c, nL1d;
+
+ if ( bVert )
+ {
+ nL1a = rL1.Top(); nL1b = rL1.Left();
+ nL1c = rL1.Right(); nL1d = rL1.Bottom();
+ }
+ else
+ {
+ nL1a = rL1.Left(); nL1b = rL1.Top();
+ nL1c = rL1.Bottom(); nL1d = rL1.Right();
+ }
+
+ // Collect all lines to possibly link with i1
+ for (iterator it2 = aLineRects.begin(); it2 != aLineRects.end(); ++it2)
+ {
+ SwLineRect &rL2 = (*it2);
+ if ( rL2.GetTab() != rL1.GetTab() ||
+ rL2.IsPainted() ||
+ rL2.IsLocked() ||
+ (bVert == (rL2.Height() > rL2.Width())) )
+ continue;
+
+ long nL2a, nL2b, nL2c, nL2d;
+ if ( bVert )
+ {
+ nL2a = rL2.Top(); nL2b = rL2.Left();
+ nL2c = rL2.Right(); nL2d = rL2.Bottom();
+ }
+ else
+ {
+ nL2a = rL2.Left(); nL2b = rL2.Top();
+ nL2c = rL2.Bottom(); nL2d = rL2.Right();
+ }
+
+ if ( (nL1a - nAdd < nL2d && nL1d + nAdd > nL2a) &&
+ ((nL1b > nL2b && nL1c < nL2c) ||
+ (nL1c >= nL2c && nL1b - nAdd < nL2c) ||
+ (nL1b <= nL2b && nL1c + nAdd > nL2b)) )
+ {
+ aCheck.push_back( &rL2 );
+ }
+ }
+ if ( aCheck.size() < 2 )
+ continue;
+
+ bool bRemove = false;
+
+ // For each line test all following ones.
+ for ( size_t k = 0; !bRemove && k < aCheck.size(); ++k )
+ {
+ SwLineRect &rR1 = *aCheck[k];
+
+ for ( size_t k2 = k+1; !bRemove && k2 < aCheck.size(); ++k2 )
+ {
+ SwLineRect &rR2 = *aCheck[k2];
+ if ( bVert )
+ {
+ SwLineRect *pLA = nullptr;
+ SwLineRect *pLB = nullptr;
+ if ( rR1.Top() < rR2.Top() )
+ {
+ pLA = &rR1; pLB = &rR2;
+ }
+ else if ( rR1.Top() > rR2.Top() )
+ {
+ pLA = &rR2; pLB = &rR1;
+ }
+ // are k1 and k2 describing a double line?
+ if ( pLA && pLA->Bottom() + 60 > pLB->Top() )
+ {
+ if ( rL1.Top() < pLA->Top() )
+ {
+ if ( rL1.Bottom() == pLA->Bottom() )
+ continue; //Small mistake (where?)
+
+ SwRect aIns( rL1 );
+ aIns.Bottom( pLA->Bottom() );
+ if ( !rL1.IsInside( aIns ) )
+ continue;
+ aLineRects.emplace_back( aIns, &rL1.GetColor(),
+ SvxBorderLineStyle::SOLID,
+ rL1.GetTab(), SubColFlags::Tab );
+ if ( isFull() )
+ {
+ --i;
+ k = aCheck.size();
+ break;
+ }
+ }
+
+ if ( rL1.Bottom() > pLB->Bottom() )
+ rL1.Top( pLB->Top() ); // extend i1 on the top
+ else
+ bRemove = true; //stopping, remove i1
+ }
+ }
+ else
+ {
+ SwLineRect *pLA = nullptr;
+ SwLineRect *pLB = nullptr;
+ if ( rR1.Left() < rR2.Left() )
+ {
+ pLA = &rR1; pLB = &rR2;
+ }
+ else if ( rR1.Left() > rR2.Left() )
+ {
+ pLA = &rR2; pLB = &rR1;
+ }
+ // Is it double line?
+ if ( pLA && pLA->Right() + 60 > pLB->Left() )
+ {
+ if ( rL1.Left() < pLA->Left() )
+ {
+ if ( rL1.Right() == pLA->Right() )
+ continue; //small error
+
+ SwRect aIns( rL1 );
+ aIns.Right( pLA->Right() );
+ if ( !rL1.IsInside( aIns ) )
+ continue;
+ aLineRects.emplace_back( aIns, &rL1.GetColor(),
+ SvxBorderLineStyle::SOLID,
+ rL1.GetTab(), SubColFlags::Tab );
+ if ( isFull() )
+ {
+ --i;
+ k = aCheck.size();
+ break;
+ }
+ }
+ if ( rL1.Right() > pLB->Right() )
+ rL1.Left( pLB->Left() );
+ else
+ bRemove = true;
+ }
+ }
+ }
+ }
+ if ( bRemove )
+ {
+ aLineRects.erase(aLineRects.begin() + i);
+ --i;
+ }
+ }
+}
+
+void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const & properties )
+{
+ // All help lines that are covered by any border will be removed or split
+ for (size_t i = 0; i < aLineRects.size(); ++i)
+ {
+ // get a copy instead of a reference, because an <insert> may destroy
+ // the object due to a necessary array resize.
+ const SwLineRect aSubsLineRect = SwLineRect(aLineRects[i]);
+
+ // add condition <aSubsLineRect.IsLocked()> in order to consider only
+ // border lines, which are *not* locked.
+ if ( aSubsLineRect.IsPainted() ||
+ aSubsLineRect.IsLocked() )
+ continue;
+
+ const bool bVerticalSubs = aSubsLineRect.Height() > aSubsLineRect.Width();
+ SwRect aSubsRect( aSubsLineRect );
+ if ( bVerticalSubs )
+ {
+ aSubsRect.Left ( aSubsRect.Left() - (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
+ aSubsRect.Right ( aSubsRect.Right() + (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
+ }
+ else
+ {
+ aSubsRect.Top ( aSubsRect.Top() - (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
+ aSubsRect.Bottom( aSubsRect.Bottom() + (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
+ }
+ for (const_iterator itK = rRects.aLineRects.begin(); itK != rRects.aLineRects.end(); ++itK)
+ {
+ const SwLineRect &rLine = *itK;
+
+ // do *not* consider painted or locked border lines.
+ // #i1837# - locked border lines have to be considered.
+ if ( rLine.IsLocked () )
+ continue;
+
+ if ( !bVerticalSubs == ( rLine.Height() > rLine.Width() ) ) //same direction?
+ continue;
+
+ if ( aSubsRect.IsOver( rLine ) )
+ {
+ if ( bVerticalSubs ) // Vertical?
+ {
+ if ( aSubsRect.Left() <= rLine.Right() &&
+ aSubsRect.Right() >= rLine.Left() )
+ {
+ long nTmp = rLine.Top()-(properties.nSPixelSzH+1);
+ if ( aSubsLineRect.Top() < nTmp )
+ {
+ SwRect aNewSubsRect( aSubsLineRect );
+ aNewSubsRect.Bottom( nTmp );
+ aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+ aSubsLineRect.GetSubColor() );
+ }
+ nTmp = rLine.Bottom()+properties.nSPixelSzH+1;
+ if ( aSubsLineRect.Bottom() > nTmp )
+ {
+ SwRect aNewSubsRect( aSubsLineRect );
+ aNewSubsRect.Top( nTmp );
+ aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+ aSubsLineRect.GetSubColor() );
+ }
+ aLineRects.erase(aLineRects.begin() + i);
+ --i;
+ break;
+ }
+ }
+ else // Horizontal
+ {
+ if ( aSubsRect.Top() <= rLine.Bottom() &&
+ aSubsRect.Bottom() >= rLine.Top() )
+ {
+ long nTmp = rLine.Left()-(properties.nSPixelSzW+1);
+ if ( aSubsLineRect.Left() < nTmp )
+ {
+ SwRect aNewSubsRect( aSubsLineRect );
+ aNewSubsRect.Right( nTmp );
+ aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+ aSubsLineRect.GetSubColor() );
+ }
+ nTmp = rLine.Right()+properties.nSPixelSzW+1;
+ if ( aSubsLineRect.Right() > nTmp )
+ {
+ SwRect aNewSubsRect( aSubsLineRect );
+ aNewSubsRect.Left( nTmp );
+ aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+ aSubsLineRect.GetSubColor() );
+ }
+ aLineRects.erase(aLineRects.begin() + i);
+ --i;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void SwLineRects::LockLines( bool bLock )
+{
+ for (iterator it = aLineRects.begin(); it != aLineRects.end(); ++it)
+ (*it).Lock( bLock );
+}
+
+static void lcl_DrawDashedRect( OutputDevice * pOut, SwLineRect const & rLRect )
+{
+ long startX = rLRect.Left( ), endX;
+ long startY = rLRect.Top( ), endY;
+
+ // Discriminate vertically stretched rect from horizontally stretched
+ // and restrict minimum nHalfLWidth to 1
+ long nHalfLWidth = std::max( static_cast<long>(std::min( rLRect.Width( ), rLRect.Height( ) ) / 2), 1L );
+
+ if ( rLRect.Height( ) > rLRect.Width( ) )
+ {
+ startX += nHalfLWidth;
+ endX = startX;
+ endY = startY + rLRect.Height( );
+ }
+ else
+ {
+ startY += nHalfLWidth;
+ endY = startY;
+ endX = startX + rLRect.Width( );
+ }
+
+ svtools::DrawLine( *pOut, Point( startX, startY ), Point( endX, endY ),
+ sal_uInt32( nHalfLWidth * 2 ), rLRect.GetStyle( ) );
+}
+
+void SwLineRects::PaintLines( OutputDevice *pOut, SwPaintProperties const &properties )
+{
+ // Paint the borders. Sadly two passes are needed.
+ // Once for the inside and once for the outside edges of tables
+ if ( aLineRects.size() != nLastCount )
+ {
+ // #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
+
+ pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+ pOut->SetFillColor();
+ pOut->SetLineColor();
+ ConnectEdges( pOut, properties );
+ const Color *pLast = nullptr;
+
+ bool bPaint2nd = false;
+ size_t nMinCount = aLineRects.size();
+
+ for ( size_t i = 0; i < aLineRects.size(); ++i )
+ {
+ SwLineRect &rLRect = aLineRects[i];
+
+ if ( rLRect.IsPainted() )
+ continue;
+
+ if ( rLRect.IsLocked() )
+ {
+ nMinCount = std::min( nMinCount, i );
+ continue;
+ }
+
+ // Paint it now or in the second pass?
+ bool bPaint = true;
+ if ( rLRect.GetTab() )
+ {
+ if ( rLRect.Height() > rLRect.Width() )
+ {
+ // Vertical edge, overlapping with the table edge?
+ SwTwips nLLeft = rLRect.Left() - 30,
+ nLRight = rLRect.Right() + 30,
+ nTLeft = rLRect.GetTab()->Frame().Left() + rLRect.GetTab()->Prt().Left(),
+ nTRight = rLRect.GetTab()->Frame().Left() + rLRect.GetTab()->Prt().Right();
+ if ( (nTLeft >= nLLeft && nTLeft <= nLRight) ||
+ (nTRight>= nLLeft && nTRight<= nLRight) )
+ bPaint = false;
+ }
+ else
+ {
+ // Horizontal edge, overlapping with the table edge?
+ SwTwips nLTop = rLRect.Top() - 30,
+ nLBottom = rLRect.Bottom() + 30,
+ nTTop = rLRect.GetTab()->Frame().Top() + rLRect.GetTab()->Prt().Top(),
+ nTBottom = rLRect.GetTab()->Frame().Top() + rLRect.GetTab()->Prt().Bottom();
+ if ( (nTTop >= nLTop && nTTop <= nLBottom) ||
+ (nTBottom >= nLTop && nTBottom <= nLBottom) )
+ bPaint = false;
+ }
+ }
+ if ( bPaint )
+ {
+ if ( !pLast || *pLast != rLRect.GetColor() )
+ {
+ pLast = &rLRect.GetColor();
+
+ DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+ if( properties.pSGlobalShell->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ pOut->SetDrawMode( DrawModeFlags::Default );
+
+ pOut->SetLineColor( *pLast );
+ pOut->SetFillColor( *pLast );
+ pOut->SetDrawMode( nOldDrawMode );
+ }
+
+ if( !rLRect.IsEmpty() )
+ lcl_DrawDashedRect( pOut, rLRect );
+ rLRect.SetPainted();
+ }
+ else
+ bPaint2nd = true;
+ }
+ if ( bPaint2nd )
+ {
+ for ( size_t i = 0; i < aLineRects.size(); ++i )
+ {
+ SwLineRect &rLRect = aLineRects[i];
+ if ( rLRect.IsPainted() )
+ continue;
+
+ if ( rLRect.IsLocked() )
+ {
+ nMinCount = std::min( nMinCount, i );
+ continue;
+ }
+
+ if ( !pLast || *pLast != rLRect.GetColor() )
+ {
+ pLast = &rLRect.GetColor();
+
+ DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+ if( properties.pSGlobalShell->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pOut->SetDrawMode( DrawModeFlags::Default );
+ }
+
+ pOut->SetFillColor( *pLast );
+ pOut->SetDrawMode( nOldDrawMode );
+ }
+ if( !rLRect.IsEmpty() )
+ lcl_DrawDashedRect( pOut, rLRect );
+ rLRect.SetPainted();
+ }
+ }
+ nLastCount = nMinCount;
+ pOut->Pop();
+ }
+}
+
+void SwSubsRects::PaintSubsidiary( OutputDevice *pOut,
+ const SwLineRects *pRects,
+ SwPaintProperties const & properties )
+{
+ if ( !aLineRects.empty() )
+ {
+ // #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
+
+ // Remove all help line that are almost covered (tables)
+ for (size_type i = 0; i != aLineRects.size(); ++i)
+ {
+ SwLineRect &rLi = aLineRects[i];
+ const bool bVerticalSubs = rLi.Height() > rLi.Width();
+
+ for (size_type k = i + 1; k != aLineRects.size(); ++k)
+ {
+ SwLineRect &rLk = aLineRects[k];
+ if ( rLi.SSize() == rLk.SSize() )
+ {
+ if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) )
+ {
+ if ( bVerticalSubs )
+ {
+ long nLi = rLi.Right();
+ long nLk = rLk.Right();
+ if ( rLi.Top() == rLk.Top() &&
+ ((nLi < rLk.Left() && nLi+21 > rLk.Left()) ||
+ (nLk < rLi.Left() && nLk+21 > rLi.Left())))
+ {
+ aLineRects.erase(aLineRects.begin() + k);
+ // don't continue with inner loop any more:
+ // the array may shrink!
+ --i;
+ break;
+ }
+ }
+ else
+ {
+ long nLi = rLi.Bottom();
+ long nLk = rLk.Bottom();
+ if ( rLi.Left() == rLk.Left() &&
+ ((nLi < rLk.Top() && nLi+21 > rLk.Top()) ||
+ (nLk < rLi.Top() && nLk+21 > rLi.Top())))
+ {
+ aLineRects.erase(aLineRects.begin() + k);
+ // don't continue with inner loop any more:
+ // the array may shrink!
+ --i;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( pRects && (!pRects->aLineRects.empty()) )
+ RemoveSuperfluousSubsidiaryLines( *pRects, properties );
+
+ if ( !aLineRects.empty() )
+ {
+ pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+ pOut->SetLineColor();
+
+ // Reset draw mode in high contrast mode in order to get fill color
+ // set at output device. Recover draw mode after draw of lines.
+ // Necessary for the subsidiary lines painted by the fly frames.
+ DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+ if( gProp.pSGlobalShell->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pOut->SetDrawMode( DrawModeFlags::Default );
+ }
+
+ for (SwSubsRects::iterator it = aLineRects.begin(); it != aLineRects.end();
+ ++it)
+ {
+ SwLineRect &rLRect = (*it);
+ // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
+ if ( !rLRect.IsPainted() &&
+ !rLRect.IsLocked() )
+ {
+ const Color *pCol = nullptr;
+ switch ( rLRect.GetSubColor() )
+ {
+ case SubColFlags::Page: pCol = &SwViewOption::GetDocBoundariesColor(); break;
+ case SubColFlags::Fly: pCol = &SwViewOption::GetObjectBoundariesColor(); break;
+ case SubColFlags::Tab: pCol = &SwViewOption::GetTableBoundariesColor(); break;
+ case SubColFlags::Sect: pCol = &SwViewOption::GetSectionBoundColor(); break;
+ }
+
+ if (pCol && pOut->GetFillColor() != *pCol)
+ pOut->SetFillColor( *pCol );
+ pOut->DrawRect( rLRect.SVRect() );
+
+ rLRect.SetPainted();
+ }
+ }
+
+ pOut->SetDrawMode( nOldDrawMode );
+
+ pOut->Pop();
+ }
+ }
+}
+
+// Various functions that are use in this file.
+
+/**
+ * Function <SwAlignRect(..)> is also used outside this file
+ *
+ * Correction: adjust rectangle on pixel level in order to make sure,
+ * that the border "leaves its original pixel", if it has to
+ * No prior adjustments for odd relation between pixel and twip
+ */
+void SwAlignRect( SwRect &rRect, const SwViewShell *pSh, const vcl::RenderContext* pRenderContext )
+{
+ if( !rRect.HasArea() )
+ return;
+
+ // Make sure that view shell (parameter <pSh>) exists, if the output device
+ // is taken from this view shell --> no output device, no alignment
+ // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
+ if ( !gProp.bSFlyMetafile && !pSh )
+ {
+ return;
+ }
+
+ const vcl::RenderContext *pOut = gProp.bSFlyMetafile ?
+ gProp.pSFlyMetafileOut.get() : pRenderContext;
+
+ // Hold original rectangle in pixel
+ const tools::Rectangle aOrgPxRect = pOut->LogicToPixel( rRect.SVRect() );
+ // Determine pixel-center rectangle in twip
+ const SwRect aPxCenterRect( pOut->PixelToLogic( aOrgPxRect ) );
+
+ // Perform adjustments on pixel level.
+ SwRect aAlignedPxRect( aOrgPxRect );
+ if ( rRect.Top() > aPxCenterRect.Top() )
+ {
+ // 'leave pixel overlapping on top'
+ aAlignedPxRect.Top( aAlignedPxRect.Top() + 1 );
+ }
+
+ if ( rRect.Bottom() < aPxCenterRect.Bottom() )
+ {
+ // 'leave pixel overlapping on bottom'
+ aAlignedPxRect.Bottom( aAlignedPxRect.Bottom() - 1 );
+ }
+
+ if ( rRect.Left() > aPxCenterRect.Left() )
+ {
+ // 'leave pixel overlapping on left'
+ aAlignedPxRect.Left( aAlignedPxRect.Left() + 1 );
+ }
+
+ if ( rRect.Right() < aPxCenterRect.Right() )
+ {
+ // 'leave pixel overlapping on right'
+ aAlignedPxRect.Right( aAlignedPxRect.Right() - 1 );
+ }
+
+ // Consider negative width/height check, if aligned SwRect has negative width/height.
+ // If Yes, adjust it to width/height = 0 twip.
+ // NOTE: A SwRect with negative width/height can occur, if the width/height
+ // of the given SwRect in twip was less than a pixel in twip and that
+ // the alignment calculates that the aligned SwRect should not contain
+ // the pixels the width/height is on.
+ if ( aAlignedPxRect.Width() < 0 )
+ {
+ aAlignedPxRect.Width(0);
+ }
+ if ( aAlignedPxRect.Height() < 0 )
+ {
+ aAlignedPxRect.Height(0);
+ }
+ // Consider zero width/height for converting a rectangle from
+ // pixel to logic it needs a width/height. Thus, set width/height
+ // to one, if it's zero and correct this on the twip level after the conversion.
+ bool bZeroWidth = false;
+ if ( aAlignedPxRect.Width() == 0 )
+ {
+ aAlignedPxRect.Width(1);
+ bZeroWidth = true;
+ }
+ bool bZeroHeight = false;
+ if ( aAlignedPxRect.Height() == 0 )
+ {
+ aAlignedPxRect.Height(1);
+ bZeroHeight = true;
+ }
+
+ rRect = pOut->PixelToLogic( aAlignedPxRect.SVRect() );
+
+ // Consider zero width/height and adjust calculated aligned twip rectangle.
+ // Reset width/height to zero; previous negative width/height haven't to be considered.
+ if ( bZeroWidth )
+ {
+ rRect.Width(0);
+ }
+ if ( bZeroHeight )
+ {
+ rRect.Height(0);
+ }
+}
+
+/**
+ * Helper for twip adjustments on pixel base
+ *
+ * This method compares the x- or y-pixel position of two twip-points.
+ * If the x-/y-pixel positions are the same, the x-/y-pixel position of
+ * the second twip point is adjusted by a given amount of pixels
+*/
+static void lcl_CompPxPosAndAdjustPos( const vcl::RenderContext& _rOut,
+ const Point& _rRefPt,
+ Point& _rCompPt,
+ const bool _bChkXPos,
+ const sal_Int8 _nPxAdjustment )
+{
+ const Point aRefPxPt = _rOut.LogicToPixel( _rRefPt );
+ Point aCompPxPt = _rOut.LogicToPixel( _rCompPt );
+
+ if ( _bChkXPos )
+ {
+ if ( aCompPxPt.X() == aRefPxPt.X() )
+ {
+ aCompPxPt.X() += _nPxAdjustment ;
+ const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt );
+ _rCompPt.X() = aAdjustedCompPt.X();
+ }
+ }
+ else
+ {
+ if ( aCompPxPt.Y() == aRefPxPt.Y() )
+ {
+ aCompPxPt.Y() += _nPxAdjustment ;
+ const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt );
+ _rCompPt.Y() = aAdjustedCompPt.Y();
+ }
+ }
+}
+
+/**
+ * Method to pixel-align rectangle for drawing graphic object
+ *
+ * Because we are drawing graphics from the left-top-corner in conjunction
+ * with size coordinates, these coordinates have to be calculated at a pixel
+ * level.
+ * Thus, we convert the rectangle to pixel and then convert to left-top-corner
+ * and then get size of pixel rectangle back to logic.
+ * This calculation is necessary, because there's a different between
+ * the conversion from logic to pixel of a normal rectangle with its left-top-
+ * and right-bottom-corner and the same conversion of the same rectangle
+ * with left-top-corner and size.
+ *
+ * NOTE: Call this method before each <GraphicObject.Draw(...)>
+*/
+void SwAlignGrfRect( SwRect *pGrfRect, const vcl::RenderContext &rOut )
+{
+ tools::Rectangle aPxRect = rOut.LogicToPixel( pGrfRect->SVRect() );
+ pGrfRect->Pos( rOut.PixelToLogic( aPxRect.TopLeft() ) );
+ pGrfRect->SSize( rOut.PixelToLogic( aPxRect.GetSize() ) );
+}
+
+static long lcl_AlignWidth( const long nWidth, SwPaintProperties const & properties )
+{
+ if ( nWidth )
+ {
+ const long nW = nWidth % properties.nSPixelSzW;
+
+ if ( !nW || nW > properties.nSHalfPixelSzW )
+ return std::max(1L, nWidth - properties.nSHalfPixelSzW);
+ }
+ return nWidth;
+}
+
+static long lcl_AlignHeight( const long nHeight, SwPaintProperties const & properties )
+{
+ if ( nHeight )
+ {
+ const long nH = nHeight % properties.nSPixelSzH;
+
+ if ( !nH || nH > properties.nSHalfPixelSzH )
+ return std::max(1L, nHeight - properties.nSHalfPixelSzH);
+ }
+ return nHeight;
+}
+
+static long lcl_MinHeightDist( const long nDist, SwPaintProperties const & properties )
+{
+ if ( properties.aSScaleX < aMinDistScale || properties.aSScaleY < aMinDistScale )
+ return nDist;
+ return ::lcl_AlignHeight( std::max( nDist, properties.nSMinDistPixelH ), properties);
+}
+
+/**
+ * Calculate PrtArea plus surrounding plus shadow
+ */
+static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame,
+ const SwBorderAttrs &rAttrs,
+ const bool bShadow,
+ SwPaintProperties const & properties)
+{
+ // Special handling for cell frames.
+ // The printing area of a cell frame is completely enclosed in the frame area
+ // and a cell frame has no shadow. Thus, for cell frames the calculated
+ // area equals the frame area.
+ // Notes: Borders of cell frames in R2L text direction will switch its side
+ // - left border is painted on the right; right border on the left.
+ // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
+ if( pFrame->IsSctFrame() )
+ {
+ rRect = pFrame->Prt();
+ rRect.Pos() += pFrame->Frame().Pos();
+ }
+ else if ( pFrame->IsCellFrame() )
+ rRect = pFrame->Frame();
+ else
+ {
+ rRect = pFrame->Prt();
+ rRect.Pos() += pFrame->Frame().Pos();
+
+ if ( rAttrs.IsLine() || rAttrs.IsBorderDist() ||
+ (bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE) )
+ {
+ SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+
+ const SvxBoxItem &rBox = rAttrs.GetBox();
+ const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
+ if ( bTop )
+ {
+ SwTwips nDiff = rBox.GetTop() ?
+ rBox.CalcLineSpace( SvxBoxItemLine::TOP ) :
+ ( rAttrs.IsBorderDist() ?
+ // Increase of distance by one twip is incorrect.
+ rBox.GetDistance( SvxBoxItemLine::TOP ) : 0 );
+ if( nDiff )
+ (rRect.*fnRect->fnSubTop)( nDiff );
+ }
+
+ const bool bBottom = 0 != (pFrame->*fnRect->fnGetBottomMargin)();
+ if ( bBottom )
+ {
+ SwTwips nDiff = 0;
+ // #i29550#
+ if ( pFrame->IsTabFrame() &&
+ static_cast<const SwTabFrame*>(pFrame)->IsCollapsingBorders() )
+ {
+ // For collapsing borders, we have to add the height of
+ // the height of the last line
+ nDiff = static_cast<const SwTabFrame*>(pFrame)->GetBottomLineSize();
+ }
+ else
+ {
+ nDiff = rBox.GetBottom() ?
+ rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM ) :
+ ( rAttrs.IsBorderDist() ?
+ // Increase of distance by one twip is incorrect.
+ rBox.GetDistance( SvxBoxItemLine::BOTTOM ) : 0 );
+ }
+ if( nDiff )
+ (rRect.*fnRect->fnAddBottom)( nDiff );
+ }
+
+ if ( rBox.GetLeft() )
+ (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( SvxBoxItemLine::LEFT ) );
+ else if ( rAttrs.IsBorderDist() )
+ // Increase of distance by one twip is incorrect.
+ (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( SvxBoxItemLine::LEFT ) );
+
+ if ( rBox.GetRight() )
+ (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( SvxBoxItemLine::RIGHT ) );
+ else if ( rAttrs.IsBorderDist() )
+ // Increase of distance by one twip is incorrect.
+ (rRect.*fnRect->fnAddRight)( rBox.GetDistance( SvxBoxItemLine::RIGHT ) );
+
+ if ( bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
+ {
+ const SvxShadowItem &rShadow = rAttrs.GetShadow();
+ if ( bTop )
+ (rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
+ (rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
+ if ( bBottom )
+ (rRect.*fnRect->fnAddBottom)
+ (rShadow.CalcShadowSpace( SvxShadowItemSide::BOTTOM ));
+ (rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
+ }
+ }
+ }
+
+ ::SwAlignRect( rRect, properties.pSGlobalShell, properties.pSGlobalShell ? properties.pSGlobalShell->GetOut() : nullptr );
+}
+
+/**
+ * Extend left/right border/shadow rectangle to bottom of previous frame/to
+ * top of next frame, if border/shadow is joined with previous/next frame
+ */
+static void lcl_ExtendLeftAndRight( SwRect& _rRect,
+ const SwFrame& _rFrame,
+ const SwBorderAttrs& _rAttrs,
+ const SwRectFn& _rRectFn )
+{
+ if ( _rAttrs.JoinedWithPrev( _rFrame ) )
+ {
+ const SwFrame* pPrevFrame = _rFrame.GetPrev();
+ (_rRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
+ }
+ if ( _rAttrs.JoinedWithNext( _rFrame ) )
+ {
+ const SwFrame* pNextFrame = _rFrame.GetNext();
+ (_rRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
+ }
+}
+
+/// Returns a range suitable for subtraction when lcl_SubtractFlys() is used.
+/// Otherwise DrawFillAttributes() expands the clip path itself.
+static basegfx::B2DRange lcl_ShrinkFly(const SwRect& rRect)
+{
+ static MapMode aMapMode(MapUnit::MapTwip);
+ static const Size aSingleUnit = Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode);
+
+ double x1 = rRect.Left() + aSingleUnit.getWidth();
+ double y1 = rRect.Top() + aSingleUnit.getHeight();
+ double x2 = rRect.Right() - aSingleUnit.getWidth();
+ double y2 = rRect.Bottom() - aSingleUnit.getHeight();
+
+ return basegfx::B2DRange(x1, y1, x2, y2);
+}
+
+static void lcl_SubtractFlys( const SwFrame *pFrame, const SwPageFrame *pPage,
+ const SwRect &rRect, SwRegionRects &rRegion, basegfx::tools::B2DClipState& rClipState, SwPaintProperties const & rProperties)
+{
+ const SwSortedObjs& rObjs = *pPage->GetSortedObjs();
+ const SwFlyFrame* pSelfFly = pFrame->IsInFly() ? pFrame->FindFlyFrame() : gProp.pSRetoucheFly2;
+ if (!gProp.pSRetoucheFly)
+ gProp.pSRetoucheFly = gProp.pSRetoucheFly2;
+
+ for (size_t j = 0; (j < rObjs.size()) && !rRegion.empty(); ++j)
+ {
+ const SwAnchoredObject* pAnchoredObj = rObjs[j];
+ const SdrObject* pSdrObj = pAnchoredObj->GetDrawObj();
+
+ // Do not consider invisible objects
+ if (!pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj->GetLayer()))
+ continue;
+
+ if (dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) == nullptr)
+ continue;
+
+ const SwFlyFrame *pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
+
+ if (pSelfFly == pFly || gProp.pSRetoucheFly == pFly || !rRect.IsOver(pFly->Frame()))
+ continue;
+
+ if (!pFly->GetFormat()->GetPrint().GetValue() &&
+ (OUTDEV_PRINTER == gProp.pSGlobalShell->GetOut()->GetOutDevType() ||
+ gProp.pSGlobalShell->IsPreview()))
+ continue;
+
+ const bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly );
+
+ //For character bound Flys only examine those Flys in which it is not
+ //anchored itself.
+ //Why only for character bound ones you may ask? It never makes sense to
+ //subtract frames in which it is anchored itself right?
+ if (pSelfFly && pSelfFly->IsLowerOf(pFly))
+ continue;
+
+ //Any why does it not apply for the RetoucheFly too?
+ if (gProp.pSRetoucheFly && gProp.pSRetoucheFly->IsLowerOf(pFly))
+ continue;
+
+#if OSL_DEBUG_LEVEL > 0
+ //Flys who are anchored inside their own one, must have a bigger OrdNum
+ //or be character bound.
+ if (pSelfFly && bLowerOfSelf)
+ {
+ OSL_ENSURE( pFly->IsFlyInContentFrame() ||
+ pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(),
+ "Fly with wrong z-Order" );
+ }
+#endif
+
+ bool bStopOnHell = true;
+ if (pSelfFly)
+ {
+ const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
+ if (pSdrObj->GetLayer() == pTmp->GetLayer())
+ {
+ if (pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect())
+ //In the same layer we only observe those that are above.
+ continue;
+ }
+ else
+ {
+ if (!bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue())
+ //From other layers we are only interested in non
+ //transparent ones or those that are internal
+ continue;
+ bStopOnHell = false;
+ }
+ }
+ if (gProp.pSRetoucheFly)
+ {
+ const SdrObject *pTmp = gProp.pSRetoucheFly->GetVirtDrawObj();
+ if ( pSdrObj->GetLayer() == pTmp->GetLayer() )
+ {
+ if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
+ //In the same layer we only observe those that are above.
+ continue;
+ }
+ else
+ {
+ if (!pFly->IsLowerOf( gProp.pSRetoucheFly ) && !pFly->GetFormat()->GetOpaque().GetValue())
+ //From other layers we are only interested in non
+ //transparent ones or those that are internal
+ continue;
+ bStopOnHell = false;
+ }
+ }
+
+ //If the content of the Fly is transparent, we subtract it only if it's
+ //contained in the hell layer.
+ const IDocumentDrawModelAccess& rIDDMA = pFly->GetFormat()->getIDocumentDrawModelAccess();
+ bool bHell = pSdrObj->GetLayer() == rIDDMA.GetHellId();
+ if ( (bStopOnHell && bHell) ||
+ /// Change internal order of condition
+ /// first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()"
+ /// have not to be performed, if frame is in "Hell"
+ ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTextFrame() &&
+ (static_cast<SwNoTextFrame const*>(pFly->Lower())->IsTransparent() ||
+ static_cast<SwNoTextFrame const*>(pFly->Lower())->HasAnimation() ||
+ pFly->GetFormat()->GetSurround().IsContour()
+ )
+ )
+ )
+ continue;
+
+ // Own if-statements for transparent background/shadow of fly frames
+ // in order to handle special conditions.
+ if (pFly->IsBackgroundTransparent())
+ {
+ // Background <pFly> is transparent drawn. Thus normally, its region
+ // have not to be subtracted from given region.
+ // But, if method is called for a fly frame and
+ // <pFly> is a direct lower of this fly frame and
+ // <pFly> inherites its transparent background brush from its parent,
+ // then <pFly> frame area have to be subtracted from given region.
+ // NOTE: Because in Status Quo transparent backgrounds can only be
+ // assigned to fly frames, the handle of this special case
+ // avoids drawing of transparent areas more than once, if
+ // a fly frame inherites a transparent background from its
+ // parent fly frame.
+ if (pFrame->IsFlyFrame() &&
+ (pFly->GetAnchorFrame()->FindFlyFrame() == pFrame) &&
+ pFly->GetFormat()->IsBackgroundBrushInherited()
+ )
+ {
+ SwRect aRect;
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
+ rRegion -= aRect;
+ rClipState.subtractRange(lcl_ShrinkFly(aRect));
+ continue;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ if (bHell && pFly->GetAnchorFrame()->IsInFly())
+ {
+ //So the border won't get dismantled by the background of the other
+ //Fly.
+ SwRect aRect;
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
+ rRegion -= aRect;
+ rClipState.subtractRange(lcl_ShrinkFly(aRect));
+ }
+ else
+ {
+ SwRect aRect( pFly->Prt() );
+ aRect += pFly->Frame().Pos();
+ rRegion -= aRect;
+ rClipState.subtractRange(lcl_ShrinkFly(aRect));
+ }
+ }
+ if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
+ gProp.pSRetoucheFly = nullptr;
+}
+
+static void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
+ vcl::RenderContext* _pOut,
+ const SwRect& _rAlignedPaintRect,
+ const GraphicObject& _rGraphicObj,
+ SwPaintProperties const & properties)
+{
+ /// determine color of background
+ /// If color of background brush is not "no fill"/"auto fill" or
+ /// <SwPaintProperties.bSFlyMetafile> is set, use color of background brush, otherwise
+ /// use global retouche color.
+ const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || properties.bSFlyMetafile )
+ ? _rBackgrdBrush.GetColor()
+ : aGlobalRetoucheColor );
+
+ /// determine, if background color have to be drawn transparent
+ /// and calculate transparency percent value
+ sal_Int8 nTransparencyPercent = 0;
+ bool bDrawTransparent = false;
+ if ( aColor.GetTransparency() != 0 )
+ /// background color is transparent --> draw transparent.
+ {
+ bDrawTransparent = true;
+ nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF;
+ }
+ else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) &&
+ (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) )
+ /// graphic is drawn transparent and background color is
+ /// "no fill"/"auto fill" --> draw transparent
+ {
+ bDrawTransparent = true;
+ nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF;
+ }
+
+ if ( bDrawTransparent )
+ {
+ /// draw background transparent
+ if( _pOut->GetFillColor() != aColor.GetRGBColor() )
+ _pOut->SetFillColor( aColor.GetRGBColor() );
+ tools::PolyPolygon aPoly( _rAlignedPaintRect.SVRect() );
+ _pOut->DrawTransparent( aPoly, nTransparencyPercent );
+ }
+ else
+ {
+ /// draw background opaque
+ if ( _pOut->GetFillColor() != aColor )
+ _pOut->SetFillColor( aColor );
+ _pOut->DrawRect( _rAlignedPaintRect.SVRect() );
+ }
+}
+
+/**
+ * This is a local help method to draw a background for a graphic
+ *
+ * Under certain circumstances we have to draw a background for a graphic.
+ * This method takes care of the conditions and draws the background with the
+ * corresponding color.
+ * Method introduced for bug fix #103876# in order to optimize drawing tiled
+ * background graphics. Previously, this code was integrated in method
+ * <lcl_DrawGraphic>.
+ * Method implemented as a inline, checking the conditions and calling method
+ * method <lcl_implDrawGraphicBackgrd(..)> for the intrinsic drawing.
+ *
+ * @param _rBackgrdBrush
+ * background brush contain the color the background has to be drawn.
+ *
+ * @param _pOut
+ * output device the background has to be drawn in.
+ *
+ * @param _rAlignedPaintRect
+ * paint rectangle in the output device, which has to be drawn with the background.
+ * rectangle have to be aligned by method ::SwAlignRect
+ *
+ * @param _rGraphicObj
+ * graphic object, for which the background has to be drawn. Used for checking
+ * the transparency of its bitmap, its type and if the graphic is drawn transparent
+ *
+ * @param _bNumberingGraphic
+ * boolean indicating that graphic is used as a numbering.
+ *
+ * @param _bBackgrdAlreadyDrawn
+ * boolean (optional; default: false) indicating, if the background is already drawn.
+*/
+static inline void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
+ OutputDevice* _pOut,
+ const SwRect& _rAlignedPaintRect,
+ const GraphicObject& _rGraphicObj,
+ bool _bNumberingGraphic,
+ SwPaintProperties const & properties,
+ bool _bBackgrdAlreadyDrawn = false)
+{
+ // draw background with background color, if
+ // (1) graphic is not used as a numbering AND
+ // (2) background is not already drawn AND
+ // (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
+ if ( !_bNumberingGraphic &&
+ !_bBackgrdAlreadyDrawn &&
+ ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GraphicType::NONE )
+ )
+ {
+ lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj, properties );
+ }
+}
+
+/**
+ * NNOTE: the transparency of the background graphic is saved in
+ * SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency()
+ * and is considered in the drawing of the graphic
+ *
+ * Thus, to provide transparent background graphic for text frames nothing
+ * has to be coded
+ *
+ * Use align rectangle for drawing graphic Pixel-align coordinates for
+ * drawing graphic
+ * Outsource code for drawing background of the graphic
+ * with a background color in method <lcl_DrawGraphicBackgrd>
+ *
+ * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
+ */
+static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext *pOut,
+ SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut,
+ bool bClip, bool bGrfNum,
+ SwPaintProperties const & properties,
+ bool bBackgrdAlreadyDrawn )
+ // add parameter <bBackgrdAlreadyDrawn> to indicate
+ // that the background is already drawn.
+{
+ // Calculate align rectangle from parameter <rGrf> and use aligned
+ // rectangle <aAlignedGrfRect> in the following code
+ SwRect aAlignedGrfRect = rGrf;
+ ::SwAlignRect( aAlignedGrfRect, &rSh, pOut );
+
+ // Change type from <bool> to <bool>.
+ const bool bNotInside = bClip && !rOut.IsInside( aAlignedGrfRect );
+ if ( bNotInside )
+ {
+ pOut->Push( PushFlags::CLIPREGION );
+ pOut->IntersectClipRegion( rOut.SVRect() );
+ }
+
+ GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
+
+ // Outsource drawing of background with a background color
+ ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, properties, bBackgrdAlreadyDrawn );
+
+ // Because for drawing a graphic left-top-corner and size coordinates are
+ // used, these coordinates have to be determined on pixel level.
+ ::SwAlignGrfRect( &aAlignedGrfRect, *pOut );
+
+ paintGraphicUsingPrimitivesHelper(*pOut,
+ *pGrf, pGrf->GetAttr(), aAlignedGrfRect);
+
+ if ( bNotInside )
+ pOut->Pop();
+}
+
+bool DrawFillAttributes(
+ const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
+ const SwRect& rOriginalLayoutRect,
+ const SwRegionRects& rPaintRegion,
+ const basegfx::tools::B2DClipState& rClipState,
+ vcl::RenderContext& rOut)
+{
+ if(rFillAttributes.get() && rFillAttributes->isUsed())
+ {
+ basegfx::B2DRange aPaintRange(
+ rPaintRegion.GetOrigin().Left(),
+ rPaintRegion.GetOrigin().Top(),
+ rPaintRegion.GetOrigin().Right(),
+ rPaintRegion.GetOrigin().Bottom());
+
+ if (!aPaintRange.isEmpty() &&
+ !rPaintRegion.empty() &&
+ !basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
+ !basegfx::fTools::equalZero(aPaintRange.getHeight()))
+ {
+ const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
+
+ // need to expand for correct AAed and non-AAed visualization as primitive.
+ // This must probably be removed again when we will be able to get all Writer visualization
+ // as primitives and Writer prepares all it's stuff in high precision coordinates (also
+ // needs to avoid moving boundaries around to better show overlapping stuff...)
+ if(aSvtOptionsDrawinglayer.IsAntiAliasing())
+ {
+ // if AAed in principle expand by 0.5 in all directions. Since painting edges of
+ // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
+ // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
+ // artifacts. Checked experimentally - a little bit more in Y is needed, probably
+ // due to still existing integer alignment and crunching in writer.
+ static double fExpandX = 0.55;
+ static double fExpandY = 0.70;
+ const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX, fExpandY));
+
+ aPaintRange.expand(aPaintRange.getMinimum() - aSingleUnit);
+ aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
+ }
+ else
+ {
+ // if not AAed expand by one unit to bottom right due to the missing unit
+ // from SwRect/Rectangle integer handling
+ const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+
+ aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
+ }
+
+ const basegfx::B2DRange aDefineRange(
+ rOriginalLayoutRect.Left(),
+ rOriginalLayoutRect.Top(),
+ rOriginalLayoutRect.Right(),
+ rOriginalLayoutRect.Bottom());
+
+ const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rFillAttributes->getPrimitive2DSequence(
+ aPaintRange,
+ aDefineRange);
+
+ if(rSequence.size())
+ {
+ drawinglayer::primitive2d::Primitive2DContainer const*
+ pPrimitives(&rSequence);
+ drawinglayer::primitive2d::Primitive2DContainer primitives;
+ // tdf#86578 the awful lcl_SubtractFlys hack
+ if (rPaintRegion.size() > 1 || rPaintRegion[0] != rPaintRegion.GetOrigin())
+ {
+ basegfx::B2DPolyPolygon const maskRegion(rClipState.getClipPoly());
+ primitives.resize(1);
+ primitives[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
+ maskRegion, rSequence);
+ pPrimitives = &primitives;
+ }
+ assert(pPrimitives && pPrimitives->size());
+
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
+ basegfx::B2DHomMatrix(),
+ rOut.GetViewTransformation(),
+ aPaintRange,
+ nullptr,
+ 0.0,
+ uno::Sequence< beans::PropertyValue >());
+ drawinglayer::processor2d::BaseProcessor2D* pProcessor = drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+ rOut,
+ aViewInformation2D);
+
+ if(pProcessor)
+ {
+ pProcessor->process(*pPrimitives);
+
+ delete pProcessor;
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void DrawGraphic(
+ const SvxBrushItem *pBrush,
+ vcl::RenderContext *pOutDev,
+ const SwRect &rOrg,
+ const SwRect &rOut,
+ const sal_uInt8 nGrfNum,
+ const bool bConsiderBackgroundTransparency )
+ // Add 6th parameter to indicate that method should
+ // consider background transparency, saved in the color of the brush item
+{
+ SwViewShell &rSh = *gProp.pSGlobalShell;
+ bool bReplaceGrfNum = GRFNUM_REPLACE == nGrfNum;
+ bool bGrfNum = GRFNUM_NO != nGrfNum;
+ Size aGrfSize;
+ SvxGraphicPosition ePos = GPOS_NONE;
+ if( pBrush && !bReplaceGrfNum )
+ {
+ if( rSh.GetViewOptions()->IsGraphic() )
+ {
+ OUString referer;
+ SfxObjectShell * sh = rSh.GetDoc()->GetPersist();
+ if (sh != nullptr && sh->HasName()) {
+ referer = sh->GetMedium()->GetName();
+ }
+ const Graphic* pGrf = pBrush->GetGraphic(referer);
+ if( pGrf && GraphicType::NONE != pGrf->GetType() )
+ {
+ ePos = pBrush->GetGraphicPos();
+ if( pGrf->IsSupportedGraphic() )
+ // don't the use the specific output device! Bug 94802
+ aGrfSize = ::GetGraphicSizeTwip( *pGrf, nullptr );
+ }
+ }
+ else
+ bReplaceGrfNum = bGrfNum;
+ }
+
+ SwRect aGrf;
+ aGrf.SSize( aGrfSize );
+ bool bDraw = true;
+ bool bRetouche = true;
+ switch ( ePos )
+ {
+ case GPOS_LT:
+ aGrf.Pos() = rOrg.Pos();
+ break;
+
+ case GPOS_MT:
+ aGrf.Pos().Y() = rOrg.Top();
+ aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+ break;
+
+ case GPOS_RT:
+ aGrf.Pos().Y() = rOrg.Top();
+ aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+ break;
+
+ case GPOS_LM:
+ aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+ aGrf.Pos().X() = rOrg.Left();
+ break;
+
+ case GPOS_MM:
+ aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+ aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+ break;
+
+ case GPOS_RM:
+ aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+ aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+ break;
+
+ case GPOS_LB:
+ aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+ aGrf.Pos().X() = rOrg.Left();
+ break;
+
+ case GPOS_MB:
+ aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+ aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+ break;
+
+ case GPOS_RB:
+ aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+ aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+ break;
+
+ case GPOS_AREA:
+ aGrf = rOrg;
+ // Despite the fact that the background graphic has to fill the complete
+ // area, we already checked, whether the graphic will completely fill out
+ // the region the <rOut> that is to be painted. Thus, nothing has to be
+ // touched again.
+ // E.g. this is the case for a Fly Frame without a background
+ // brush positioned on the border of the page which inherited the background
+ // brush from the page.
+ bRetouche = !rOut.IsInside( aGrf );
+ break;
+
+ case GPOS_TILED:
+ {
+ // draw background of tiled graphic before drawing tiled graphic in loop
+ // determine graphic object
+ GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject());
+ // calculate aligned paint rectangle
+ SwRect aAlignedPaintRect = rOut;
+ ::SwAlignRect( aAlignedPaintRect, &rSh, pOutDev );
+ // draw background color for aligned paint rectangle
+ lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum, gProp );
+
+ // set left-top-corner of background graphic to left-top-corner of the
+ // area, from which the background brush is determined.
+ aGrf.Pos() = rOrg.Pos();
+ // setup clipping at output device
+ pOutDev->Push( PushFlags::CLIPREGION );
+ pOutDev->IntersectClipRegion( rOut.SVRect() );
+ // use new method <GraphicObject::DrawTiled(::)>
+ {
+ // calculate paint offset
+ Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() );
+ // draw background graphic tiled for aligned paint rectangle
+ // #i42643#
+ // For PDF export, every draw operation for bitmaps takes a
+ // noticeable amount of place (~50 characters). Thus, optimize
+ // between tile bitmap size and number of drawing operations here.
+
+ // A_out
+ // n_chars = k1 * ---------- + k2 * A_bitmap
+ // A_bitmap
+
+ // minimum n_chars is obtained for (derive for A_bitmap,
+ // set to 0, take positive solution):
+ // k1
+ // A_bitmap = Sqrt( ---- A_out )
+ // k2
+
+ // where k1 is the number of chars per draw operation, and
+ // k2 is the number of chars per bitmap pixel.
+ // This is approximately 50 and 7 for current PDF writer, respectively.
+
+ const double k1( 50 );
+ const double k2( 7 );
+ const Size aSize( aAlignedPaintRect.SSize() );
+ const double Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() );
+
+ pGraphicObj->DrawTiled( pOutDev,
+ aAlignedPaintRect.SVRect(),
+ aGrf.SSize(),
+ Size( aPaintOffset.X(), aPaintOffset.Y() ),
+ GraphicManagerDrawFlags::STANDARD,
+ std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
+ }
+ // reset clipping at output device
+ pOutDev->Pop();
+ // set <bDraw> and <bRetouche> to false, indicating that background
+ // graphic and background are already drawn.
+ bDraw = bRetouche = false;
+ }
+ break;
+
+ case GPOS_NONE:
+ bDraw = false;
+ break;
+
+ default: OSL_ENSURE( !pOutDev, "new Graphic position?" );
+ }
+
+ /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of
+ /// graphic is already drawn or not.
+ bool bGrfBackgrdAlreadyDrawn = false;
+ if ( bRetouche )
+ {
+ pOutDev->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+ pOutDev->SetLineColor();
+
+ // check, if a existing background graphic (not filling the complete
+ // background) is transparent drawn and the background color is
+ // "no fill" respectively "auto fill", if background transparency
+ // has to be considered.
+ // If YES, memorize transparency of background graphic.
+ // check also, if background graphic bitmap is transparent.
+ bool bTransparentGrfWithNoFillBackgrd = false;
+ sal_Int32 nGrfTransparency = 0;
+ bool bGrfIsTransparent = false;
+ if ( (ePos != GPOS_NONE) &&
+ (ePos != GPOS_TILED) && (ePos != GPOS_AREA)
+ )
+ {
+ GraphicObject *pGrf = const_cast<GraphicObject*>(pBrush->GetGraphicObject());
+ if ( bConsiderBackgroundTransparency )
+ {
+ GraphicAttr aGrfAttr = pGrf->GetAttr();
+ if ( (aGrfAttr.GetTransparency() != 0) &&
+ (pBrush->GetColor() == COL_TRANSPARENT)
+ )
+ {
+ bTransparentGrfWithNoFillBackgrd = true;
+ nGrfTransparency = aGrfAttr.GetTransparency();
+ }
+ }
+ if ( pGrf->IsTransparent() )
+ {
+ bGrfIsTransparent = true;
+ }
+ }
+
+ // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
+ // instead of checking, if transparency is not set.
+ const Color aColor( pBrush &&
+ ( !(pBrush->GetColor() == COL_TRANSPARENT) ||
+ gProp.bSFlyMetafile )
+ ? pBrush->GetColor()
+ : aGlobalRetoucheColor );
+
+ // determine, if background region have to be
+ // drawn transparent.
+ // background region has to be drawn transparent, if
+ // background transparency have to be considered
+ // AND
+ // ( background color is transparent OR
+ // background graphic is transparent and background color is "no fill"
+ // )
+
+ enum DrawStyle {
+ Default,
+ Transparent,
+ } eDrawStyle = Default;
+
+ if (bConsiderBackgroundTransparency &&
+ ( ( aColor.GetTransparency() != 0) ||
+ bTransparentGrfWithNoFillBackgrd ) )
+ {
+ eDrawStyle = Transparent;
+ }
+
+ // #i75614# reset draw mode in high contrast mode in order to get fill color set
+ const DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
+ if ( gProp.pSGlobalShell->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pOutDev->SetDrawMode( DrawModeFlags::Default );
+ }
+
+ // OD 06.08.2002 #99657# - if background region has to be drawn
+ // transparent, set only the RGB values of the background color as
+ // the fill color for the output device.
+ switch (eDrawStyle)
+ {
+ case Transparent:
+ {
+ if( pOutDev->GetFillColor() != aColor.GetRGBColor() )
+ pOutDev->SetFillColor( aColor.GetRGBColor() );
+ break;
+ }
+ default:
+ {
+ if( pOutDev->GetFillColor() != aColor )
+ pOutDev->SetFillColor( aColor );
+ break;
+ }
+ }
+
+ // #i75614#
+ // restore draw mode
+ pOutDev->SetDrawMode( nOldDrawMode );
+
+ // OD 02.09.2002 #99657#
+ switch (eDrawStyle)
+ {
+ case Transparent:
+ {
+ // background region have to be drawn transparent.
+ // Thus, create a poly-polygon from the region and draw it with
+ // the corresponding transparency percent.
+ tools::PolyPolygon aDrawPoly( rOut.SVRect() );
+ if ( aGrf.HasArea() )
+ {
+ if ( !bGrfIsTransparent )
+ {
+ // subtract area of background graphic from draw area
+ // OD 08.10.2002 #103898# - consider only that part of the
+ // graphic area that is overlapping with draw area.
+ SwRect aTmpGrf = aGrf;
+ aTmpGrf.Intersection( rOut );
+ if ( aTmpGrf.HasArea() )
+ {
+ tools::Polygon aGrfPoly( aTmpGrf.SVRect() );
+ aDrawPoly.Insert( aGrfPoly );
+ }
+ }
+ else
+ bGrfBackgrdAlreadyDrawn = true;
+ }
+ // calculate transparency percent:
+ // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
+ // If there is a background graphic with a background color "no fill"/"auto fill",
+ // the transparency value is taken from the background graphic,
+ // otherwise take the transparency value from the color.
+ sal_Int8 nTransparencyPercent = static_cast<sal_Int8>(
+ (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency()
+ )*100 + 0x7F)/0xFF);
+ // draw poly-polygon transparent
+ pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent );
+
+ break;
+ }
+ case Default:
+ default:
+ {
+ SwRegionRects aRegion( rOut, 4 );
+ if ( !bGrfIsTransparent )
+ aRegion -= aGrf;
+ else
+ bGrfBackgrdAlreadyDrawn = true;
+ // loop rectangles of background region, which has to be drawn
+ for( size_t i = 0; i < aRegion.size(); ++i )
+ {
+ pOutDev->DrawRect( aRegion[i].SVRect() );
+ }
+ }
+ }
+ pOutDev ->Pop();
+ }
+
+ if( bDraw && aGrf.IsOver( rOut ) )
+ // OD 02.09.2002 #99657#
+ // add parameter <bGrfBackgrdAlreadyDrawn>
+ lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, true, bGrfNum, gProp,
+ bGrfBackgrdAlreadyDrawn );
+
+ if( bReplaceGrfNum )
+ {
+ const BitmapEx& rBmp = rSh.GetReplacementBitmap(false);
+ vcl::Font aTmp( pOutDev->GetFont() );
+ Graphic::DrawEx( pOutDev, aEmptyOUStr, aTmp, rBmp, rOrg.Pos(), rOrg.SSize() );
+ }
+}
+
+/**
+ * Local helper for SwRootFrame::Paint(..) - Adjust given rectangle to pixel size
+ *
+ * By OD at 27.09.2002 for #103636#
+ * In order to avoid paint errors caused by multiple alignments (e.g. ::SwAlignRect(..))
+ * and other changes to the to be painted rectangle, this method is called for the
+ * rectangle to be painted in order to adjust it to the pixel it is overlapping
+*/
+static void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const vcl::RenderContext &aOut )
+{
+ // local constant object of class <Size> to determine number of Twips
+ // representing a pixel.
+ const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) );
+
+ // local object of class <Rectangle> in Twip coordinates
+ // calculated from given rectangle aligned to pixel centers.
+ const tools::Rectangle aPxCenterRect = aOut.PixelToLogic(
+ aOut.LogicToPixel( io_aSwRect.SVRect() ) );
+
+ // local constant object of class <Rectangle> representing given rectangle
+ // in pixel.
+ const tools::Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
+
+ // calculate adjusted rectangle from pixel centered rectangle.
+ // Due to rounding differences <aPxCenterRect> doesn't exactly represents
+ // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
+ // Afterwards, adjust calculated Twip-positions of the all borders.
+ tools::Rectangle aSizedRect = aPxCenterRect;
+ aSizedRect.Left() -= (aTwipToPxSize.Width()/2 + 1);
+ aSizedRect.Right() += (aTwipToPxSize.Width()/2 + 1);
+ aSizedRect.Top() -= (aTwipToPxSize.Height()/2 + 1);
+ aSizedRect.Bottom() += (aTwipToPxSize.Height()/2 + 1);
+
+ // adjust left()
+ while ( (aOut.LogicToPixel(aSizedRect)).Left() < aOrgPxRect.Left() )
+ {
+ ++aSizedRect.Left();
+ }
+ // adjust right()
+ while ( (aOut.LogicToPixel(aSizedRect)).Right() > aOrgPxRect.Right() )
+ {
+ --aSizedRect.Right();
+ }
+ // adjust top()
+ while ( (aOut.LogicToPixel(aSizedRect)).Top() < aOrgPxRect.Top() )
+ {
+ ++aSizedRect.Top();
+ }
+ // adjust bottom()
+ while ( (aOut.LogicToPixel(aSizedRect)).Bottom() > aOrgPxRect.Bottom() )
+ {
+ --aSizedRect.Bottom();
+ }
+
+ io_aSwRect = SwRect( aSizedRect );
+
+#if OSL_DEBUG_LEVEL > 0
+ tools::Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
+ tools::Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+ OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect,
+ "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
+ // check Left()
+ --aSizedRect.Left();
+ aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+ OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1),
+ "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
+ ++aSizedRect.Left();
+ // check Right()
+ ++aSizedRect.Right();
+ aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+ OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1),
+ "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
+ --aSizedRect.Right();
+ // check Top()
+ --aSizedRect.Top();
+ aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+ OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1),
+ "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
+ ++aSizedRect.Top();
+ // check Bottom()
+ ++aSizedRect.Bottom();
+ aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+ OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1),
+ "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
+ --aSizedRect.Bottom();
+#endif
+}
+
+// FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
+
+struct SwLineEntry
+{
+ SwTwips mnKey;
+ SwTwips mnStartPos;
+ SwTwips mnEndPos;
+
+ svx::frame::Style maAttribute;
+
+ enum OverlapType { NO_OVERLAP, OVERLAP1, OVERLAP2, OVERLAP3 };
+
+public:
+ SwLineEntry( SwTwips nKey,
+ SwTwips nStartPos,
+ SwTwips nEndPos,
+ const svx::frame::Style& rAttribute );
+
+ OverlapType Overlaps( const SwLineEntry& rComp ) const;
+};
+
+SwLineEntry::SwLineEntry( SwTwips nKey,
+ SwTwips nStartPos,
+ SwTwips nEndPos,
+ const svx::frame::Style& rAttribute )
+ : mnKey( nKey ),
+ mnStartPos( nStartPos ),
+ mnEndPos( nEndPos ),
+ maAttribute( rAttribute )
+{
+}
+
+/*
+
+ 1. ---------- rOld
+ ---------- rNew
+
+ 2. ---------- rOld
+ ------------- rNew
+
+ 3. ------- rOld
+ ------------- rNew
+
+ 4. ------------- rOld
+ ---------- rNew
+
+ 5. ---------- rOld
+ ---- rNew
+
+ 6. ---------- rOld
+ ---------- rNew
+
+ 7. ------------- rOld
+ ---------- rNew
+
+ 8. ---------- rOld
+ ------------- rNew
+
+ 9. ---------- rOld
+ ---------- rNew
+*/
+
+SwLineEntry::OverlapType SwLineEntry::Overlaps( const SwLineEntry& rNew ) const
+{
+ SwLineEntry::OverlapType eRet = OVERLAP3;
+
+ if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos )
+ eRet = NO_OVERLAP;
+
+ // 1, 2, 3
+ else if ( mnEndPos < rNew.mnEndPos )
+ eRet = OVERLAP1;
+
+ // 4, 5, 6, 7
+ else if ( mnStartPos <= rNew.mnStartPos && mnEndPos >= rNew.mnEndPos )
+ eRet = OVERLAP2;
+
+ // 8, 9
+ return eRet;
+}
+
+struct lt_SwLineEntry
+{
+ bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const
+ {
+ return e1.mnStartPos < e2.mnStartPos;
+ }
+};
+
+typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet;
+typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap;
+
+class SwTabFramePainter
+{
+ SwLineEntryMap maVertLines;
+ SwLineEntryMap maHoriLines;
+ const SwTabFrame& mrTabFrame;
+
+ void Insert( SwLineEntry&, bool bHori );
+ void Insert( const SwFrame& rFrame, const SvxBoxItem& rBoxItem );
+ void HandleFrame( const SwLayoutFrame& rFrame );
+ void FindStylesForLine( const Point&,
+ const Point&,
+ svx::frame::Style*,
+ bool bHori ) const;
+
+public:
+ explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
+
+ void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const;
+};
+
+SwTabFramePainter::SwTabFramePainter( const SwTabFrame& rTabFrame )
+ : mrTabFrame( rTabFrame )
+{
+ HandleFrame( rTabFrame );
+}
+
+void SwTabFramePainter::HandleFrame( const SwLayoutFrame& rLayoutFrame )
+{
+ // Add border lines of cell frames. Skip covered cells. Skip cells
+ // in special row span row, which do not have a negative row span:
+ if ( rLayoutFrame.IsCellFrame() && !rLayoutFrame.IsCoveredCell() )
+ {
+ const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rLayoutFrame);
+ const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pThisCell->GetUpper());
+ const long nRowSpan = pThisCell->GetTabBox()->getRowSpan();
+ if ( !pRowFrame->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 )
+ {
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), &rLayoutFrame );
+ const SwBorderAttrs& rAttrs = *aAccess.Get();
+ const SvxBoxItem& rBox = rAttrs.GetBox();
+ Insert( rLayoutFrame, rBox );
+ }
+ }
+
+ // Recurse into lower layout frames, but do not recurse into lower tabframes.
+ const SwFrame* pLower = rLayoutFrame.Lower();
+ while ( pLower )
+ {
+ const SwLayoutFrame* pLowerLayFrame = dynamic_cast<const SwLayoutFrame*>(pLower);
+ if ( pLowerLayFrame && !pLowerLayFrame->IsTabFrame() )
+ HandleFrame( *pLowerLayFrame );
+
+ pLower = pLower->GetNext();
+ }
+}
+
+void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) const
+{
+ // #i16816# tagged pdf support
+ SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev );
+
+ SwLineEntryMap::const_iterator aIter = maHoriLines.begin();
+ bool bHori = true;
+
+ // color for subsidiary lines:
+ const Color& rCol( SwViewOption::GetTableBoundariesColor() );
+
+ // high contrast mode:
+ // overrides the color of non-subsidiary lines.
+ const Color* pHCColor = nullptr;
+ DrawModeFlags nOldDrawMode = rDev.GetDrawMode();
+ if( gProp.pSGlobalShell->GetWin() &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pHCColor = &SwViewOption::GetFontColor();
+ rDev.SetDrawMode( DrawModeFlags::Default );
+ }
+
+ const SwFrame* pUpper = mrTabFrame.GetUpper();
+ SwRect aUpper( pUpper->Prt() );
+ aUpper.Pos() += pUpper->Frame().Pos();
+ SwRect aUpperAligned( aUpper );
+ ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
+ drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence;
+ drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence;
+
+ while ( true )
+ {
+ if ( bHori && aIter == maHoriLines.end() )
+ {
+ aIter = maVertLines.begin();
+ bHori = false;
+ }
+
+ if ( !bHori && aIter == maVertLines.end() )
+ break;
+
+ const SwLineEntrySet& rEntrySet = (*aIter).second;
+ for (SwLineEntrySet::const_iterator aSetIter = rEntrySet.begin();
+ aSetIter != rEntrySet.end(); ++aSetIter)
+ {
+ const SwLineEntry& rEntry = *aSetIter;
+ const svx::frame::Style& rEntryStyle( (*aSetIter).maAttribute );
+
+ Point aStart, aEnd;
+ if ( bHori )
+ {
+ aStart.X() = rEntry.mnStartPos;
+ aStart.Y() = rEntry.mnKey;
+ aEnd.X() = rEntry.mnEndPos;
+ aEnd.Y() = rEntry.mnKey;
+ }
+ else
+ {
+ aStart.X() = rEntry.mnKey;
+ aStart.Y() = rEntry.mnStartPos;
+ aEnd.X() = rEntry.mnKey;
+ aEnd.Y() = rEntry.mnEndPos;
+ }
+
+ svx::frame::Style aStyles[ 7 ];
+ aStyles[ 0 ] = rEntryStyle;
+ FindStylesForLine( aStart, aEnd, aStyles, bHori );
+ SwRect aRepaintRect( aStart, aEnd );
+
+ // the repaint rectangle has to be moved a bit for the centered lines:
+ SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth();
+ if ( bHori )
+ {
+ aRepaintRect.Height( 2 * nRepaintRectSize );
+ aRepaintRect.Pos().Y() -= nRepaintRectSize;
+ }
+ else
+ {
+ aRepaintRect.Width( 2 * nRepaintRectSize );
+ aRepaintRect.Pos().X() -= nRepaintRectSize;
+ }
+
+ if (!rRect.IsOver(aRepaintRect))
+ {
+ continue;
+ }
+
+ // subsidiary lines
+ const Color* pTmpColor = nullptr;
+ if (0 == aStyles[ 0 ].GetWidth())
+ {
+ if (isTableBoundariesEnabled() && gProp.pSGlobalShell->GetWin())
+ aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 );
+ else
+ aStyles[0].SetType(SvxBorderLineStyle::NONE);
+ }
+ else
+ pTmpColor = pHCColor;
+
+ // The (twip) positions will be adjusted to meet these requirements:
+ // 1. The y coordinates are located in the middle of the pixel grid
+ // 2. The x coordinated are located at the beginning of the pixel grid
+ // This is done, because the horizontal lines are painted "at
+ // beginning", whereas the vertical lines are painted "centered".
+ // By making the line sizes a multiple of one pixel size, we can
+ // assure that all lines having the same twip size have the same
+ // pixel size, independent of their position on the screen.
+ Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel(aStart) );
+ Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel(aEnd) );
+
+ if (gProp.pSGlobalShell->GetWin())
+ {
+ // The table borders do not use SwAlignRect, but all the other frames do.
+ // Therefore we tweak the outer borders a bit to achieve that the outer
+ // borders match the subsidiary lines of the upper:
+ if (aStart.X() == aUpper.Left())
+ aPaintStart.X() = aUpperAligned.Left();
+ else if (aStart.X() == aUpper.Rigth_())
+ aPaintStart.X() = aUpperAligned.Rigth_();
+ if (aStart.Y() == aUpper.Top())
+ aPaintStart.Y() = aUpperAligned.Top();
+ else if (aStart.Y() == aUpper.Bottom_())
+ aPaintStart.Y() = aUpperAligned.Bottom_();
+
+ if (aEnd.X() == aUpper.Left())
+ aPaintEnd.X() = aUpperAligned.Left();
+ else if (aEnd.X() == aUpper.Rigth_())
+ aPaintEnd.X() = aUpperAligned.Rigth_();
+ if (aEnd.Y() == aUpper.Top())
+ aPaintEnd.Y() = aUpperAligned.Top();
+ else if (aEnd.Y() == aUpper.Bottom_())
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list